Este blog é o primeiro de uma série de blogs que abordam vários aspectos do que foi necessário para construir e operar nosso serviço SaaS :
Conforme descrito em nosso blog anterior , nossos clientes estão criando conjuntos complexos e diversos de soluções de negócios — como manufatura inteligente, análise forense de vídeo para segurança pública, negociação algorítmica, redes de telecomunicações 5G — e, portanto, precisamos oferecer uma experiência sempre ativa, conectada e confiável para esses aplicativos e seus usuários finais.
Como esses aplicativos podiam ser executados em vários clusters entre provedores de nuvem ou locais de ponta dos clientes, nossa equipe de plataforma teve que criar um plano de controle distribuído e um serviço PaaS para implantar, proteger e operar vários clusters Kubernetes multilocatários. Este plano de controle distribuído proporcionou muitos benefícios operacionais, de escala e de desempenho que abordaremos em nossa apresentação ( link do vídeo ) — por exemplo, como gerenciar milhares de clusters K8s de ponta com GitOps — e também como uma postagem de blog separada nas próximas semanas.
Escolhemos o Kubernetes (K8s) para ser o núcleo da nossa plataforma de gerenciamento de aplicativos distribuídos, pois ele fornece um rico conjunto de funcionalidades sem ser excessivamente prescritivo, o que nos dá flexibilidade para inovar em coisas que acreditamos serem importantes para nossos clientes. Usamos isso como base para começar a construir nosso serviço e, com a crescente popularidade dos K8s, também é mais fácil encontrar desenvolvedores e operadores familiarizados com eles.
Dito isso, implantar e gerenciar um grande número de clusters Kubernetes de nível de produção em um ambiente híbrido (várias nuvens, POPs de rede e locais de borda) não é muito fácil, pois não há soluções prontas para uso para Kubernetes que possam:
Após várias provas de conceito com vários provedores de nuvem e plataformas de código aberto como GKE, AKS, EKS e RKE, bem como OpenShift e Cloud Foundry, percebemos que nenhum deles poderia atender a todos os cinco requisitos acima. Como resultado, decidimos construir nosso próprio PaaS — começando com o Kubernetes “vanilla” e fizemos várias adições — para identidade, rede, segurança, multilocação, registro, métricas, etc. Embora usemos o Kubernetes para atender às nossas necessidades internas, tivemos que tomar algumas decisões difíceis, como não expor esses clusters do Kubernetes diretamente aos nossos usuários internos e/ou clientes para executar suas cargas de trabalho (mais sobre isso depois, pois a multilocação era um objetivo fundamental para nós).
Além de vários novos recursos que precisávamos adicionar, também havia a necessidade de executar nossas cargas de trabalho/serviços junto com as cargas de trabalho dos clientes em muitos locais na borda, em nossa rede e em nuvens públicas/privadas. Isso significava que precisávamos criar recursos adicionais para gerenciar vários clusters em vários ambientes... todos conectados usando nossa rede global e nossos gateways de aplicativos distribuídos para fornecer conectividade de nível de aplicativo e confiança zero entre esses clusters.
Criar e operar aplicativos executados em um único cluster do Kubernetes não é uma tarefa trivial, mesmo que consuma um cluster gerenciado pelo provedor de nuvem. É por isso que é comum que equipes de DevOps e SRE minimizem sua sobrecarga e não lidem com as complexidades de muitos clusters. É bastante comum ver equipes criarem um grande cluster do Kubernetes e colocarem todos os tipos de recursos dentro do mesmo cluster. Embora isso pareça ótimo porque eles podem simplificar as operações e executar o cluster para obter a máxima eficiência computacional e custo, essa não é a melhor ideia por vários motivos. Primeiro, as necessidades de cargas de trabalho de produção são muito diferentes das de desenvolvimento e teste e de preparação — cargas de trabalho de desenvolvimento instáveis podem causar problemas para cargas de trabalho de produção mais estáveis.
Além das necessidades de cargas de trabalho variadas, as limitações de segurança e isolamento do K8s são outro fator determinante para o multicluster. Uma abordagem típica para resolver a segurança e o isolamento de recursos do K8s é criar clusters independentes para cada locatário usando um modelo multilocatário. Embora isso possa ser viável na nuvem, não é possível executar vários clusters na borda. Os sites de ponta têm limitações de recursos de computação e armazenamento e largura de banda de rede restrita para enviar logs e métricas de cada cluster adicional para a nuvem central.
Para lidar com o problema de vários clusters do Kubernetes, avaliamos o Rancher para gerenciamento centralizado de nossos clusters do Kubernetes (quando começamos, o Anthos e o Azure Arc não existiam) e o KubeFed. As duas abordagens disponíveis naquela época eram (e continuam sendo a mesma situação hoje):
Após o anúncio recente do GCP Anthos e do Azure Arc, reavaliamos nossa decisão original de criar um plano de controle distribuído e concluímos que mesmo essas duas novas ofertas não conseguiriam resolver dois problemas críticos com clusters distribuídos. Esses dois principais recursos que precisávamos para nossa plataforma eram:
Para resolver esses dois problemas, tivemos que criar uma nova técnica — plano de controle distribuído — para resolver a sobrecarga operacional de “vários” clusters e fornecer um equivalente a “vários clusters” para multilocação em ambientes com recursos limitados.
Nossa equipe de plataforma decidiu construir um plano de controle distribuído para o Kubernetes que expõe as APIs do Kubernetes para uso da nossa equipe. No entanto, essas APIs vêm de clusters "virtuais" que existem apenas em nosso plano de controle — um servidor de API K8s virtual (vK8s) para um cluster K8s virtual (conforme mostrado na Figura 1 ). Este plano de controle mapeia a intenção do usuário para vários clusters físicos do Kubernetes em execução em nossa borda, nossos POPs de rede e locais de nuvem pública. Esses clusters físicos são acessíveis somente ao nosso plano de controle distribuído, e não a nenhum locatário/usuário individual.
Este plano de controle fornece a cada locatário um ou mais clusters de aplicativos “virtuais” onde eles podem implantar seus aplicativos e, com base na configuração, o plano de controle irá replicá-los e gerenciá-los em vários clusters físicos do Kubernetes. Além das operações de configuração e implantação, as operações de monitoramento também seguem esse cluster “virtual” sem a necessidade de construir ferramentas para coletar e dissecar dados de vários clusters físicos.
Vamos pegar um aplicativo de UI de exemplo chamado productpage, onde a intenção do usuário é executá-lo distribuído em 3 locais — pa2-par, ny8-nyc e ams9-ams com 2 réplicas em cada um deles. Conforme o usuário cria um objeto vK8s e o anexa a um cluster virtual, ele imediatamente provisiona um servidor de API vK8s que pode ser usado com o kubectl padrão.
Como próxima etapa, o usuário baixa o kubeconfig para este cluster virtual e cria um yaml padrão para descrever uma implantação do K8s para a página do produto.
Após a criação da especificação de implantação, o usuário pode prosseguir para criar uma implantação neste cluster virtual:
Agora, se o usuário verificar sua implantação, ele verá que 6 réplicas foram iniciadas, com 2 em cada local (pa2-par, ny8-nyc e ams9-ams).
A saída a seguir mostra 2 pods em execução em cada local com mapeamento para um nó físico específico
Este exemplo simples demonstra como é trivial obter replicação multicluster de qualquer aplicativo em minutos, sem qualquer sobrecarga de instalação e gerenciamento. Além de mapear a intenção, o plano de controle distribuído também fornece observabilidade para o cluster virtual e não para cada cluster individual.
Como você pode ver na Figura 2 , nosso plano de gerenciamento centralizado está sendo executado em dois provedores de nuvem pública (uma região cada) — um na AWS e um no Azure (para redundância). Este plano de gerenciamento permite que nosso SRE crie locatários com multilocação rígida — por exemplo, uma equipe de desenvolvimento trabalhando em nosso serviço VoltMesh pode ser um locatário e uma equipe de soluções para clientes trabalhando em POCs de clientes pode ser seu próprio locatário com seu próprio conjunto de usuários.
Cada um desses locatários pode criar muitos namespaces e atribuir um grupo de usuários para colaborar nesses namespaces. Esses namespaces não são namespaces do Kubernetes — eles são um limite de isolamento em nossa plataforma com regras RBAC e políticas de IAM para usuários.
Quando um usuário dentro de um namespace deseja criar um cluster de aplicativos, ele cria um objeto vK8s e isso, por sua vez, cria um servidor de API vK8s em nosso plano de gerenciamento. Usando este objeto vK8s, o usuário pode criar implantações, conjuntos com estado, PVCs, etc., e o plano de controle garantirá que essas operações aconteçam em um ou muitos clusters físicos, com base em sites associados ao objeto vK8s.
Como cada locatário e usuário está usando operações K8s padrão sem nenhuma modificação, isso permite que o sistema seja compatível com uma série de ferramentas populares entre os operadores — por exemplo, Spinnaker, Helm, Jenkins, etc.
A grande vantagem de um plano de controle distribuído é que ele resolveu a sobrecarga operacional para nossas equipes de SRE e DevOps. Agora eles podem executar operações (configuração, implantação, monitoramento, política, etc.) em um cluster virtual e o plano de controle mapeará automaticamente em vários clusters físicos. Além da simplificação operacional para múltiplos clusters, o plano de controle também resolveu o problema de segurança e isolamento para multilocação.
Este plano de controle distribuído também melhorou a produtividade dos desenvolvedores que desejam adicionar novos recursos à nossa plataforma — eles não precisam criar uma nova automação toda vez que adicionam novos recursos que impactam a configuração ou as operações em vários clusters. Eles usam o modelo de configuração baseado em intenção e o plano de controle sabe o que precisa ser feito. Além disso, eles podem continuar a interagir com esse objeto de cluster distribuído e múltiplo — kubernetes virtual — usando kubectl e não outra CLI.
Depois de executar isso em nossos ambientes de desenvolvimento, teste, preparação e produção por mais de um ano, percebemos que esse plano de controle distribuído globalmente (executado em nossos POPs de rede) também oferece vantagens significativas de escala, desempenho e confiabilidade — algo que não havíamos imaginado completamente em nossos primeiros dias. Abordaremos essa descoberta em nossa próxima apresentação na KubeCon e em uma postagem de blog separada nas próximas semanas.
Esta série de blogs abordará vários aspectos do que foi necessário para construir e operar nosso serviço SaaS distribuído globalmente com muitos clusters de aplicativos na nuvem pública, nossos PoPs de rede privada e sites de ponta. O próximo é o Global Service Mesh para aplicativos distribuídos …