컨테이너 빌드 시 ls 명령어에서 Operation not permitted 에러 발생 디버깅
문제 내용
집에서 간단한 프론트 앱을 하나 컨테이너로 빌드해서 올려보려고 하다가 황당한 에러를 마주쳤다.
에러 내용은 docker 이미지 빌드 과정에서 디버깅을 위해 넣어 두었던 ls 명령어를 RUN 하는 부분에서 Operation not permitted 라며 권한 에러가 났던 것이었다.
처음에는 이미지 빌드 과정에서 사용되는 사용자 권한이 부족해서 나는 단순 오류인줄 알고 빌드 유저 권한을 root로 부여했는데도 똑같은 에러가 나서 띠용했다.👀
- Dockerfile 예시
FROM nginx:1.21.4
USER root
RUN ls /
- 에러 내용
[root@192 docker]# docker build -t test .
Sending build context to Docker daemon 2.048kB
Step 1/3 : FROM nginx:1.20.2
---> c90c369e7833
Step 2/3 : USER root
---> Using cache
---> 4336d2894eb9
Step 3/3 : RUN ls /
---> Running in 939fabe20261
ls: cannot access '/': Operation not permitted
The command '/bin/sh -c ls /' returned a non-zero code: 2
TL;DR
디버깅 과정이 읽기 귀찮은 사람들을 위해 결론부터 말하면, baseimage로 사용된 debian 컨테이너가 Bullseye 버전으로 업데이트 되면서 발생한 의존성 문제가 원인인 것으로 추정된다. 문제 해결을 위해서는 Docker, runc, libseccomp 등을 최신버전으로 업데이트 해주어 문제를 해결하였다.
디버깅
이상하게도 nginx 컨테이너 최신 버전에서만 문제가 발생하였다. 1.21.4 버전에서는 문제가 발생했는데, 1.11.6 버전에서는 위와 같은 문제가 발생하지 않았던 것! 그리고 다른 컨테이너들(node, redis) 등을 대상으로 테스트를 해보자 마찬가지로 최신 버전의 컨테이너들에서는 문제가 발생하는데 과거 버전들은 에러가 나지 않는것이었다.
합리적인 의심으로 내가 가진 도커 버전이 옛날 버전이어서 그 사이에 오버레이FS 쪽에
뭔가 변화가 있었나..?! 싶었다. 만약 그렇다면 정확하게 무슨 버전에서 일어난 패치로 인해 이렇게 된건지 궁금해져서 VM 여러대에 각 도커 version들을 설치해서 같은 에러가 발생할때까지 삽질을 이어 나갔다. 에러가 발생헀던 서버의 도커 버전은 18.09.2 였고, 최대 테스트 버전은 글 발행일 기준으로 20.10.12-3 이었다.
그.런.데…! 하도 에러가 나는 버전이 좁혀 지지 않아서 새로운 가상환경에서 에러가 나는 도커 버전과 동일한 버전을 설치하고 테스트 했는데, 에러가 나질 않는 것이다..! 멘붕이었다. 도커 버전에 따른 영향이 아니었단 말인가..? 그렇다면 내 시스템에서는 무슨 원인 때문에 에러가 나는 거지..?
많은 생각으로 머리가 복잡해지기 시작해서 다시 처음으로 돌아가서 다른 방향으로 디버깅을 시작했다.
이번에는 nginx 이미지의 에러가 나는 버전과 에러가 나지 않는 버전을 특정해 보기로 했다. 테스트 결과 아래와 같은 결과가 나왔다.
에러가 나는 이미지 version | 에러가 나지 않는 이미지 version |
nginx:1.20.2 이상 | nginx:1.20.1 이하 |
해당 버전 사이의 Nginx 도커 프로젝트의 커밋 로그를 뒤지다 보니 이런 변경 사항을 찾을 수 있었다.
1.20.1 → 1.20.2 수정 배포 과정에서 baseimage가 debian:buster-slim → debian:bullseye-slim 으로 변경 된 것을 찾은 것이다. 실제로 테스트 해보니, buster-slim을 베이스로 하여 빌드 과정에 ls 명령을 삽입하면 에러가 나지 않고, bullseye-slim을 베이스로 할 때에는 에러가 나는 것을 확인하였다.
혹시나 하여 이전에 테스트 과정에서 사용했던 node, redis 등의 이미지들도 base이미지 부분에서 비슷한 업데이트가 있었던 것을 확인했다. 관련 키워드로 검색해보니 드디어 나와 비슷한 상황을 경험하고 결론을 내린 사람을 찾을 수 있었다.
그런데 그 사람이 제시한 해결책은 다른 아닌 docker 엔진의 버전 업데이트였다. ????
테스트 서버에서 도커 버전 문제가 아니라고 결론을 내리고 돌아온 상황에서 다시 도달한 결론이 도커 버전 업데이트라니… 그래도 이미 너무 지친 상태라 더 이상의 테스트는 못하겠어서 그냥 속는셈 치고 개발서버의 도커 버전을 업데이트 하기로 했다.
결과는 절망적이게도 성공 이었다. 도커 버전을 업데이트 하자 마법같이 에러가 사라졌다.
에러는 해결되었지만, 결국 원인을 찾지 못하였다. 차라리 그냥 버전 문제로 치부하고 처음부터 업그레이드를 했으면 이렇게까지 찝찝하진 않았을텐데…
여튼 결론은 이렇다.
“일부 환경에서 Docker image 빌드 과정에서 이유없는 권한 에러가 발생할 수 있다. 특정 버전의 문제로 국한 지을 수는 없지만 baseimage를 debian:bullseye-slim 를 사용할 때에만 발생하는 문제라면 도커 버전 업데이트로 문제를 해결할 수 있다.“ ;;
더 문제의 원인을 찾아보려 했으나 이미 비정상 동작하는 환경을 재현할 수 없게 된 시점이라 원인을 밝힐 수 없게 되었다. 단순히 추측만 해보자면 도커의 특정 버전이 아닌 관련하여 의존성을 가지고 있는 여러 라이브러리들에 의한 영향도 이지 않을까 이다.(부록의 내용을 보면 버전 업 이후에 containerd의 버전도 함께 업그레이드 되고 다른 의존성 패키지들이 몇개 추가된 것을 볼 수 있다.)
이상이다.
부록
- 서버 환경
[root@192 docker]# cat /etc/*release*
CentOS Linux release 7.6.1810 (Core)
Derived from Red Hat Enterprise Linux 7.6 (Source)
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"
CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"
CentOS Linux release 7.6.1810 (Core)
CentOS Linux release 7.6.1810 (Core)
cpe:/o:centos:centos:7
- 버전업 전
[root@192 docker]# rpm -qa | egrep 'docker|runc|libseccom|container'
libseccomp-2.3.1-3.el7.x86_64
container-selinux-2.74-1.el7.noarch
containerd.io-1.2.2-3.3.el7.x86_64
docker-ce-18.09.2-3.el7.x86_64
docker-ce-cli-18.09.2-3.el7.x86_64
- 버전업 후
[root@192 docker]# rpm -qa | egrep 'docker|runc|libseccom|container'
libseccomp-2.3.1-3.el7.x86_64
container-selinux-2.74-1.el7.noarch
docker-ce-rootless-extras-20.10.12-3.el7.x86_64
docker-scan-plugin-0.12.0-3.el7.x86_64
containerd.io-1.4.12-3.1.el7.x86_64
docker-ce-20.10.12-3.el7.x86_64
docker-ce-cli-20.10.12-3.el7.x86_64