루트가 아닌 사용자가 NFS 파일 스토리지 마운트 경로를 소유하는 경우 내 앱이 실패하는 이유는 무엇입니까?
파일 저장을 위한 비루트(non-root) NFS 마운트 문제 해결.
클래식 인프라
배치에 NFS 스토리지를 추가한 후 컨테이너의 배치가 실패합니다. 컨테이너의 로그를 검색할 때 다음 과 같은 오류가 표시될 수 있습니다. 팟(Pod)에 장애가 발생하여 다시 로드 순환에서 벗어나지 못합니다.
write-permission
don't have required permission
can't create directory '/bitnami/mariadb/data': Permission denied
기본적으로, 루트가 아닌 사용자에게는 NFS 지원 스토리지의 볼륨 마운트 경로에 대한 쓰기 권한이 없습니다. Jenkins 및 Nexus3과 같은 일부 일반적인 앱 이미지에서는 Dockerfile에 마운트 경로를 소유하는 루트가 아닌 사용자를 지정합니다.
이 Dockerfile에서 컨테이너를 작성하는 경우 마운트 경로에 루트가 아닌 사용자에 대한 권한이 충분하지 않기 때문에 컨테이너의 작성에 실패합니다. 쓰기 권한을 부여하려면, Dockerfile을 수정하여 마운트 경로의 권한을 변경하기 전에 비루트 사용자를 일시적으로 루트 사용자 그룹에 추가하거나, init 컨테이너를 사용할 수 있습니다.
Helm 차트를 사용하여 이미지를 배포하는 경우, Helm 배포 설정을 수정하여 init 컨테이너를 사용하도록 하십시오.
배포에 [init 컨테이너를](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/){: external} 포함하면, Dockerfile에 지정된 비루트 사용자에게 컨테이너
내부의 볼륨 마운트 경로에 대한 쓰기 권한을 부여할 수 있습니다.
init 컨테이너는 앱 컨테이너가 시작되기 전에 시작됩니다. init 컨테이너는 컨테이너 내부에 볼륨 마운트 경로를 생성하고, 해당 마운트 경로의 소유권을 올바른 (루트가 아닌) 사용자로 변경한 뒤, 종료됩니다. 그런 다음, 마운트 경로에 쓰기를 수행해야 하는 루트가 아닌 사용자가 포함된 앱 컨테이너가 시작됩니다. 루트가 아닌 사용자가 경로를 이미 소유하고 있기 때문에 마운트 경로 쓰기에
성공합니다. init 컨테이너를 사용하지 않으려면, Dockerfile을 수정하여 NFS 파일 저장소에 비루트 사용자 접근 권한을 부여할 수 있습니다.
시작하기 전에:
- Red Hat OpenShift 클러스터에 액세스하십시오.
- 배치가 오퍼레이션을 수행하도록 허용하는 SCC(Security Context Constraint)
chown를 선택하십시오.
init 컨테이너를 사용하여 비루트 사용자에게 볼륨 마운트 경로에 대한 쓰기 권한을 부여하려면:
-
앱의 Dockerfile을 열고 볼륨 마운트 경로에 대한 쓰기 권한을 제공하려는 사용자로부터 사용자 ID(UID) 및 그룹 ID(GID)를 가져오십시오. Jenkins Dockerfile의 예에서 정보는 다음과 같습니다.
- UID:
1000 - GID:
1000
예제 Dockerfile
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:
-
지속적 볼륨 클레임(PVC)을 작성하여 지속적 스토리지를 앱에 추가하십시오. 이 예에서는
ibmc-file-bronze스토리지 클래스를 사용합니다. 사용 가능한 스토리지 클래스를 확인하려면oc 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 -
PVC를 작성하십시오.
oc apply -f mypvc.yaml -
.yaml배포 파일에서init컨테이너를 추가하십시오. 이전에 검색한 UID 및 GID를 포함하십시오.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 line다음 Jenkins 배치 예제를 검토하십시오.
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 -
팟(Pod)을 작성하고 PVC를 팟(Pod)에 마운트하십시오.
oc apply -f my-pod.yamlinit컨테이너에 오류가 발생하고 있나요? Red Hat OpenShift는 제한된 보안 컨텍스트 제한조건을 설정하므로chown: /opt/ibm-ucd/server/ext_lib: Operation not permitted와 같은 오류가 표시될 수 있습니다. 배치의 경우 오퍼레이션을 허용하는 SCC를 사용chown하고 다시 시도하십시오. -
볼륨이 팟(Pod)에 정상적으로 마운트되었는지 확인하십시오. 팟(Pod) 이름 및 컨테이너/마운트 경로를 기록해 두십시오.
oc describe pod <my-pod>출력 예
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 -
이전에 기록해 놓은 팟(Pod) 이름을 사용하여 팟(Pod)에 로그인하십시오.
oc exec -it <my-pod-123456789> /bin/bash -
컨테이너의 마운트 경로에 대한 권한을 확인하십시오. 예를 들어, 마운트 경로는
/var/jenkins_home입니다.ls -ln /var/jenkins_home출력 예
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 war이 출력은 Dockerfile의 GID 및 UID(이 예에서
1000및1000)가 컨테이너 내부의 마운트 경로를 소유함을 표시합니다.