Gerenciador de Pacotes para Kubernetes - Helm: Passado, Presente, Futuro

Nota perev. : Com este artigo, abrimos uma série de publicações sobre o gerenciador de pacotes do Kubernetes, que usamos ativamente no trabalho diário - Helm. O autor original do material é Matt Butcher, um dos fundadores do projeto Helm, trabalhando em projetos de código aberto na Microsoft e escrevendo 8 livros técnicos (em particular, “Go in Practice”). No entanto, o artigo é complementado por nossos comentários (às vezes extensos) e em breve será expandido com novas notas sobre o Helm, com um foco mais prático. ATUALIZAÇÃO (03/03/2018): saiu a sequência - " Conhecimento prático do gerenciador de pacotes do Kubernetes - Helm ".



Em junho, Helm mudou do status de projeto líder do Kubernetes para a Cloud Native Computing Foundation (CNCF). O CNCF está se tornando a organização pai das melhores ferramentas nativas de nuvem de código aberto. Portanto, é uma grande honra para Helm se tornar parte desse fundamento. E nosso primeiro projeto significativo sob os auspícios do CNCF é verdadeiramente em larga escala: criamos o Helm 3.

Uma Breve História do Leme


Helm apareceu originalmente como um projeto Deis Open Source. Foi modelado com base no Homebrew (o gerenciador de pacotes do macOS - aprox. Transl. ) , E a tarefa que o Helm 1 teve foi uma oportunidade facilitada para os usuários instalarem rapidamente suas primeiras cargas de trabalho no Kubernetes. O anúncio oficial do Helm ocorreu na primeira conferência da KubeCon em São Francisco em 2015.

Nota trans.: a partir da primeira versão, chamada dm (Deployment Manager), a sintaxe YAML foi escolhida para descrever os recursos do Kubernetes, e os modelos Jinja e scripts Python foram suportados ao escrever configurações.

Um modelo de aplicativo da web simples pode ser assim:

Yaml
resources: - name: frontend type: github.com/kubernetes/application-dm-templates/common/replicatedservice:v1 properties: service_port: 80 container_port: 80 external_service: true replicas: 3 image: gcr.io/google_containers/example-guestbook-php-redis:v3 - name: redis type: github.com/kubernetes/application-dm-templates/storage/redis:v1 properties: null 

Ao descrever os componentes do aplicativo implementado, são indicados o nome, o modelo usado e também os parâmetros necessários desse modelo. No exemplo acima, os redis frontend e redis usam modelos do repositório oficial.

Já nesta versão, você pode usar recursos de uma base de conhecimento comum, criar seus próprios repositórios de modelos e criar aplicativos complexos devido aos parâmetros e aninhamento de modelos.

A arquitetura Helm 1 consiste em três componentes. O diagrama a seguir ilustra o relacionamento entre eles:



  1. Manager desempenha a função de um servidor Web (a comunicação com os clientes ocorre por meio da API REST), gerencia as implantações no cluster Kubernetes e é usado como um data warehouse.
  2. O componente expandybird traz as configurações do usuário para uma forma plana, ou seja, aplica modelos Jinja e executa scripts Python.
  3. Depois de receber uma configuração simples, o resourcifier faz as chamadas necessárias para o kubectl e retorna as mensagens de status e de erro, se houver, ao manager .

Para entender os recursos da primeira versão do Helm, darei ajuda no comando dm :
Ajuda da saída do dm
 Usage: ./dm [<flags>] <command> [(<template-name> | <deployment-name> | (<configuration> [<import1>...<importN>]))] Commands: expand Expands the supplied configuration(s) deploy Deploys the named template or the supplied configuration(s) list Lists the deployments in the cluster get Retrieves the supplied deployment manifest Lists manifests for deployment or retrieves the supplied manifest in the form (deployment[/manifest]) delete Deletes the supplied deployment update Updates a deployment using the supplied configuration(s) deployed-types Lists the types deployed in the cluster deployed-instances Lists the instances of the named type deployed in the cluster templates Lists the templates in a given template registry (specified with --registry) registries Lists the registries available describe Describes the named template in a given template registry getcredential Gets the named credential used by a registry setcredential Sets a credential used by a registry createregistry Creates a registry that holds charts Flags: -apitoken string Github api token that overrides GITHUB_API_TOKEN environment variable -binary string Path to template expansion binary (default "../expandybird/expansion/expansion.py") -httptest.serve string if non-empty, httptest.NewServer serves on this address and blocks -name string Name of deployment, used for deploy and update commands (defaults to template name) -password string Github password that overrides GITHUB_PASSWORD environment variable -properties string Properties to use when deploying a template (eg, --properties k1=v1,k2=v2) -regex string Regular expression to filter the templates listed in a template registry -registry string Registry name (default "application-dm-templates") -registryfile string File containing registry specification -service string URL for deployment manager (default "http://localhost:8001/api/v1/proxy/namespaces/dm/services/manager-service:manager") -serviceaccount string Service account file containing JWT token -stdin Reads a configuration from the standard input -timeout int Time in seconds to wait for response (default 20) -username string Github user name that overrides GITHUB_USERNAME environment variable --stdin requires a file name and either the file contents or a tar archive containing the named file. a tar archive may include any additional files referenced directly or indirectly by the named file. 

E agora, de volta ao texto original sobre a história de Helm ...

Alguns meses depois, unimos forças à equipe do Kubernetes Deployment Manager do Google e começamos a trabalhar no Helm 2. O objetivo era manter o Helm fácil de usar, adicionando o seguinte:

  1. modelos de gráfico (“gráfico” - um análogo de um pacote no ecossistema Helm - aprox. transl. ) para personalização;
  2. gerenciamento de cluster para equipes;
  3. repositório completo de gráficos;
  4. formato de pacote estável e assinado;
  5. forte compromisso com o controle de versão semântico e manutenção da compatibilidade com versões anteriores de versão para versão.

Para atingir esses objetivos, um segundo componente foi adicionado ao ecossistema Helm. Tornou-se o cluster interno do Tiller, que fornecia a instalação dos gráficos Helm e seu gerenciamento.

Nota perev.: Portanto, na segunda versão do Helm, o único componente restante no cluster é responsável pelo ciclo de vida da instalação ( release ) e a preparação da configuração é enviada ao cliente Helm.

Se a reinicialização do cluster ao usar a primeira versão do Helm levar a uma perda completa dos dados de serviço (desde que eles foram armazenados na RAM), no Helm 2 todos os dados serão armazenados no ConfigMaps , ou seja, recursos dentro do Kubernetes. Outra etapa importante foi a transição de uma API síncrona (onde todas as solicitações estavam bloqueando) para o uso de gRPC assíncrono.

Desde o lançamento do Helm 2 em 2016, o projeto Kubernetes experimentou um crescimento explosivo e novas oportunidades significativas. O Controle de Acesso Baseado em Função (RBAC) foi adicionado. Muitos novos tipos de recursos são introduzidos. Recursos de terceiros inventados (Definições de Recursos Personalizados, CRD). E o mais importante, existem práticas recomendadas. Passando por todas essas mudanças, Helm continuou a atender às necessidades dos usuários do Kubernetes. Mas ficou claro para nós que era hora de fazer grandes mudanças para que as necessidades desse ecossistema em desenvolvimento continuassem sendo atendidas.

Chegamos ao Helm 3. A seguir, falarei sobre algumas das inovações apresentadas no roteiro do projeto.

Saudações Lua


No Helm 2, introduzimos modelos. No estágio inicial do desenvolvimento do Helm 2, apoiamos modelos Go, Jinja, código Python limpo e até tínhamos um protótipo de suporte ao ksonnet. Mas a presença de muitos mecanismos de modelos deu origem a mais problemas do que resolveu. Portanto, chegamos ao ponto de escolher um.

Os modelos Go têm quatro vantagens:

  1. a biblioteca está embutida no Go ;
  2. os modelos são executados em um ambiente sandbox estritamente limitado;
  3. poderíamos inserir funções e objetos arbitrários no mecanismo;
  4. eles trabalharam bem com o YAML.

Embora tenhamos mantido a interface no Helm para oferecer suporte a outros mecanismos de modelo, os modelos Go se tornaram nosso padrão padrão. E os próximos anos de experiência mostraram como engenheiros de muitas empresas criaram milhares de gráficos usando modelos Go.

E nós aprendemos sobre suas decepções:

  1. A sintaxe é difícil de ler e mal documentada.
  2. Problemas de linguagem, como variáveis ​​imutáveis, tipos de dados complexos e regras de visibilidade restritivas, transformaram coisas simples em complexas.
  3. A incapacidade de definir funções nos modelos tornou a criação de bibliotecas reutilizáveis ​​ainda mais difícil.

Mais importante ainda, usando a linguagem de modelo, "truncamos" os objetos Kubernetes para sua representação de linha. (Em outras palavras, os desenvolvedores de modelos precisavam gerenciar os recursos do Kubernetes como documentos de texto no formato YAML.)

Trabalhar em objetos, não em pedaços de YAML


Repetidamente, ouvimos dos usuários uma solicitação para a capacidade de inspecionar e modificar os recursos do Kubernetes como objetos, não como strings. Ao mesmo tempo, eles afirmaram que, independentemente da forma de implementação que escolhemos para isso, deve ser fácil aprender e bem mantido no ecossistema.

Após meses de pesquisa, decidimos fornecer uma linguagem de script integrada que pode ser empacotada em uma sandbox e personalizada. Entre os 20 principais idiomas, havia apenas um candidato que atendeu aos requisitos: Lua .

Em 1993, um grupo de engenheiros de TI brasileiros criou uma linguagem de script leve para incorporar em suas ferramentas. Lua possui uma sintaxe simples, é amplamente suportado e tem sido destaque na lista dos 20 principais idiomas por um longo tempo. É suportado pelo IDE e editores de texto, existem muitos manuais e tutoriais. Em um ecossistema existente, gostaríamos de desenvolver nossa solução.

Nosso trabalho no Helm Lua ainda está na fase de prova conceitual, e esperamos uma sintaxe que seja familiar e flexível. Comparando as abordagens antiga e nova, você pode ver para onde estamos nos movendo.

Aqui está um exemplo de um modelo de lareira com Alpine no Helm 2:

 apiVersion: v1 kind: Pod metadata: name: {{ template "alpine.fullname" . }} labels: heritage: {{ .Release.Service }} release: {{ .Release.Name }} chart: {{ .Chart.Name }}-{{ .Chart.Version }} app: {{ template "alpine.name" . }} spec: restartPolicy: {{ .Values.restartPolicy }} containers: - name: waiter image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" imagePullPolicy: {{ .Values.image.pullPolicy }} command: ["/bin/sleep", "9000"] 

Nesse modelo simples, você pode ver imediatamente todas as diretivas {{ .Chart.Name }} modelo, como {{ .Chart.Name }} .

E aqui está a definição da mesma lareira na versão preliminar do código Lua:

 unction create_alpine_pod(_) local pod = { apiVersion = "v1", kind = "Pod", metadata = { name = alpine_fullname(_), labels = { heritage = _.Release.Service or "helm", release = _.Release.Name, chart = _.Chart.Name .. "-" .. _.Chart.Version, app = alpine_name(_) } }, spec = { restartPolicy = _.Values.restartPolicy, containers = { { name = waiter, image = _.Values.image.repository .. ":" .. _.Values.image.tag, imagePullPolicy = _.Values.image.pullPolicy, command = { "/bin/sleep", "9000" } } } } } _.resources.add(pod) end 

Não há necessidade de examinar todas as linhas deste exemplo para entender o que está acontecendo. É imediatamente óbvio que no código está definido em. Mas, em vez de usar cadeias YAML com diretivas de modelo internas, nós a definimos como um objeto em Lua.

Vamos encurtar esse código


Como trabalhamos diretamente com objetos (em vez de manipular uma grande quantidade de texto), podemos tirar o máximo proveito do script. As oportunidades para criar bibliotecas compartilhadas que aparecem aqui parecem realmente atraentes. E esperamos que, introduzindo bibliotecas especializadas (ou permitindo que a comunidade as crie), possamos reduzir o código acima para algo como isto:

 local pods = require("mylib.pods"); function create_alpine_pod(_) myPod = pods.new("alpine:3.7", _) myPod.spec.restartPolicy = "Always" -- set any other properties _.Manifests.add(myPod) end 

Neste exemplo, usamos a capacidade de trabalhar com a definição de um recurso como um objeto, o que é fácil de definir propriedades, mantendo a concisão e a legibilidade do código.

Modelos ... Lua ... Por que não todos juntos?


Embora os modelos não sejam tão maravilhosos para todas as tarefas, eles ainda têm certas vantagens. O Templates in Go é uma tecnologia estável, com uma base de usuários estabelecida e muitos gráficos existentes. Muitos desenvolvedores de gráficos afirmam gostar de escrever modelos. Portanto, não vamos remover o suporte ao modelo.

Em vez disso, queremos permitir que os modelos e Lua sejam usados ​​ao mesmo tempo. Os scripts Lua terão acesso aos modelos do Helm antes e depois da renderização, o que permitirá que desenvolvedores avançados de gráficos realizem transformações complexas nos gráficos existentes, mantendo a capacidade simples de criar gráficos do Helm com modelos.

Somos muito encorajados pelo suporte de scripts em Lua, mas ao mesmo tempo estamos nos livrando de uma parte significativa da arquitetura Helm ...

Dizer adeus a Tiller


Durante o desenvolvimento do Helm 2, apresentamos o Tiller como um componente de integração com o Deployment Manager. O Tiller desempenhou um papel importante para as equipes que trabalham no mesmo cluster: tornou possível interagir com o mesmo conjunto de releases para muitos administradores diferentes.

No entanto, o Tiller atuou como um servidor sudo gigante, concedendo uma ampla gama de direitos a todos que têm acesso ao Tiller. E nosso esquema de instalação padrão era a configuração permissiva. Portanto, os engenheiros do DevOps e do SRE precisaram aprender as etapas adicionais para instalar o Tiller em clusters de vários inquilinos.

Além disso, com o advento do CRD, não podíamos mais confiar no Tiller para manter o estado ou a função como um hub central para as informações de liberação do Helm. Só poderíamos armazenar essas informações como entradas separadas no Kubernetes.

O principal objetivo do Tiller pode ser alcançado sem o próprio Tiller. Portanto, uma das primeiras decisões tomadas durante a fase de planejamento do Helm 3 foi abandonar completamente o Tiller.

Melhoria de segurança


Sem o Tiller, o modelo de segurança Helm é radicalmente simplificado. A autenticação do usuário é delegada pelo Kubernetes. E autorização também. Os direitos do leme são definidos como direitos do Kubernetes (via RBAC), e os administradores de cluster podem restringir os direitos do leme em qualquer nível de detalhe necessário.

Versões, versões de liberação e armazenamento de estado


Na ausência do Tiller, para manter o estado de várias liberações dentro do cluster, precisamos de uma nova maneira para todos os clientes interagirem (no gerenciamento de liberações).

Para isso, introduzimos duas novas entradas:

  1. Release - para uma instalação específica de um gráfico específico. Se rodarmos helm install my-wordpress stable/wordpress , uma versão chamada my-wordpress será criada e mantida ao longo da vida desta instalação do WordPress.
  2. ReleaseVersion - sempre que você atualiza o gráfico Helm, é necessário considerar o que mudou e se a alteração foi bem-sucedida. ReleaseVersion vinculado a uma liberação e armazena apenas registros com informações sobre atualização, ReleaseVersion e exclusão. Quando executamos o helm upgrade my-wordpress stable/wordpress , o objeto Release original permanece o mesmo, mas um objeto filho ReleaseVersion com informações sobre a operação de atualização.

Releases e Releases ReleaseVersions serão armazenadas nos mesmos espaços de nomes que os objetos de gráfico.

Com esses recursos, as equipes de usuários do Helm poderão rastrear os registros das instalações do Helm no cluster sem a necessidade do Tiller.

Mas espere, isso não é tudo!


Neste artigo, tentei falar sobre algumas das principais alterações no Helm 3. No entanto, esta lista não está completa. O plano Helm 3 também inclui outras alterações, como melhorias no formato do gráfico, aprimoramentos de desempenho para repositórios de gráficos e um novo sistema de eventos que os desenvolvedores de gráficos podem usar. Também estamos tornando Eric Raymond chamado arqueologia de código, limpando a base de código e atualizando componentes que perderam relevância nos últimos três anos.

Nota perev. : É um paradoxo, mas o gerenciador de pacotes do Helm 2, quando a install ou upgrade bem upgrade sucedida, ou seja, ter liberação no estado de success não garante que os recursos do aplicativo tenham sido implementados com êxito (por exemplo, não há erros como ImagePullError ). Talvez o novo modelo de evento permita adicionar ganchos adicionais para recursos e controlar melhor o processo de lançamento - descobriremos em breve.

Com a adesão do Helm ao CNCF, não apenas o Helm 3, mas também o Chart Museum , o maravilhoso utilitário de teste de gráficos , o repositório oficial de gráficos e outros projetos sob os auspícios do Helm no CNCF nos inspiram. Estamos confiantes de que o bom gerenciamento de pacotes do Kubernetes é tão importante para o ecossistema nativo da nuvem quanto os bons gerenciadores de pacotes do Linux.

PS do tradutor


Leia também em nosso blog:

Source: https://habr.com/ru/post/pt417079/


All Articles