7.4 Entendendo o Chart

Helm Charts

O deploy da aplicação no Kubernetes pode ser realizado por meio do Helm, o qual, como dito anteriormente, é um gerenciador de pacotes para o Kubernetes. Nesse caso podemos entender pacote como uma ou mais aplicações. Ou seja, com o Helm podemos instalar e gerenciar aplicações em um cluster Kubernetes, que é exatamente o que ocorre no Auto DevOps.

Conceitos importantes

Para entender como funciona o Helm, precisamos entender alguns conceitos importantes referentes a como o Helm trabalha. Basicamente são 3 conceitos principais:

  • Chart

  • Config

  • Release

Chart

O chart é conjunto de informações necessárias, reunidas numa coleção de arquivos, para definir uma estrutura lógica para realizar o deploy uma aplicação no Kubernetes.

Vamos simplificar nossa aplicação e imaginar que ela necessite apenas de um servidor Tomcat e de um banco MySQL para ser executada. O chart nesse caso descreverá os elementos (recursos) da estrutura necessária para executar essa aplicação no Kubernetes, por exemplo, deployments, services, load balancers e volumes.

Config

A configuração (config) consiste na definição de valores que serão utilizados para a realização do deploy, adaptando-o conforme necessidade. Por exemplo, podemos ter uma configuração específica para o ambiente de produção e outra para um ambiente de teste. Ou seja, pode ser entendida como uma personalização ou adequação do chart para um propósito específico.

Release

A release consiste na implantação efetiva da aplicação, usando como base o chart e as configurações pré-determinadas para o ambiente em questão. Ou seja, ela consiste em tornar real o plano que é dado pelo chart e pela config.

Entendidos esses conceitos, vamos analisar em detalhes a estrutura de um chart.

Estrutura de um chart

Os arquivos do chart são alocados uma estrutura de diretórios bem definida:

chart/
  Chart.yaml          # Arquivo YAML com informações sobre o chart
  LICENSE             # Opcional: Arquivo de texto plano com a licença para o chart
  README.md           # Opcional: Um README para explicar o funcionamento do chart
  values.yaml         # Os valores-padrão de configuraçãodo chart
  values.schema.json  # Opcional: Arquivo json para impor uma estrutura arbitrária dos valores no arquivo values.yaml
  charts/             # Opcional: Diretório onde devem estar os charts dos quais esse chart depende.
  crds/               # Opcional: Custom Resource Definitions (https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/)
  templates/          # Diretório de templates para definição dos recursos do Kubernetes. Nesses templates podem
                      # existir variáveis que serão substituídas com os valores definidos no values.yaml,
  templates/NOTES.txt # Opcional: Arquivo contendo explicações de como usar o chart

Veremos essa estrutura em detalhes a seguir.

Diretório chart

O diretório chart pode ter qualquer nome, de preferência o nome da aplicação. No caso do SAGUI, o nome desse diretório poderia ser sagui. Esse é o diretório raiz do chart, e é nele (e nos seus subdiretórios) que estão contidos todos os arquivos do chart, inclusive as configurações.

Arquivo LICENSE

Nesse arquivo de texto, pode estar contida a licença pela qual o chart é disponibilizado. Ele permite aos usuários do chart entenderem os modos pelos quais podem fazer uso do chart, se podem redistribuí-lo, etc.

Arquivo README.md

Esse arquivo é utizado para explicar o funcionamento do chart. Nele podem/devem estar os valores padrão das variáveis utilizadas no chart, bem como o significado delas.

É a principal documentação do chart, pode ser gerado automaticamente usando ferramentas como o Helm Docs.

Arquivo Chart.yaml

O arquivo Chart.yaml é obrigatório em todo chart. Nesse arquivo são definidas diversas informações sobre o chart, por meio de campos pré-definidos, sendo alguns obrigatórios e outros opcionais. Os campos obrigatórios são:

apiVersion: Versão da API utilizada no chart
name: O nome do chart
version: A versão do chart, seguindo a versão 2 da SemVer (https://semver.org/lang/pt-BR/)

Caso tenha interesse, confira a lista dos demais campos.

Como exemplo, temos o Chart.yaml usado no projeto:

apiVersion: v2
name: loja-virtual
description: Chart para implantação da loja virtual no Kubernetes

type: application
version: 0.1.0
appVersion: "1.16.0"

No campo apiVersion, deve ser informado o valor v2 para projetos que exigem o Helm 3, e v1 para projetos que suportam versões prévias dele.

Um fato interessante, é que existe o campo version, para indicar a versão do chart e o campo appVersion, que define a versão da aplicação que será instalad pelo chart, sendo assim, esses campos podem ter valores diferentes, como no caso da aplicação que estamos utilizando.

Diretório charts

Esse diretório é bem interessante, pois pode ser utilizado para armazenar os charts dos quais depende o chart atual. Considerando nossa aplicação, que depende do MySQL e do Nagios, nesse diretório, poderiam estar os charts de cada uma dessas aplicações, o que simplifica o entendimento do chart atual.

Diretório templates

O diretório templates é sem dúvida o diretório mais importante de um chart. É nele que são definidos os templates dos recursos Kubernetes utilizados para realizar a implantação da aplicação. Esses templates quando combinados com valores devem gerar arquivos Kubernetes válidos.

Vamos ver um exemplo de template bem simples:

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
{{- include "app.labels" . | nindent 4 }}
  name: {{ .Values.app.name }
spec:
  replicas: 1
  selector:
    matchLabels:
{{- include "app.labels" . | nindent 4 }}
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
{{- include "app.labels" . | nindent 4 }}
    spec:
      containers:
      - image: {{ .Values.app.image.repository }}
        name: {{ .Values.app.container.name }}
        resources: {}

Todos os trechos de código que estão entre {{ }} são trechos que são passíveis de alteração por um determinado valor. Por exemplo, na linha name: {{ .Values.app.name }} o valor do campo name será dado pelo valor definido para a chave app.name. As chaves e seus respectivos valores geralmente estão definidas no arquivo values.yaml.

Já a construção {{- include "app.labels" . | nindent 4 }} terá seu valor definido pela execução da função include, que permite a utilização de uma construção chamada named template.

Para entender como podemos determinar esses valores, vamos olhar o arquivo values.yaml

Arquivo values.yaml

Como todo arquivo YAML, o arquivo values.yaml espera que sejam definidas chaves e seus repectivos valores. O modo mais simples é assim:

chave: valor

Mas também é possível ter chaves aninhadas:

chave1: 
    subchave1_1: valor_subchave1
    subchave1_2:
      subchave1_2_1: valor_subchave1_2_1

Ou de modo mais verboso:

chave1.subchave1_1: valor_subchave1
chave1.subchave1_2.subchave1_2_1: valor_subchave1_2_1

Para maiores informações, consulte a documentação oficial.

Esse arquivo faz parte da estrutura do chart, mas determina as configurações (config) de uma release. É importante salientar, que também é possível utilizar arquivos extra de configuração, além de ser possível passar configurações por linha de comando, como veremos posteriormente.

Exemplos

Vamos olhar um trecho do arquivo values.yaml da aplicação:

# Default values for chart.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.

replicaCount: 1

app:
  image:
    repository: nginx
    pullPolicy: IfNotPresent
    # Overrides the image tag whose default is the chart appVersion.
    tag: ""
imagePullPolicy: IfNotPresent
imagePullSecrets: 
  - name: gitlab-registry
nameOverride: ""
fullnameOverride: ""

Observe que podemos usar comentários, pré-fixando as linhas com o caracter #. Além disso, podemos utilizar esse arquivo para personalizar nosso deployment, configurando por a imagem utilizada:

app:
  image:
    repository: nginx

Como vimos, esse valor pode ser utilizado no arquivo de deployment do seguinte modo:

    spec:
      containers:
      - image: {{ .Values.app.image.repository }}

Valores de variáveis diferentes por ambiente

Como mencionado anteriormente, o arquivo values.yaml é utilizado para definir valores padrão que são utilizados nos templates do Helm. No entanto, há casos em que é necessários ter configurações diferentes de acordo com o ambiente no qual será feita a implantação da aplicação. Felizmente, o Helm permite a utilização de outro arquivo com definição de valores para sobreescrever valores padrão definidos no values.yaml.

Podemos por exemplo, definir um arquivo com um nome arbitrário, por exemplo prod-values.yaml. Ele usa a mesma sintaxe do arquivo values.yaml, sobre o qual terá precedência.

Imaginemos então a seguinte situação. Criamos o arquivo values.yaml do seguinte modo:

chave1: valor1
chave2: valor2

E o arquivo prod-values.yaml assim:

chave1: valor1a
chave3: valor3

Esses dois arquivos são então combinados (mesclados), e devido a precedência sobre o arquivo values.yaml, a variável chave1 assume o valor valor1a definido no rod-values.yaml, já a variável chave3, definida somente no arquivo rod-values.yaml recebe o valor valor3, e a variável chave2, por não estar definida nesse arquivo, herda o valor do values.yaml (valor2). Sendo assim, os valores passados para o Helm seriam:

chave1: valor1a
chave2: valor2
chave3: valor3

Ou seja, é feita uma mescla entre os dois arquivos, e o resultado final leva em consideração a precedência do arquivo prod-values.yaml. Podemos ter um arquivo de values para cada ambiente, desse modo, é possível utilizar valores diferentes para cada ambiente, tornando bem flexível a utilização do Helm.

É importante salientar que os nomes (e o diretório) desses arquivos são arbitrários e escolhidos pelo usuário, não sendo necessário seguir uma convenção nesses casos.

Testando templates

Ao criar ou modificar um template, ou então modificar os valores utilizados nele, é sempre uma boa prática verificar se o arquivo Kubernetes gerado a partir do template é realmente válido. Para fazer isso, você deve ter o Helm instalado localmente.

Validação dos arquivos Kubernetes

Uma vez instalado o Helm localmente, e assumindo a convenção do GitLab para os arquivos prod-values.yaml e values.yaml podemos gerar os arquivos do Kubernetes com o seguinte comando:

helm template chart/ -f prod-values.yaml -f chart/values.yaml --debug -v 5 --output-dir ./build/templates/

Nesse comando informamos que desejamos utilizar um template (helm template) para gerar arquivos Kubernetes no diretório .build/templates/ com a opção --output-dir, sendo que nosso chart está localizado em chart, e nossos arquivos de valores serão prod-values.yaml e chart/values.yaml, dado o parâmetro -f. Além disso queremos executar em modo de debug (--debug), com verbosidade nível 5 (-v 5).

Desse modo, se houver algum problema no template, como por exemplo sintaxe incorreta, ou falta de definição de algum valor, saberemos rapidamente, sem ter que tentar implantar a aplicação no Kubernetes.

Os contêineres que são exectados no Kubernetes utilizam imagens construídas previamente e armazenadas em registries, que são repositórios de imagens. Na próxima seção, vamos conhecer o Jib, uma ferramenta que auxilia a criação de imagens de aplicações Java sem a necessidade de conhecer e ter instalado o Docker, além de outras vantagens.

Last updated