Em aplicações modernas, especialmente em ambientes de contêineres e orquestração como Kubernetes, a separação entre código e configuração é uma prática essencial para manter a flexibilidade, segurança e escalabilidade. Nesta aula, vamos explorar dois recursos fundamentais do Kubernetes: ConfigMaps e Secrets. Eles permitem que você gerencie configurações de aplicativos sem precisar reconstruir imagens de contêineres ou expor dados sensíveis no código-fonte.

Vamos entender como criar, utilizar e montar esses recursos em seus pods, além de discutir boas práticas para lidar com configurações em ambientes dinâmicos.

Separando config do código

O princípio de separar configuração do código é uma das bases do design de software moderno. Em vez de embutir valores como URLs de banco de dados, chaves de API ou parâmetros de ambiente diretamente no código-fonte, você os externaliza em arquivos de configuração, variáveis de ambiente ou serviços de gerenciamento de configuração. Isso traz benefícios como: a possibilidade de alterar o comportamento da aplicação sem recompilar o código, a facilidade de promover a mesma imagem de contêiner entre diferentes ambientes (desenvolvimento, teste, produção) e a redução de riscos de segurança ao evitar a exposição de dados sensíveis no repositório.

No contexto do Kubernetes, essa separação é alcançada principalmente por meio de dois objetos: ConfigMap e Secret. Ambos armazenam dados que podem ser injetados nos pods como variáveis de ambiente, argumentos de linha de comando ou arquivos montados em volumes. A diferença fundamental é que Secrets são destinados a dados sensíveis, como senhas e chaves, enquanto ConfigMaps são para configurações não sensíveis. Kubernetes também oferece criptografia básica para Secrets, embora a criptografia em repouso dependa da configuração do cluster.

ConfigMaps

Um ConfigMap é um objeto do Kubernetes que armazena dados não confidenciais em pares chave-valor. Ele permite que você mantenha a configuração do aplicativo separada da imagem do contêiner, facilitando a atualização de configurações sem precisar reconstruir imagens. Você pode criar um ConfigMap a partir de literais, arquivos ou diretórios, e depois referenciá-lo em seus pods.

Para criar um ConfigMap, você pode usar o comando kubectl create configmap. Por exemplo, para criar um ConfigMap chamado app-config com algumas variáveis:

kubectl create configmap app-config --from-literal=APP_COLOR=blue --from-literal=APP_MODE=production

Você também pode criar a partir de arquivos de configuração:

kubectl create configmap app-config --from-file=application.properties

Depois de criado, você pode usar o ConfigMap em um pod de várias maneiras. A mais comum é definir variáveis de ambiente a partir do ConfigMap. No manifesto YAML do pod, você pode usar valueFrom e configMapKeyRef:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: nginx
    env:
    - name: APP_COLOR
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: APP_COLOR

Também é possível montar o ConfigMap como um volume, o que veremos na seção de montagem.

Secrets

Secrets são semelhantes aos ConfigMaps, mas são projetados para armazenar dados sensíveis, como senhas, tokens e chaves SSH. O Kubernetes armazena Secrets em formato base64, mas isso não é criptografia; qualquer pessoa com acesso ao cluster pode facilmente decodificá-los. Portanto, é importante usar mecanismos adicionais como criptografia em repouso e controle de acesso baseado em RBAC.

Para criar um Secret, use o comando kubectl create secret. Por exemplo, para criar um Secret chamado db-secret com uma senha:

kubectl create secret generic db-secret --from-literal=DB_PASSWORD=supersecret

Você também pode criar a partir de arquivos:

kubectl create secret generic db-secret --from-file=credentials.txt

Para usar o Secret em um pod, você pode injetar como variável de ambiente:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: postgres
    env:
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: DB_PASSWORD

Lembre-se de que os valores dos Secrets são codificados em base64, mas você pode usar o valor diretamente no YAML se quiser, desde que esteja no formato correto.

Montagem

Além de injetar variáveis de ambiente, você pode montar ConfigMaps e Secrets como volumes nos pods. Isso é útil quando sua aplicação espera arquivos de configuração em um diretório específico, como /etc/config. Quando você monta um ConfigMap ou Secret como volume, cada chave se torna um arquivo no diretório de montagem, com o conteúdo sendo o valor correspondente.

Por exemplo, para montar o ConfigMap app-config no diretório /etc/config:

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

Da mesma forma, para Secrets, você pode montar como volume:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: nginx
    volumeMounts:
    - name: secret-volume
      mountPath: /etc/secret
  volumes:
  - name: secret-volume
    secret:
      secretName: db-secret

Uma vantagem de montar como volume é que as atualizações nos ConfigMaps/Secrets podem ser refletidas nos pods automaticamente (dependendo da configuração de sincronização), enquanto variáveis de ambiente não são atualizadas após a criação do pod.

Boas práticas

Ao trabalhar com ConfigMaps e Secrets, considere as seguintes boas práticas:

  • Não inclua dados sensíveis em ConfigMaps; use Secrets para isso.
  • Limite o acesso a Secrets usando RBAC e namespaces.
  • Considere usar ferramentas como Sealed Secrets ou External Secrets para gerenciar Secrets de forma mais segura.
  • Prefira montar volumes para configurações que podem mudar durante a vida útil do pod.
  • Use nomes descritivos e organize seus ConfigMaps/Secrets por aplicação ou namespace.

Exercícios

  1. Crie um ConfigMap chamado meu-config com as chaves COR=azul e MODO=teste usando kubectl. Qual comando você usaria?
  2. ✓ Resposta: kubectl create configmap meu-config --from-literal=COR=azul --from-literal=MODO=teste
  3. Escreva um manifesto YAML para um pod que use o ConfigMap meu-config para definir a variável de ambiente COR.
  4. ✓ Resposta:
    apiVersion: v1
    kind: Pod
    metadata:
      name: meu-pod
    spec:
      containers:
      - name: meu-container
        image: nginx
        env:
        - name: COR
          valueFrom:
            configMapKeyRef:
              name: meu-config
              key: COR
  5. Crie um Secret chamado meu-secret com a chave SENHA=123456 usando kubectl e depois visualize o valor codificado em base64.
  6. ✓ Resposta: kubectl create secret generic meu-secret --from-literal=SENHA=123456
    Para ver: kubectl get secret meu-secret -o yaml e observe o valor em base64 (MTIzNDU2).
  7. Monte o Secret meu-secret como volume no caminho /etc/segredo em um pod. Escreva o YAML.
  8. ✓ Resposta:
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-com-secret
    spec:
      containers:
      - name: container
        image: nginx
        volumeMounts:
        - name: segredo-volume
          mountPath: /etc/segredo
      volumes:
      - name: segredo-volume
        secret:
          secretName: meu-secret
  9. Explique a diferença entre usar ConfigMaps/Secrets como variáveis de ambiente e como volumes, e quando preferir cada um.
  10. ✓ Resposta: Variáveis de ambiente são estáticas e não são atualizadas após a criação do pod, enquanto volumes são atualizados dinamicamente (se o kubelet sincronizar). Use variáveis para configurações que não mudam durante a vida do pod, e volumes para configurações que podem ser atualizadas ou quando a aplicação espera arquivos de configuração.

Referências