Introdução
Gerenciar as permissões de volume no Kubernetes pode ser desafiador para desenvolvedores e administradores de sistema. Quando os contêineres precisam ler ou escrever em volumes persistentes, problemas de permissão frequentemente surgem devido a incompatibilidades entre os IDs de usuário do contêiner e a propriedade do volume. Esses desafios podem causar falhas de aplicação e problemas de acesso a dados.
Este laboratório irá guiá-lo através dos problemas comuns de permissão de volume no Kubernetes e fornecer soluções práticas para resolvê-los. Você aprenderá como configurar corretamente os contextos de segurança, usar contêineres init (init containers) e implementar as melhores práticas para o gerenciamento de permissões de volume em suas implantações Kubernetes.
Compreendendo os Volumes do Kubernetes
Nesta etapa, exploraremos os volumes do Kubernetes e entenderemos como eles funcionam. Os volumes do Kubernetes fornecem uma maneira para os contêineres armazenarem e acessarem dados de forma persistente, mesmo quando os contêineres são reiniciados ou reprogramados.
Tipos de Volumes do Kubernetes
O Kubernetes suporta vários tipos de volume:
- EmptyDir: Um diretório vazio simples que existe durante a vida útil de um pod.
- HostPath: Monta um arquivo ou diretório do sistema de arquivos do nó host em seu pod.
- PersistentVolume: Um recurso de armazenamento provisionado por um administrador com um ciclo de vida independente de qualquer pod.
- ConfigMap e Secret: Fornecem uma maneira de injetar dados de configuração e informações confidenciais.
Criando Seu Primeiro Volume
Vamos criar um pod simples com um volume EmptyDir:
- Crie um arquivo YAML para a configuração do nosso pod:
cd ~/project/k8s-volume-demo
nano emptydir-pod.yaml
- Copie o seguinte conteúdo para o arquivo:
apiVersion: v1
kind: Pod
metadata:
name: emptydir-pod
spec:
containers:
- name: container-1
image: ubuntu:22.04
command:
[
"/bin/bash",
"-c",
"while true; do echo $(date) >> /data/log.txt; sleep 10; done"
]
volumeMounts:
- name: data-volume
mountPath: /data
volumes:
- name: data-volume
emptyDir: {}
Salve o arquivo (pressione Ctrl+X, depois Y, depois Enter).
Crie o pod em seu cluster Kubernetes:
kubectl apply -f emptydir-pod.yaml
- Aguarde até que o pod esteja pronto:
kubectl get pods
A saída deve mostrar seu pod em estado de execução:
NAME READY STATUS RESTARTS AGE
emptydir-pod 1/1 Running 0 30s
- Vamos verificar o conteúdo do nosso volume:
kubectl exec emptydir-pod -- cat /data/log.txt
Você deve ver uma lista de timestamps, mostrando que nosso contêiner está escrevendo no volume:
Mon Jan 1 12:34:56 UTC 2023
Mon Jan 1 12:35:06 UTC 2023
Mon Jan 1 12:35:16 UTC 2023
Compreendendo as Montagens de Volume (Volume Mounts)
No exemplo acima:
- Definimos um volume chamado
data-volumedo tipoemptyDir - Montamos este volume no contêiner no caminho
/data - O contêiner escreve timestamps em um arquivo neste volume
Isso demonstra o conceito básico de volumes do Kubernetes - eles fornecem armazenamento que é acessível por contêineres em um pod. O volume EmptyDir existe durante a vida útil do pod, então, se o pod for excluído, os dados serão perdidos.
Limpeza
Vamos excluir o pod que criamos:
kubectl delete pod emptydir-pod
Na próxima etapa, exploraremos como os problemas de permissão podem surgir ao usar volumes e como identificá-los.
Identificando Problemas de Permissão de Volume
Nesta etapa, criaremos um cenário que demonstra problemas comuns de permissão de volume no Kubernetes. Esses problemas normalmente ocorrem ao usar volumes HostPath ou volumes persistentes, onde as permissões do sistema de arquivos não correspondem ao ID do usuário em execução no contêiner.
Compreendendo o Problema
Quando um contêiner é executado como um usuário não-root, mas tenta acessar um volume pertencente ao root (ou outro usuário), erros de permissão negada podem ocorrer. Este é um problema comum em ambientes de produção, onde a execução de contêineres como usuários não-root é uma prática recomendada de segurança.
Criando um Volume HostPath com Problemas de Permissão
Vamos criar um pod que tenta acessar um volume HostPath com propriedade root:
- Crie um arquivo YAML para a configuração do nosso pod:
cd ~/project/k8s-volume-demo
nano hostpath-pod.yaml
- Copie o seguinte conteúdo para o arquivo:
apiVersion: v1
kind: Pod
metadata:
name: hostpath-pod
spec:
containers:
- name: container-1
image: ubuntu:22.04
command:
[
"/bin/bash",
"-c",
"while true; do echo 'Trying to write' >> /data/output.txt; sleep 10; done"
]
volumeMounts:
- name: host-data
mountPath: /data
securityContext:
runAsUser: 1000 ## Run as non-root user
volumes:
- name: host-data
hostPath:
path: /home/labex/project/k8s-volume-demo/data
type: Directory
Salve o arquivo (pressione Ctrl+X, depois Y, depois Enter).
Crie o pod em seu cluster Kubernetes:
kubectl apply -f hostpath-pod.yaml
- Aguarde um momento e, em seguida, verifique o status do pod:
kubectl get pods
- Você deve ver que o pod está em execução, mas se verificarmos os logs, podemos ver erros:
kubectl logs hostpath-pod
Você pode ver erros de permissão negada como:
bash: /data/output.txt: Permission denied
- Vamos confirmar o problema verificando as permissões em nosso diretório host:
ls -la ~/project/k8s-volume-demo/data
Você deve ver uma saída como:
total 12
drwxr-xr-x 2 root root 4096 Jan 1 12:00 .
drwxr-xr-x 3 labex labex 4096 Jan 1 12:00 ..
-rw-r--r-- 1 root root 19 Jan 1 12:00 test.txt
O diretório e os arquivos pertencem ao root, mas nosso contêiner está sendo executado como ID de usuário 1000. Essa incompatibilidade causa os erros de permissão negada.
Compreendendo os IDs de Usuário e Grupo em Contêineres
No Kubernetes, os contêineres podem ser executados como IDs de usuário específicos através da configuração securityContext. Em nosso exemplo:
securityContext:
runAsUser: 1000 ## Run as non-root user
Isso informa ao Kubernetes para executar o processo do contêiner como ID de usuário 1000, que não tem permissão para escrever nos arquivos pertencentes ao root.
Limpeza
Antes de passarmos para a próxima etapa, vamos excluir o pod:
kubectl delete pod hostpath-pod
Na próxima etapa, exploraremos soluções para esses problemas de permissão.
Corrigindo Problemas de Permissão com Security Context
Nesta etapa, exploraremos como usar o SecurityContext do Kubernetes para resolver problemas de permissão de volume. O SecurityContext define configurações de privilégio e controle de acesso para pods e contêineres.
Usando fsGroup para Corrigir Permissões
A configuração fsGroup em um SecurityContext pode ajudar a resolver problemas de permissão. Quando especificado, o Kubernetes altera a propriedade do grupo do volume para corresponder ao ID do grupo especificado e define a permissão para que o volume seja legível e gravável por esse grupo.
Vamos criar um pod com um SecurityContext adequado:
- Crie um arquivo YAML para a configuração do nosso pod:
cd ~/project/k8s-volume-demo
nano fixed-pod.yaml
- Copie o seguinte conteúdo para o arquivo:
apiVersion: v1
kind: Pod
metadata:
name: fixed-pod
spec:
securityContext:
fsGroup: 2000 ## Set group ID for all containers in the pod
containers:
- name: container-1
image: ubuntu:22.04
command:
[
"/bin/bash",
"-c",
"while true; do echo $(date) >> /data/output.txt; cat /data/test.txt; sleep 10; done"
]
volumeMounts:
- name: host-data
mountPath: /data
securityContext:
runAsUser: 1000 ## Run as non-root user
volumes:
- name: host-data
hostPath:
path: /home/labex/project/k8s-volume-demo/data
type: Directory
Salve o arquivo (pressione Ctrl+X, depois Y, depois Enter).
Crie o pod em seu cluster Kubernetes:
kubectl apply -f fixed-pod.yaml
- Aguarde até que o pod esteja pronto:
kubectl get pods
- Agora, vamos verificar os logs para ver se nosso problema de permissão foi resolvido:
kubectl logs fixed-pod
Você deve ver timestamps sendo gravados com sucesso, mostrando que o contêiner agora pode escrever no volume:
This is a test file
Mon Jan 1 12:45:06 UTC 2023
This is a test file
Mon Jan 1 12:45:16 UTC 2023
- Vamos examinar o que aconteceu com as permissões do volume:
## Get into the container
kubectl exec -it fixed-pod -- bash
## Inside the container, check the permissions
ls -la /data
## Exit the container
exit
Você deve ver que os arquivos no volume agora são acessíveis pelo contêiner porque o Kubernetes aplicou a configuração fsGroup.
Compreendendo as Configurações do Security Context
- runAsUser: Especifica o ID do usuário sob o qual os processos do contêiner serão executados.
- fsGroup: Controla o ID do grupo usado para acesso ao volume. Todos os processos no pod farão parte deste grupo suplementar.
- runAsGroup: Especifica o ID do grupo primário para todos os processos dentro dos contêineres (opcional).
Essas configurações ajudam a garantir que seus contêineres possam acessar corretamente os dados do volume, mantendo as práticas recomendadas de segurança de não serem executados como root.
Limpeza
Vamos excluir o pod que criamos:
kubectl delete pod fixed-pod
Na próxima etapa, exploraremos outra abordagem para corrigir problemas de permissão usando contêineres init.
Usando Contêineres Init para Corrigir Permissões
Em algumas situações, usar fsGroup pode não ser suficiente ou possível. Por exemplo, ao usar certos tipos de volume ou ao executar em versões mais antigas do Kubernetes. Nesses casos, os contêineres init podem ser usados para definir as permissões corretas antes que o contêiner principal seja iniciado.
O que são Contêineres Init?
Os contêineres init são executados antes dos contêineres principais em um pod. Eles podem executar tarefas de inicialização, como configurar permissões, baixar conteúdo ou aguardar dependências. Os contêineres init são particularmente úteis para o gerenciamento de permissões, pois podem ser executados com privilégios elevados para alterar a propriedade e as permissões dos arquivos de volume.
Criando um Pod com um Contêiner Init
Vamos criar um pod que usa um contêiner init para corrigir permissões:
- Crie um arquivo YAML para a configuração do nosso pod:
cd ~/project/k8s-volume-demo
nano init-pod.yaml
- Copie o seguinte conteúdo para o arquivo:
apiVersion: v1
kind: Pod
metadata:
name: init-pod
spec:
initContainers:
- name: permission-fixer
image: ubuntu:22.04
command:
["/bin/bash", "-c", "chown -R 1000:1000 /data && chmod -R 755 /data"]
volumeMounts:
- name: host-data
mountPath: /data
securityContext:
runAsUser: 0 ## Run as root to change permissions
containers:
- name: main-container
image: ubuntu:22.04
command:
[
"/bin/bash",
"-c",
"while true; do echo $(date) >> /data/init-output.txt; cat /data/test.txt; sleep 10; done"
]
volumeMounts:
- name: host-data
mountPath: /data
securityContext:
runAsUser: 1000 ## Run as non-root user
volumes:
- name: host-data
hostPath:
path: /home/labex/project/k8s-volume-demo/data
type: Directory
Salve o arquivo (pressione Ctrl+X, depois Y, depois Enter).
Crie o pod em seu cluster Kubernetes:
kubectl apply -f init-pod.yaml
- Aguarde até que o pod esteja pronto. O pod permanecerá no estado "Init" até que o contêiner init seja concluído:
kubectl get pods
- Depois que o pod estiver no estado de execução, verifique os logs do contêiner principal:
kubectl logs init-pod
Você deve ver timestamps sendo gravados com sucesso, mostrando que o contêiner agora pode escrever no volume:
This is a test file
Mon Jan 1 13:05:06 UTC 2023
This is a test file
Mon Jan 1 13:05:16 UTC 2023
- Vamos examinar o que aconteceu com as permissões do volume:
## Check the content of the data directory
ls -la ~/project/k8s-volume-demo/data
Você notará que a propriedade do arquivo foi alterada para refletir o ID do usuário especificado no comando do contêiner init.
Compreendendo a Abordagem do Contêiner Init
Neste exemplo:
- O contêiner init é executado com privilégios de root (
runAsUser: 0) - Ele altera a propriedade e as permissões do conteúdo do volume
- Após a conclusão do contêiner init, o contêiner principal é iniciado
- O contêiner principal é executado como um usuário não-root (
runAsUser: 1000) - O contêiner principal agora pode ler e gravar no volume
Essa técnica é particularmente útil quando:
- Você precisa preparar volumes com padrões de propriedade específicos
- Você está trabalhando com volumes que não suportam
fsGroup - Você precisa executar uma lógica complexa de configuração de permissões
Limpeza
Vamos excluir o pod que criamos:
kubectl delete pod init-pod
Na próxima etapa, exploraremos as melhores práticas e aprenderemos como combinar essas abordagens para um gerenciamento robusto de permissões de volume.
Melhores Práticas e Abordagem Combinada
Em cenários do mundo real, pode ser necessário combinar várias abordagens para lidar com as permissões de volume de forma eficaz. Nesta etapa final, exploraremos as melhores práticas e criaremos um exemplo abrangente que implementa uma solução robusta.
Melhores Práticas para Permissões de Volume
Aqui estão algumas das principais melhores práticas para gerenciar permissões de volume no Kubernetes:
- Execute contêineres como usuários não-root sempre que possível
- Use o usuário com o menor privilégio necessário para que seu aplicativo funcione
- Aproveite os contextos de segurança em níveis de pod e contêiner
- Padronize os valores de UID/GID em toda a sua organização
- Use contêineres init para cenários de configuração complexos
- Implemente o tratamento adequado de erros para problemas de permissão
Criando uma Solução Abrangente
Vamos criar um deployment que combine o que aprendemos em uma solução robusta:
- Crie um arquivo YAML para nosso deployment:
cd ~/project/k8s-volume-demo
nano best-practice-deployment.yaml
- Copie o seguinte conteúdo para o arquivo:
apiVersion: apps/v1
kind: Deployment
metadata:
name: volume-best-practices
labels:
app: volume-demo
spec:
replicas: 1
selector:
matchLabels:
app: volume-demo
template:
metadata:
labels:
app: volume-demo
spec:
## Pod-level security context
securityContext:
fsGroup: 2000
## Init container for advanced preparation
initContainers:
- name: volume-permissions
image: ubuntu:22.04
command:
- /bin/bash
- -c
- |
## Create directory structure if it doesn't exist
mkdir -p /data/app /data/logs /data/config
## Set appropriate permissions
chmod 755 /data
chmod 775 /data/app /data/logs
chmod 755 /data/config
## Set ownership (belt and suspenders approach)
chown -R 1000:2000 /data
echo "Volume prepared successfully"
volumeMounts:
- name: data-volume
mountPath: /data
securityContext:
runAsUser: 0 ## Run as root for setup
## Application containers
containers:
- name: app-container
image: ubuntu:22.04
command:
- /bin/bash
- -c
- |
echo "Starting application with user $(id)"
while true; do
echo "$(date) - Application running" >> /data/logs/app.log
echo "Writing to app directory" >> /data/app/status.txt
echo "Reading from config"
cat /data/config/test.txt || echo "No config found"
sleep 10
done
volumeMounts:
- name: data-volume
mountPath: /data
securityContext:
runAsUser: 1000 ## Run as non-root user
runAsGroup: 2000 ## Use the same group as fsGroup
allowPrivilegeEscalation: false ## Prevent privilege escalation
volumes:
- name: data-volume
hostPath:
path: /home/labex/project/k8s-volume-demo/data
type: Directory
Salve o arquivo (pressione Ctrl+X, depois Y, depois Enter).
Crie o deployment em seu cluster Kubernetes:
kubectl apply -f best-practice-deployment.yaml
- Aguarde até que o deployment esteja pronto:
kubectl get pods -l app=volume-demo
- Vamos verificar os logs do contêiner init:
## Get the pod name
POD_NAME=$(kubectl get pods -l app=volume-demo -o jsonpath='{.items[0].metadata.name}')
## Check the init container logs
kubectl logs $POD_NAME -c volume-permissions
Você deve ver uma mensagem de que o volume foi preparado com sucesso.
- Agora, verifique os logs do contêiner do aplicativo:
kubectl logs $POD_NAME -c app-container
Você deve ver que o aplicativo está em execução e pode ler e gravar no volume.
- Vamos examinar os arquivos criados pelo nosso deployment:
ls -la ~/project/k8s-volume-demo/data
Você deve ver a estrutura de diretórios criada pelo contêiner init, com as permissões e a propriedade apropriadas.
Compreendendo a Solução Abrangente
Esta solução combina várias melhores práticas:
- Contexto de segurança no nível do pod com
fsGrouppara definir permissões básicas - Contêiner init para configuração complexa da estrutura de diretórios
- Contexto de segurança no nível do contêiner para executar como não-root
- Alinhamento de grupo adequado entre
fsGrouperunAsGroup - Segurança aprimorada com
allowPrivilegeEscalation: false
Essa abordagem garante:
- O aplicativo tem as permissões necessárias para funcionar
- O princípio do menor privilégio é seguido
- A solução é robusta em diferentes ambientes
Limpeza
Vamos limpar todos os recursos criados durante este laboratório:
kubectl delete deployment volume-best-practices
rm -rf ~/project/k8s-volume-demo/data/app ~/project/k8s-volume-demo/data/logs ~/project/k8s-volume-demo/data/config
Você agora aprendeu várias abordagens para resolver problemas de permissão de volume no Kubernetes e implementou uma solução abrangente seguindo as melhores práticas.
Resumo
Neste laboratório, você aprendeu a identificar e resolver problemas de permissão de volume do Kubernetes por meio de várias abordagens:
- Primeiro, você adquiriu uma compreensão de como os volumes do Kubernetes funcionam e criou um exemplo simples de volume EmptyDir.
- Em seguida, você identificou problemas comuns de permissão de volume criando um volume HostPath com permissões de usuário incompatíveis.
- Você implementou uma solução usando o SecurityContext do Kubernetes com
fsGrouppara definir as permissões de volume apropriadas. - Você explorou uma abordagem alternativa usando contêineres init para definir explicitamente as permissões antes que o contêiner principal seja iniciado.
- Por fim, você combinou essas técnicas em uma solução abrangente de melhores práticas que fornece uma maneira robusta de gerenciar permissões de volume no Kubernetes.
Essas habilidades o ajudarão a garantir que seus aplicativos em contêineres possam acessar corretamente o armazenamento persistente, mantendo as melhores práticas de segurança. Ao aplicar a combinação certa de contextos de segurança, contêineres init e técnicas de gerenciamento de permissões, você pode evitar problemas comuns de permissão em seus deployments do Kubernetes.


