오류 : oci runtime error: exec failed: container_linux.go:235: starting container process caused "exec: \"/bin/bash\": stat /bin/bash: no such file or directory"
상황
kubernetes cluster에 배포 되어있는 kube-apiserver pod에 접속하기 위해
kubectl exec -it [pod name] -n kube-system -- /bin/bash
를 했는데 오류가 발생.
[오류 메세지]
rpc error: code = 2 desc = oci runtime error: exec failed: container_linux.go:235: starting container process caused "exec: \"/bin/bash\": stat /bin/bash: no such file or directory"
command terminated with exit code 126
원인
container에 /bin/bash 가 없어서 발생하는 오류임.
해결책
첫번째 해결법
사용했던 container image : k8s.gcr.io/kube-apiserver:v1.18.5
일반적으로는 /bin/bash가 없다면
-- /bin/bash
-- /bin/sh
-- sh
-- ksh
등 다른 shell로 접근해서 해결 가능.
예)
kubectl exec -it [pod name] -n kube-system -- /bin/sh
실제로 container에 접속한 후 shell 목록을 확인해보면
아래와 같이 bash shell이 없는 것을 확인할 수 있음.
두번째 해결법
사용했던 container image : k8s.gcr.io/kube-apiserver:v1.19.3
kube-apiserver container image version 1.19.3 을 사용했는데 위의 해결법으로 접속이 안됨.
해당 1.19.3 kube-apiserver image의 경우
shell이 포함되어있지 않거나 path 환경변수가 설정되어있지 않은 image로 예상됨.
이렇게 shell 자체가 포함되어있지 않은 image가 꽤 많이 있음
예를 들어 portieris addon의 image, corednb image도 shell이 포함되어 있지 않음.
이러한 image는 exec 명령으로 접근이 불가능함.
보안상의 이유로 shell을 빼놓고 image를 만든것으로 예상됨...
정확한 해결법은 더 리서치를 해봐야겠음.
그렇다면 image설정 수정은 어떻게 하나?
라는 의문이 생길탠데 image관련 설정의 경우
해당 image에 반영되어있는 configMap object를 사용해서 진행함.
두번째 해결법->추가 리서치 내용
[원인 파악]
어떤 shell 로도 접근이 불가능하고
해결법을 찾기위해 shell 을 container로 copy하는 방법도 시도 했지만
정상적으로 접근이 안됨.
역으로 이렇게 접근이 불가능한 container를 제공하는 Dockerfile를 찾아봄.
portieris 에서 작성한 Dockerfile을 확인하니
scratch라는 image를 사용해서 container를 생성하고 있었음.
scratch 는 말그대로 아무것도 없는 텅빈 container임.
주로 go를 CGO_ENABLED 환경변수를 0 으로 설정해서 cgo 가 아닌 Go 컴파일러로 빌드한
바이너리 실행 파일을 scratch container로 올려서 실행함.
이러한 scratch image를 사용해서 container를 생성하면
해당 container에는 사용자가 올린 바이너리 파일들만 존재하기 때문에
어떤 shell도 존재하지 않음. 환경변수 또한 없음.
그렇기 때문에 접속이 불가능함.
용량 또한 매우 낮아짐.
[해결법]
이렇게 scratch container처럼
shell도 없고 tool도 없는 단일실행 파일만 있는 container를 디버깅하기 위해서는
shell 과 기타 필요한 유틸리티를 파일 시스템에 복사 한 다음 실행해야함.
그러기 위해 리눅스 상에서 자주 사용되는 명령어들을 모아놓은 Busybox를 사용해야함.
아래 작업은 디버깅 하고자하는 scratch container가 배포되어있는 host에서 실행함.
1. busybox container image pull
docker pull busybox:latest
2. busybox container 실행
docker run -d docker.io/busybox:latest /bin/sh -c "while true; do sleep 30; done;"
busybox container 또한 실행되고 있는 프로세스가 없기때문에
/bin/sh -c "while true; do sleep 30; done;"
명령으로 무한 루프를 실행해서 container가 정상적으로 run 상태가 되도록 실행함.
3. 실행되고있는 busybox container에서 busybox 툴을 복사함
docker cp [busybox_container_id]:/bin/busybox .
예) docker cp 497ea58951ce:/bin/busybox .
물론 이렇게 busybox container에서 busybox tool을 복사하는 방법 말고도
직접 busybox를 down받는 방법도 있지만
실제 test 해봤을때 down 받았던 busybox로 실패해서 (개인역량 부족일듯...)
위와같이 busybox container에서 busybox tool을 복사함.
4. scratch container로 해당 busybox 툴을 복사함.
docker cp ./busybox [scratch container_id]:/busybox
scratch container (kube-apiserver v1.19.3) 으로 해당 busybox 툴을 전달함.
5. scratch container에 접속하면서 busybox 설정을 진행.
docker exec -it [scratch_container_id] /busybox sh -c '
export PATH="/busybin:$PATH"
/busybox mkdir /busybin
/busybox --install /busybin
sh'
해당 작업을 통해 container에 접속 시도하면
아래와 같이 정상적으로 접속가능
제 글을 복사할 시 출처를 명시해주세요.
글에 오타, 오류가 있다면 댓글로 알려주세요! 바로 수정하겠습니다!
참고
github.com/IBM/portieris/blob/master/Dockerfile
blog.chann.kr/posts/scratch-container-with-go/
stackoverflow.com/questions/54720824/how-to-docker-exec-a-container-built-from-scratch