O blog da AWS
Criando uma solução SaaS multi-tenant usando o Amazon EKS
À medida que mais organizações migram para um modelo de entrega de software como serviço (SaaS), muitas estão escolhendo o Amazon Elastic Kubernetes Service (Amazon EKS) como alvo para suas soluções. O modelo de programação, a eficiência de custos, a segurança, a implantação e os atributos operacionais do EKS representam um modelo atraente para fornecedores de SaaS.
O modelo EKS também apresenta aos arquitetos e desenvolvedores de SaaS uma coleção de novas considerações sobre multi-tenant. Agora você terá que pensar em como os princípios fundamentais do SaaS (isolamento, integração, identidade) são implementados em um ambiente EKS.
Para fornecer uma visão mais clara de como esses princípios são construídos, criamos um exemplo de solução EKS SaaS que fornece aos desenvolvedores e arquitetos um exemplo prático. Isso ilustra como as melhores práticas de arquitetura e design multi-tenant ganham vida em um ambiente EKS.
Neste post, abordaremos os principais elementos da arquitetura de referencia. Veremos como isolar tenants em um cluster EKS, automatizar a integração de tenants, gerenciar identidades de tenants e oferecer suporte ao roteamento de cargas de trabalho de tenants.
Essa solução inclui uma experiência de trabalho completa com um exemplo de aplicação SaaS e um console de administração que gerencia seu ambiente SaaS.
Explore o exemplo da solução EKS SaaS aqui >>
Escolhendo um modelo de isolamento
Há inúmeras maneiras de projetar e criar uma solução SaaS multi-tenant no Amazon EKS, cada uma com seu próprio conjunto de vantagens e desvantagens. Com o EKS, você tem várias opções que podem afetar o esforço de implementação, a complexidade operacional e a eficiência de custos.
Por exemplo, alguns podem optar por empregar um modelo de cluster por tenant, para isolar seus tenants. Isso forneceria um modelo de isolamento simples, mas também pode ter um preço alto.
Outros podem usar um modelo de computação compartilhado em que todos os tenants são agrupados no cluster e o namespace e o isolamento são tratados no nível da aplicação. Como era de se esperar, isso proporciona uma grande eficiência operacional e de custos; porem representa um modelo de isolamento menos atraente.
No meio desses dois extremos está o isolamento de namespace por tenant, em que cada tenant é implantado no mesmo cluster, mas separado um do outro usando namespaces e uma série de construções nativas e complementares do Kubernetes. Isso é comumente chamado de modelo de “silo”, em que os recursos do tenant não são compartilhados pelos tenants.
Esse modelo de namespace por tenant representa uma boa combinação de isolamento e economia. Por esse motivo, optamos por implementar esse modelo na solução EKS SaaS. Essa escolha acaba tendo um impacto significativo em toda a nossa solução, incluindo a integração de tenants, o isolamento dos tenants e o roteamento do tráfego dos tenants.
Arquitetura de alto nível
Figura 1 — Arquitetura conceitual.
Primeiro, temos três tipos diferentes de aplicativos que fazem parte da experiência EKS SaaS. Eles se correlacionam com os tipos comuns de aplicações que você teria em muitos ambientes SaaS. A primeira aplicação, a página inicial, representa a página voltada para o público em que o cliente pode encontrar e se inscrever em nossa solução. Novos clientes podem acessar este site, acionar o processo de registro e criar um novo tenant no sistema.
A próxima aplicação é a aplicação comercial de exemplo. Aqui, criamos um aplicativo de comércio eletrônico simples que fornece algumas funcionalidades básicas de pedidos e produtos enquanto nos comunicamos com microsserviços específicos para tenants executados no cluster EKS. É aqui que você instala sua aplicação SaaS multi-tenant.
A última aplicação é o console de administração do provedor SaaS, que utiliza o Amazon Cognito para controlar o acesso. Como provedor de SaaS, você usaria essa aplicação para definir e gerenciar suas políticas e configurações de tenant. Cada um desses aplicativos interage com serviços que estão sendo executados em um cluster EKS.
Há duas categorias diferentes de serviços que são executados nesse cluster. Primeiro, a camada de serviços compartilhados representa todos os serviços comuns necessários para dar suporte a todos os recursos operacionais, de gerenciamento, de identidade, de integração e de configuração de um ambiente SaaS.
A outra categoria de serviços faz parte dos ambientes gerenciados de tenants. Os serviços executados aqui representam os diferentes ambientes de tenants implantados que executam os microsserviços do nosso aplicativo. Temos implantações separadas para cada tenant do nosso sistema e exploraremos a justificativa para essa decisão de arquitetura abaixo.
O que é provisionado
Agora que entendemos a arquitetura de alto nível, vamos nos aprofundar para ver o que é provisionado ao instalar a solução EKS SaaS.
Infraestrutura básica
Antes de começarmos a pensar em tenants e aplicativos, precisamos implantar a versão básica do nosso ambiente.
Essa infraestrutura é composta pelo cluster EKS real que hospeda nosso serviço. Também inclui a infraestrutura de suporte necessária, como funções do AWS Identity and Access Management (IAM), distribuições do Amazon CloudFront e buckets de apoio do Amazon Simple Storage Service (Amazon S3).
Figura 2 — Infraestrutura básica.
O cluster EKS, junto com sua Virtual Private Cloud (VPC), sub-redes e gateways de Conversão de Endereços de Rede (NAT) correspondentes, é implantado por meio da ferramenta eksctl. Essa interface de linha de comando (CLI) simplifica a criação dos vários scripts do AWS CloudFormation necessários para implantar um cluster EKS pronto para uso. Esse cluster executa os ambientes compartilhados e tenants da sua solução EKS SaaS.
Embora tenhamos aproveitado padrões comuns para configurar e implantar o cluster, você deve pensar em como proteger ainda mais a rede e o cluster com base nas necessidades específicas do seu ambiente. Saiba mais sobre as melhores práticas de segurança para criar um cluster EKS.
Depois que o cluster é instalado, implantamos vários objetos da API Kubernetes no cluster, incluindo o ingress controller NGINX de código aberto e o DNS externo.
O ingress controller desempenha um papel fundamental, ajudando a rotear solicitações de vários tenants dos aplicativos do cliente. Ele funciona em conjunto com o DNS externo, que cria automaticamente entradas de DNS do Amazon Route 53 para qualquer subdomínio referenciado em nossos recursos de entrada.
No nosso caso, isso é apenas API.domain.com. O DOMÍNIO referenciado aqui representa um domínio personalizado que você configurará na implantação.
Essa arquitetura básica inclui o Amazon S3 e é onde cada um dos aplicativos web apresentados nessa solução é hospedado como sites estáticos. Usamos distribuições do CloudFront com nomes de domínio personalizados para distribuição de conteúdo. Cada site é criado e copiado para seu respectivo bucket S3 após a implantação.
Além dos buckets S3 e do suporte ao serviço do CloudFront, a stack fornece um certificado wildcard correspondente ao nome de domínio personalizado fornecido quando implantado. Esse certificado é usado para fornecer conexões HTTPS a todas as entidades públicas da Web nessa solução, incluindo os três aplicativos da Web descritos acima, bem como os serviços da Web públicos compartilhados e específicos do tenant.
A configuração desse ambiente básico também inclui a implantação da parte de serviços compartilhados do nosso ambiente SaaS (registro, gerenciamento de tenants e gerenciamento de usuários). Eles apoiam nossa capacidade de integrar e gerenciar tenants e usuários administradores de tenants.
Os serviços compartilhados dependem de vários recursos da AWS. O gerenciamento de tenants armazena e gerencia as informações do tenant em uma tabela do Amazon DynamoDB. O gerenciamento de usuários administra os usuários que estão armazenados no Amazon Cognito.
Todos os microsserviços executados no EKS são implementados com Java Spring Boot. Durante a implantação da stack, um repositório Amazon Elastic Container Registry (Amazon ECR) é criado para cada um dos microsserviços do sistema. No momento da implantação, cada serviço é criado e enviado para seu respectivo repositório.
Como etapa final na configuração básica, os registros DNS do Amazon Route 53 são adicionados para duas das três aplicações web nesta solução. O console administrativo está configurado como Admin.domain.com
e a página inicial está configurada como www.domain.com
. A página de exemplo do aplicativo de comércio eletrônico não recebe um alias do Route 53 até que um tenant seja implantado.
Infraestrutura do tenant
Depois de criar sua infraestrutura básica, você pode começar a pensar mais sobre a infraestrutura necessária para dar suporte aos tenants à medida que eles são integrados ao seu aplicativo SaaS.
A arquitetura que selecionamos aqui usa um modelo de namespace por tenant para implementar nosso isolamento, que exige que recursos separados sejam implantados para cada tenant. Exploraremos esse modelo de isolamento com mais detalhes abaixo.
Figura 3 — Microsserviços de tenants implantados.
A arquitetura acima ilustra como os microsserviços do nosso aplicativo são implantados em nossa infraestrutura básica. Nós os colocamos no mesmo cluster usado para implantar os serviços compartilhados do ambiente. A principal diferença é que nenhum desses microsserviços e namespaces é criado até que um tenant realmente se integre.
Obviamente, as construções necessárias para dar vida a esses microsserviços têm mais partes móveis. O diagrama a seguir fornece uma visão mais granular dos elementos de nossos ambientes de tenants.
Figura 4 — Infraestrutura por tenant.
Analisando o fluxo básico, temos os recursos usados pelo aplicativo SaaS para acessar cada um dos nossos namespaces de tenants. Grupos de usuários e domínios separados são usados para autenticar e encaminhar tenants para o nosso ambiente.
À medida que você avança, a solução usa um ingress controller NGINX para rotear o tráfego para nossos namespaces. Outra solução que pode ser usada aqui é o AWS Load Balancer Controller.
Nossos serviços de pedidos e produtos representam o back-end de nosso exemplo de aplicativo de comércio eletrônico. Embora esses serviços sejam implantados a partir do repositório ECR compartilhado por todos os tenants, cada tenant recebe sua própria cópia desses microsserviços, que são configurados com informações específicas do tenant no momento da implantação.
Todos os nossos artefatos específicos para tenants, incluindo os microsserviços e os recursos de entrada do NGINX, são implantados em seu próprio namespace. Atribuímos uma política de IAM para a conta de serviço do tenant, bem como políticas de segurança de pod e rede para segurança adicional.
Os serviços AWS Code*, mostrados na parte inferior da Figura 4, são usados como a máquina que orquestra a configuração e a implantação desses objetos em nosso cluster EKS. Os projetos Code* são definidos como recursos do CloudFormation com parâmetros que servem como espaços reservados para os dados específicos do tenant.
À direita, você verá as tabelas do DynamoDB. Queremos mostrar vários exemplos de particionamento de dados na solução EKS SaaS. Nosso microsserviço de pedidos, por exemplo, usa um modelo de particionamento de armazenamento em silo em que cada tenant tem uma tabela separada do DynamoDB. Uma nova tabela de pedidos é criada para cada novo tenant adicionado ao sistema.
O microsserviço do produto usa um modelo de particionamento agrupado (pool) em que os dados do tenant são reunidos na mesma tabela e acessados por meio de uma chave de partição preenchida com um identificador do tenant.
As tabelas de pedidos são protegidas com funções do IAM que impedem qualquer acesso entre tenants. O acesso às tabelas de produtos também é controlado pelas funções do IAM. Nesse caso, usamos condições do IAM com base nas chaves de partição específicas do tenant na tabela do DynamoDB.
Integração de tenants
Novos tenants são introduzidos no sistema por meio de um processo de integração simples que orquestra todos os serviços necessários para colocar o tenant em funcionamento. Ter uma experiência de integração automatizada e de baixo atrito é fundamental para permitir que os provedores de SaaS tenham um mecanismo repetível e escalável para introduzir novos tenants.
Para essa solução, temos várias partes móveis que estão incluídas no processo de integração. Primeiro, precisamos criar um novo tenant e o usuário administrativo desse tenant. Em seguida, precisamos configurar o namespace e as políticas do Kubernetes para o tenant e implantar os microsserviços do aplicativo nesse namespace.
A Figura 5 descreve o fluxo de integração. O processo começa com o preenchimento de um formulário de inscrição, que simula a página típica que você ofereceria como uma experiência pública para novos tenants. A integração pode ser acionada pelo aplicativo de administração.
Incluímos esse fluxo para ilustrar como seria ter essa mesma experiência de integração gerenciada por um processo interno. A principal conclusão é que esses dois processos dependem do mesmo mecanismo subjacente para integrar um tenant ao sistema.
Figura 5 — Integração do tenant.
As etapas abaixo descrevem a sequência de eventos envolvidos durante o processo de integração do tenant:
- O serviço de registro de tenants recebe uma solicitação da página inicial ou do aplicativo administrativo que inclui os dados de integração do tenant.
- O serviço de registro chama o serviço de gerenciamento de tenants para registrar os detalhes do tenant no Amazon DynamoDB.
- O serviço de registro cria um Cognito User Pool para o tenant.
- O serviço de registro chama o serviço de gerenciamento de usuários para criar o usuário de administração de tenants no User Pool recém-criado.
- O serviço de registro dá início ao provisionamento dos serviços de aplicativos do tenant usando o AWS CodePipeline e o AWS CodeBuild para orquestrar a implantação dos recursos do tenant. Isso inclui a criação de um namespace para o tenant e a implantação de microsserviços de Produto e Pedido no namespace do tenant.
- As políticas de segurança de isolamento de tenants são aplicadas no nível de rede e dos dados.
Além do isolamento de namespace
Conforme descrito anteriormente, usamos um modelo de namespace por tenant para criar uma camada de isolamento para tenants e seus recursos em um cluster do Amazon EKS.
No entanto, um namespace Kubernetes, por padrão, não fornece um limite rígido de isolamento para os recursos que estão dentro desse namespace. Devemos introduzir construções adicionais para evitar qualquer acesso entre tenants.
Figura 6 — Isolamento do tenant.
Neste exemplo, usamos políticas de segurança e de rede do pod para impedir o acesso entre tenants no nível do namespace do pod. Usamos funções do IAM para a conta de serviço para impor o isolamento.
Essa abordagem introduz o isolamento de credenciais, garantindo que um container só possa recuperar credenciais para a função do IAM associada à conta de serviço à qual ele pertence. Isso significa que um container nunca poderá acessar as credenciais de um container que pertence a outro pod em execução em outro namespace.
Conforme você avança pelo diagrama na Figura 6, você pode ver como aplicamos o isolamento à medida que cada namespace tenta acessar outro recurso do tenant (nesse caso, tabelas do DynamoDB). Há duas variações diferentes de isolamento para as tabelas de produtos e pedidos.
Para nosso microsserviço de pedidos, cada tenant tem uma tabela de pedidos separada (usando um modelo de armazenamento em silo). Temos políticas do IAM que restringem o acesso no nível da tabela.
O microsserviço do produto tem uma única tabela para todos os tenants. Nesse cenário, nossas políticas do IAM restringem o acesso aos itens reais na tabela.
Embora essas construções ajudem a aplicar nosso modelo de isolamento, você também precisa pensar em como isolar no nível da rede. Por padrão, todo o tráfego de pod para pod no Kubernetes é permitido e, sem controles, todos os pods podem se comunicar livremente com todos os outros pods dentro e entre namespaces em um cluster EKS.
Para evitar essa situação de acesso entre namespaces, implementamos políticas de rede usando o Tigera Calico, o que nos permite alcançar o isolamento da rede aplicando políticas de rede refinadas no nível do namespace.
Conclusão
Esta postagem examina algumas das principais considerações que podem influenciar a forma como você aborda o projeto e a criação de uma solução SaaS com o Amazon EKS. Deve ficar claro que o poder e a flexibilidade do EKS também exigem que você encontre maneiras criativas de realizar alguns dos principais princípios arquitetônicos do SaaS.
À medida que você se aprofunda na aplicação de exemplo EKS SaaS que apresentamos aqui, você terá uma ideia melhor da experiência geral de ponta a ponta de criar uma solução EKS SaaS completa e funcional na AWS. Isso deve proporcionar uma boa vantagem inicial e, ao mesmo tempo, permitir que você a defina de acordo com as políticas que se alinham às necessidades do seu ambiente SaaS.
Para uma visão mais aprofundada dessa solução, convidamos você a dar uma olhada no repositório de soluções. Lá, você encontrará instruções de implantação passo a passo, bem como um guia mais centrado no desenvolvimento para ajudar a entender todas as partes móveis do ambiente.
Sobre o AWS SaaS Factory
O AWS SaaS Factory ajuda organizações em qualquer estágio da jornada de SaaS. Seja para criar novos produtos, migrar aplicativos existentes ou otimizar soluções de SaaS na AWS. Visite o AWS SaaS Factory Insights Hub para descobrir mais conteúdo técnico e comercial e melhores práticas.
Os criadores de SaaS são incentivados a entrar em contato com seu representante de conta para obter informações sobre modelos de engajamento e trabalhar com a equipe do AWS SaaS Factory.
Inscreva-se para se manter informado sobre as últimas notícias, recursos e eventos de SaaS na AWS.
Este artigo foi traduzido do Blog da AWS em Inglês.
Sobre os autores
Toby Buckley é arquiteto sênior de soluções de parceiros na AWS SaaS Factory
Ranjith Raman é arquiteto sênior de soluções de parceiros na AWS SaaS Factory