Por que meu aplicativo falha quando um usuário não raiz é proprietário do caminho de montagem do armazenamento de arquivo NFS?
Resolva problemas de montagem de partições “ NFS ” não-root para armazenamento de arquivos.
Infraestrutura clássica
Depois de incluir armazenamento NFS em sua implementação, a implementação de seu contêiner falha. Ao recuperar os logs para seu contêiner, é possível ver erros como os seguintes. O pod falha e fica preso em um ciclo de recarregamento.
write-permission
don't have required permission
can't create directory '/bitnami/mariadb/data': Permission denied
Por padrão, os usuários não raiz não têm permissão de gravação no caminho de montagem do volume para armazenamento suportado por NFS. Algumas imagens comuns do app, como Jenkins e Nexus3, especificam um usuário não raiz que possui o caminho de montagem no Dockerfile.
Quando você cria um contêiner por meio desse Dockerfile, a criação do contêiner falha devido a permissões insuficientes do usuário não raiz no caminho de montagem. Para conceder permissão de gravação, você pode modificar o Dockerfile para adicionar
temporariamente o usuário não root ao grupo do usuário root antes que ele altere as permissões do caminho de montagem, ou usar um contêiner com o comando init .
Se você usar um gráfico do Helm para implantar a imagem, edite a implantação do Helm para usar um contêiner do init.
Ao incluir um contêiner init em sua implantação, você pode conceder a um usuário que não seja o root
— especificado no seu Dockerfile — permissões de gravação para o caminho de montagem do volume dentro do contêiner.
O contêiner do init é iniciado antes do contêiner do seu aplicativo. O contêiner init cria o caminho de montagem do volume dentro do contêiner, altera a propriedade do caminho de montagem
para o usuário correto (que não seja o root) e é encerrado. Em seguida, seu contêiner de app é iniciado com o usuário não raiz que deve gravar no caminho de montagem. Como o caminho já pertence ao usuário não raiz, a gravação no caminho de montagem
é bem-sucedida. Se você não quiser usar um contêiner do tipo “ init ”, pode modificar o Dockerfile para adicionar acesso de um usuário que não seja o root ao armazenamento de arquivos d NFS.
Antes de iniciar:
- Acesse o seu Red Hat OpenShift cluster.
- Selecione uma restrição de contexto de segurança (SCC) que permite que sua implementação execute operações
chown.
Para usar um contêiner do init para conceder permissões de gravação a um usuário não root no caminho de montagem do volume:
-
Abra o Dockerfile para seu app e obtenha o ID do usuário (UID) e ID do grupo (GID) do usuário que você deseja fornecer permissão de gravação no caminho de montagem do volume. No exemplo de um Dockerfile Jenkins, as informações são:
- UID:
1000 - GID:
1000
Dockerfile de exemplo
FROM openjdk:8-jdk RUN apt-get update && apt-get install -y git curl && rm -rf /var/lib/apt/lists/* ARG user=jenkins ARG group=jenkins ARG uid=1000 ARG gid=1000 ARG http_port=8080 ARG agent_port=50000 ENV JENKINS_HOME /var/jenkins_home ENV JENKINS_SLAVE_AGENT_PORT ${agent_port} ... - UID:
-
Inclua armazenamento persistente para seu app criando um persistent volume claim (PVC). Este exemplo usa a classe de armazenamento
ibmc-file-bronze. Para consultar as classes de armazenamento disponíveis, execute o comandooc get sc``.apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mypvc annotations: volume.beta.kubernetes.io/storage-class: "ibmc-file-bronze" spec: accessModes: - ReadWriteMany resources: requests: storage: 20Gi -
Crie o PVC.
oc apply -f mypvc.yaml -
No arquivo de implantação
.yaml, adicione o contêinerinit. Inclua o UID e o GID que você recuperou anteriormente.initContainers: - name: initcontainer # Or replace the name image: alpine:latest command: ["/bin/sh", "-c"] args: - chown <UID>:<GID> /mount; # Replace UID and GID with values from the Dockerfile volumeMounts: - name: volume # Or you can replace with any name mountPath: /mount # Must match the mount path in the args lineRevise o exemplo de implementação do Jenkins a seguir.
apiVersion: apps/v1 kind: Deployment metadata: name: my-pod spec: replicas: 1 selector: matchLabels: app: jenkins template: metadata: labels: app: jenkins spec: containers: - name: jenkins image: jenkins volumeMounts: - mountPath: /var/jenkins_home name: volume volumes: - name: volume persistentVolumeClaim: claimName: mypvc initContainers: - name: permissionsfix image: alpine:latest command: ["/bin/sh", "-c"] args: - chown 1000:1000 /mount; volumeMounts: - name: volume mountPath: /mount -
Crie o pod e monte o PVC em seu pod.
oc apply -f my-pod.yamlO contêiner “
init” está apresentando falha? Como o Red Hat OpenShift configura restrições de contexto de segurança restritas, é possível ver um erro comochown: /opt/ibm-ucd/server/ext_lib: Operation not permitted. Para sua implementação, use um SCC que permita operaçõeschowne tente novamente. -
Verifique se o volume foi montado com êxito no pod. Anote o nome do pod e o caminho Contêineres/Montagens.
oc describe pod <my-pod>Saída de exemplo
Name: mypod-123456789 Namespace: default ... Init Containers: ... Mounts: /mount from volume (rw) /var/run/secrets/kubernetes.io/serviceaccount from default-token-cp9f0 (ro) ... Containers: jenkins: Container ID: Image: jenkins Image ID: Port: <none> State: Waiting Reason: PodInitializing Ready: False Restart Count: 0 Environment: <none> Mounts: /var/jenkins_home from volume (rw) /var/run/secrets/kubernetes.io/serviceaccount from default-token-cp9f0 (ro) ... Volumes: myvol: Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace) ClaimName: mypvc ReadOnly: false -
Efetue login no pod usando o nome do pod que você anotou anteriormente.
oc exec -it <my-pod-123456789> /bin/bash -
Verifique as permissões do caminho de montagem do seu contêiner. No exemplo, o caminho de montagem é
/var/jenkins_home.ls -ln /var/jenkins_homeSaída de exemplo
jenkins@mypod-123456789:/$ ls -ln /var/jenkins_home total 12 -rw-r--r-- 1 1000 1000 102 Mar 9 19:58 copy_reference_file.log drwxr-xr-x 2 1000 1000 4096 Mar 9 19:58 init.groovy.d drwxr-xr-x 9 1000 1000 4096 Mar 9 20:16 warEssa saída mostra que o GID e o UID de seu Dockerfile (neste exemplo,
1000e1000) possuem o caminho de montagem dentro do contêiner.