Nesta aula, vamos explorar dois recursos fundamentais do Kubernetes para gerenciar configurações e dados sensíveis: ConfigMaps e Secrets. Em qualquer aplicação moderna, é crucial separar o código da configuração, permitindo que o mesmo artefato seja implantado em diferentes ambientes (dev, staging, produção) sem recompilação. ConfigMaps e Secrets são a forma nativa do Kubernetes de lidar com isso, oferecendo flexibilidade e segurança.

Vamos começar entendendo por que a separação é importante e, em seguida, mergulhar na criação, uso e boas práticas de ConfigMaps e Secrets, incluindo diferentes formas de montá-los em seus pods.

Separando config do código

A separação de configuração do código é um princípio fundamental em DevOps e desenvolvimento de software. A ideia é que o código-fonte da aplicação seja imutável e independente do ambiente em que é executado. Isso significa que variáveis como URLs de banco de dados, chaves de API, credenciais e outras configurações não devem estar embutidas no código, mas sim fornecidas externamente.

No Kubernetes, essa separação é alcançada através de objetos como ConfigMaps e Secrets, que permitem injetar configuração nos pods sem alterar a imagem do contêiner. Isso traz benefícios como: maior portabilidade, facilidade de rotação de credenciais, e redução do risco de vazamento de dados sensíveis.

Um exemplo clássico é uma aplicação que precisa se conectar a um banco de dados. Em vez de codificar a string de conexão no código, você a coloca em um ConfigMap ou Secret, e a aplicação a lê em tempo de execução. Dessa forma, a mesma imagem pode ser usada em diferentes ambientes apenas alterando os objetos Kubernetes.

ConfigMaps

ConfigMaps são objetos do Kubernetes usados para armazenar dados não confidenciais em pares chave-valor. Eles podem ser usados para definir variáveis de ambiente, argumentos de linha de comando ou arquivos de configuração. ConfigMaps são ideais para dados como URLs, portas, nomes de serviços e outras configurações que não são sensíveis.

Um ConfigMap pode ser criado a partir de um arquivo YAML, de diretórios, ou diretamente via comandos kubectl. Vamos ver um exemplo de criação via YAML:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  DATABASE_URL: "mysql://user:pass@db-host:3306/appdb"
  LOG_LEVEL: "info"
  app.properties: |
    key1=value1
    key2=value2

Neste exemplo, temos duas variáveis simples (DATABASE_URL e LOG_LEVEL) e um arquivo de propriedades. O ConfigMap pode ser usado de várias maneiras: como variável de ambiente, como argumento de linha de comando, ou montado como volume.

Para usar um ConfigMap como variável de ambiente em um pod, você referencia o nome do ConfigMap e a chave desejada:

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  containers:
  - name: myapp
    image: myapp:latest
    envFrom:
    - configMapRef:
        name: app-config

O campo envFrom injeta todas as chaves do ConfigMap como variáveis de ambiente. Você também pode usar valueFrom para selecionar chaves específicas.

Para montar como volume, você pode fazer:

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  containers:
  - name: myapp
    image: myapp:latest
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config
  volumes:
  - name: config-volume
    configMap:
      name: app-config

Isso cria um volume com os dados do ConfigMap, permitindo que a aplicação leia arquivos de configuração diretamente do sistema de arquivos.

Secrets

Secrets são semelhantes aos ConfigMaps, mas são destinados a armazenar dados sensíveis, como senhas, chaves SSH, tokens e chaves de API. Eles são codificados em base64 e oferecem mecanismos de segurança adicionais, como criptografia em repouso e controle de acesso baseado em RBAC.

Para criar um Secret, você pode usar um arquivo YAML ou o comando kubectl create secret. O conteúdo deve ser codificado em base64, mas você pode usar o comando kubectl create secret generic para codificar automaticamente:

kubectl create secret generic db-secret --from-literal=username=admin --from-literal=password=S3cr3t

Ou via YAML, lembrando de codificar os valores em base64:

apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
data:
  username: YWRtaW4=
  password: UzNjcjN0

Para usar um Secret em um pod, você pode injetá-lo como variável de ambiente ou montá-lo como volume. Por exemplo:

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  containers:
  - name: myapp
    image: myapp:latest
    env:
    - name: DB_USER
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: username
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: password

Secrets também podem ser montados como arquivos em volumes, o que é útil para aplicações que leem credenciais de arquivos, como chaves SSL.

Montagem

A montagem (ou mounting) refere-se ao processo de disponibilizar ConfigMaps e Secrets dentro do pod como volumes ou variáveis de ambiente. Isso é essencial para que a aplicação possa acessar a configuração em tempo de execução.

Vamos detalhar as duas formas principais:

  • Variáveis de ambiente: A configuração é injetada como variáveis de ambiente no contêiner. Isso é simples e adequado para configurações pequenas.
  • Volumes: Os dados são montados como arquivos em um diretório específico. Isso é útil quando a aplicação espera arquivos de configuração (ex.: application.properties, config.yaml).

Exemplo de montagem de volume com um Secret:

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  containers:
  - name: myapp
    image: myapp:latest
    volumeMounts:
    - name: secret-volume
      mountPath: /etc/secret
  volumes:
  - name: secret-volume
    secret:
      secretName: db-secret
      defaultMode: 0400

Neste exemplo, o Secret é montado em /etc/secret com permissões restritas. Cada chave do Secret se torna um arquivo dentro do diretório.

É importante notar que, ao montar um ConfigMap ou Secret como volume, as atualizações nesses objetos são propagadas automaticamente para os pods que os montam (embora com algum atraso). Isso permite atualizar configurações sem reiniciar os pods, embora nem todas as aplicações leiam as mudanças dinamicamente.

Boas práticas

Ao trabalhar com ConfigMaps e Secrets, siga estas boas práticas:

  • Use ConfigMaps para dados não sensíveis e Secrets para dados sensíveis.
  • Limite o acesso a Secrets usando RBAC e namespaces.
  • Evite armazenar Secrets em sistemas de controle de versão; use ferramentas como Sealed Secrets ou Vault.
  • Prefira montar volumes a variáveis de ambiente se a aplicação precisar de muitos valores ou arquivos.
  • Nomeie ConfigMaps e Secrets de forma descritiva e use labels para organização.
  • Considere usar subPath para montar arquivos individuais em vez de diretórios inteiros.

Além disso, em produção, é recomendável habilitar a criptografia de Secrets em repouso no etcd, configurando a chave de criptografia apropriada no kube-apiserver.

Referências

Exercícios

  1. Crie um ConfigMap chamado meu-config com as chaves COR e NIVEL (valores: azul e alto). Use o comando kubectl.
  2. ✓ Resposta:
    kubectl create configmap meu-config --from-literal=COR=azul --from-literal=NIVEL=alto
  3. Como você faria para montar um ConfigMap como volume em um pod, no caminho /etc/config? Escreva o YAML do pod.
  4. ✓ Resposta:
    apiVersion: v1
    kind: Pod
    metadata:
      name: meu-pod
    spec:
      containers:
      - name: app
        image: nginx
        volumeMounts:
        - name: config-volume
          mountPath: /etc/config
      volumes:
      - name: config-volume
        configMap:
          name: meu-config
  5. Crie um Secret chamado meu-secret com os dados usuario=admin e senha=123456 usando kubectl.
  6. ✓ Resposta:
    kubectl create secret generic meu-secret --from-literal=usuario=admin --from-literal=senha=123456
  7. Em um pod, como você injetaria a chave senha do Secret meu-secret como variável de ambiente DB_PASSWORD? Escreva o trecho YAML do contêiner.
  8. ✓ Resposta:
    env:
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: meu-secret
          key: senha
  9. Qual a diferença principal entre ConfigMap e Secret? Dê um exemplo de uso para cada.
  10. ✓ Resposta: ConfigMaps são para dados não sensíveis, como URLs públicas ou níveis de log. Secrets são para dados sensíveis, como senhas e chaves. Exemplo: ConfigMap para LOG_LEVEL e Secret para DB_PASSWORD.