테마 전환

Docker 컨테이너 디버깅 가이드: exec 명령으로 컨테이너에 들어가 문제를 해결하는 올바른 방법

Easton editorial illustration: container packing dock

테스트 환경의 API가 갑자기 502를 반환했습니다. docker ps를 실행하니 컨테이너 상태는 분명히 정상 실행 중이라는 뜻의 “Up 2 hours”로 표시됩니다. 로그를 확인해도 차갑게 “Connection refused”라는 한 줄만 남아 있습니다.

이럴 때가 가장 답답합니다. 컨테이너가 실행 중이라는 사실은 알지만 그 안에서 대체 무슨 일이 벌어지는지는 알 수 없습니다. 설정 파일이 제대로 작성됐을까요? 프로세스가 정말 시작됐을까요? 포트는 리스닝 중일까요? 이런 문제를 확인하려면 블랙박스를 열어 안에 무엇이 들어 있는지 살펴보듯 컨테이너 내부로 “들어가야” 합니다.

솔직히 말해 저도 Docker를 처음 접했을 때는 컨테이너에 어떻게 “들어가는지” 몰랐습니다. 인터넷을 찾아보니 누구는 docker exec를 쓰라고 하고, 누구는 docker attach를 쓰라고 했으며, 어떤 사람은 컨테이너를 재시작하라고 바로 권했습니다. 여러 시행착오를 겪은 뒤에야 컨테이너 디버깅에도 올바른 방법이 있다는 사실을 알게 됐습니다.

이 글에서는 docker exec를 사용해 컨테이너에 올바르게 들어가 문제를 조사하는 방법을 설명합니다. exec와 attach의 본질적인 차이, 컨테이너 안에 필요한 도구가 없을 때의 대처법, 실용적인 디버깅 요령까지 다룹니다. 이 내용을 익히면 다음에 컨테이너 문제가 생겼을 때 무조건 재시작하는 방법에만 의존하지 않아도 됩니다.

docker exec 기초 - 컨테이너에 올바르게 들어가는 방법

가장 간단하게 들어가는 방법

실행 중인 컨테이너에 들어갈 때 가장 흔히 사용하는 명령은 다음과 같습니다.

docker exec -it my-nginx bash

여기에는 세 가지 핵심 요소가 있습니다.

  • -it: 두 옵션을 합친 표현입니다. -i는 표준 입력을 열린 상태로 유지하고, -t는 터미널을 할당합니다. 쉽게 말해 컨테이너와 “대화”할 수 있게 해 줍니다.
  • my-nginx: 컨테이너 이름입니다. 컨테이너 ID를 사용할 수도 있습니다(예: docker exec -it abc123def456 bash).
  • bash: 컨테이너 안에서 실행할 명령이며, 여기서는 bash 터미널을 시작합니다.

이 명령을 실행한 뒤 명령줄 프롬프트가 root@abc123def456:/#와 비슷한 형태로 바뀌면 컨테이너에 “들어간” 것입니다. 이제 일반 Linux 서버를 다루듯 여러 명령을 실행할 수 있습니다.

bash가 없으면 어떻게 하나요?

때로는 다음과 같은 오류를 만날 수 있습니다.

$ docker exec -it my-alpine bash
OCI runtime exec failed: exec failed: container_linux.go:380:
starting container process caused: exec: "bash": executable file not found

당황할 필요는 없습니다. 보통 컨테이너가 Alpine Linux처럼 아주 가벼운 시스템을 사용해서 기본적으로 bash 없이 sh만 제공하기 때문입니다. 명령만 바꾸면 됩니다.

docker exec -it my-alpine sh

제 경험으로는 먼저 bash를 시도하고, 안 되면 sh를 사용하면 컨테이너의 90% 정도는 해결할 수 있습니다.

컨테이너 ID를 활용하면 더 유연합니다

컨테이너 이름을 확인하기 귀찮을 때는 ID의 앞부분 몇 자리만 바로 사용해도 됩니다.

# 먼저 컨테이너 ID 확인
$ docker ps
CONTAINER ID   IMAGE    COMMAND                  CREATED
abc123def456   nginx    "/docker-entrypoint.…"   2 hours ago

# ID 접두사로 진입(3~4자리면 충분)
$ docker exec -it abc1 bash

중복되지 않기만 하면 Docker가 ID 접두사를 자동으로 찾아줍니다. 컨테이너가 많을 때 특히 유용한 방법입니다.

컨테이너에서 올바르게 나가는 방법

컨테이너에 들어간 뒤 나오려면 exit를 입력하거나 Ctrl+D를 누르면 됩니다.

root@abc123def456:/# exit
exit
$

중요한 점은 exec로 들어간 컨테이너는 사용자가 나가도 멈추지 않는다는 것입니다. 왜 중요한지는 이어서 설명하겠습니다.

exec와 attach - 이제 혼동하지 마세요

본질적인 차이

많은 튜토리얼이 docker execdocker attach를 함께 언급하지만, 둘의 본질적인 차이를 명확히 설명하는 경우는 드뭅니다. 저 역시 예전에 attach를 잘못 사용했다가 컨테이너가 갑자기 멈춘 적이 있습니다.

간단히 말하면 다음과 같습니다.

  • docker exec: 컨테이너 안에서 새 프로세스를 시작합니다. 새 창을 하나 여는 것과 같습니다.
  • docker attach: 컨테이너의 주 프로세스(PID 1)에 연결합니다. 이미 켜진 화면을 미러링하는 것과 같습니다.

조금 추상적으로 들리나요? 예를 들어 보겠습니다.

docker attach my-nginx로 Nginx 컨테이너에 연결한 다음 Ctrl+C를 누르거나 exit를 입력해 종료한다고 가정해 봅시다. 그러면 컨테이너의 주 프로세스인 Nginx가 종료 신호를 받고 컨테이너 전체가 멈춥니다. 프로덕션 환경에서 이렇게 했다가는 크게 질책받기 십상입니다.

하지만 docker exec -it my-nginx bash를 사용하면 독립적인 bash 프로세스가 시작됩니다. 이 bash를 종료해도 Nginx 주 프로세스에는 영향을 주지 않으므로 컨테이너는 계속 정상 실행됩니다.

exec와 attach는 각각 언제 사용하나요?

제 조언은 간단합니다. 99%의 상황에서는 exec를 사용하면 됩니다.

attach가 유용한 유일한 경우는 컨테이너의 주 프로세스와 직접 상호작용해야 할 때입니다. 예를 들면 다음과 같습니다.

  • 컨테이너에서 대화형 프로그램(예: Python REPL)을 실행 중일 때
  • 주 프로세스의 실시간 출력을 확인해야 할 때
  • 여러 터미널에서 같은 내용을 “동시에” 확인해야 할 때(화면 공유와 유사)

하지만 솔직히 이런 경우는 매우 드뭅니다. 대부분은 컨테이너에 들어가 파일을 확인하고 설정을 변경하거나 명령을 실행하려는 것이므로 exec가 안전하고 편리합니다.

비교표로 확실하게 구분하기

특성docker execdocker attach
새 프로세스 시작✓ 예✗ 아니요
exit 후 컨테이너 중지✗ 아니요✓ 예(위험!)
임의의 명령 실행 가능✓ 예✗ 아니요
여러 터미널 독립 사용✓ 예✗ 아니요(동일한 tty 공유)
디버깅 권장도⭐⭐⭐⭐⭐

이제 제가 왜 계속 exec 사용을 강조했는지 이해했을 것입니다. attach는 컨테이너 출력을 확인하려고 설계된 기능이지 일상적인 디버깅을 위한 기능이 아닙니다.

컨테이너 안에 도구가 없을 때의 대처법

컨테이너에는 왜 아무 명령도 없을까요?

어렵게 컨테이너에 들어가 vim으로 설정 파일을 수정하려는데 다음과 같은 결과가 나옵니다.

root@abc123:/# vim /etc/nginx/nginx.conf
bash: vim: command not found

curl로 API를 테스트해 보려고 해도 마찬가지입니다.

root@abc123:/# curl localhost:8080
bash: curl: command not found

심지어 ping조차 없습니다. 처음 이런 상황을 마주했을 때는 아무것도 없는데 어떻게 디버깅하라는 건지 정말 막막했습니다.

사실 이는 Docker 이미지의 설계 철학 때문입니다. 꼭 필요한 것만 설치하고, 없어도 되는 것은 설치하지 않습니다. 완전한 Ubuntu 이미지는 수백 MB일 수 있지만 Alpine 이미지는 5MB에 불과합니다. 어떻게 가능할까요? vim, curl, ping처럼 당연히 있을 것이라 생각하는 도구를 포함해 모든 “불필요한” 도구를 제거했기 때문입니다.

긴급할 때 도구 임시 설치하기

이런 상황에서는 필요한 도구를 임시로 설치할 수 있습니다. 컨테이너의 시스템 유형에 맞는 패키지 관리자를 사용하세요.

Debian/Ubuntu 시스템(apt/apt-get):

# 먼저 패키지 목록 업데이트
apt-get update

# 자주 쓰는 도구 설치
apt-get install -y vim curl wget net-tools

# 네트워크 진단 도구가 필요할 때
apt-get install -y iputils-ping dnsutils

CentOS/RedHat 시스템(yum):

yum install -y vim curl wget

Alpine 시스템(apk):

apk update
apk add vim curl bash

컨테이너가 어떤 시스템을 사용하는지 확인하는 방법

컨테이너의 시스템을 모른다면 두 가지 간단한 방법으로 확인할 수 있습니다.

# 방법 1: 시스템 배포판 파일 확인
cat /etc/os-release

# 방법 2: 패키지 관리자 명령이 있는지 확인
which apt-get   # 있으면 Debian/Ubuntu
which yum      # 있으면 CentOS/RedHat
which apk      # 있으면 Alpine

저는 보통 apt-get update를 바로 시도하고, 오류가 나면 다른 명령으로 바꿉니다. 이렇게 해도 컨테이너가 망가지지는 않습니다.

이렇게 해도 안전할까요?

도구를 임시 설치할 때는 몇 가지 주의해야 할 점이 있습니다.

개발 환경: 자유롭게 설치해도 괜찮습니다. 테스트 컨테이너를 재시작하면 초기화되고 설치한 도구도 사라집니다.

프로덕션 환경: 긴급하게 문제를 조사할 때만 사용하세요. 문제를 해결한 뒤에는 필요한 도구를 Dockerfile에 추가하고 이미지를 다시 빌드해야 합니다.

그 이유는 두 가지입니다.

  1. 보안: 임시로 설치한 패키지에 보안 취약점이 있을 수 있습니다.
  2. 재현성: 컨테이너를 재시작하면 설치한 도구가 사라지므로 다음에 다시 설치해야 합니다.

장기적인 해결책: Dockerfile에 미리 설치하기

특정 디버깅 도구가 자주 필요하다면 이미지를 빌드할 때 설치하는 편이 좋습니다.

FROM nginx:latest

# 자주 쓰는 디버깅 도구 설치
RUN apt-get update && apt-get install -y \
    vim \
    curl \
    wget \
    net-tools \
    iputils-ping \
 && rm -rf /var/lib/apt/lists/*  # 캐시를 정리해 이미지 크기 축소

# 기타 설정...

마지막의 rm -rf /var/lib/apt/lists/*는 이미지 크기를 크게 줄일 수 있는 좋은 습관입니다.

실용적인 작은 팁

설정 파일 내용을 빠르게 확인하기만 한다면 vim이 필요하지 않습니다. 거의 모든 컨테이너에 있는 cat이나 less를 사용하면 됩니다.

# 전체 파일 확인
cat /etc/nginx/nginx.conf

# 페이지 단위로 확인(긴 파일에 적합)
less /etc/nginx/nginx.conf  # q를 눌러 종료

# 앞부분 몇 줄만 확인
head -n 20 /etc/nginx/nginx.conf

파일을 수정해야 하는데 vim이 없다면 sed로 바로 치환할 수도 있습니다. vim만큼 직관적이지는 않지만 긴급할 때 유용합니다.

# listen 80을 listen 8080으로 변경
sed -i 's/listen 80/listen 8080/g' /etc/nginx/nginx.conf

특정 사용자 권한으로 컨테이너에 들어가기

사용자를 지정해야 하는 이유

컨테이너에 들어간 뒤 다음과 같은 상황을 만날 때가 있습니다.

root@abc123:/app# cat /var/log/app.log
cat: /var/log/app.log: Permission denied

또는 파일 권한을 변경하려고 해도 오류가 납니다.

root@abc123:/app# chmod 644 config.yaml
chmod: changing permissions of 'config.yaml': Operation not permitted

프롬프트에는 분명 root라고 표시되는데 왜 권한이 없을까요? 보통 컨테이너가 root가 아닌 사용자로 실행되도록 설정됐고(프로덕션 환경에서 권장하는 좋은 습관입니다), exec로 들어갈 때 기본 사용자가 컨테이너의 사용자 설정을 그대로 물려받았기 때문입니다.

root 권한으로 들어가기

이때는 root 권한으로 들어가도록 명시해야 합니다.

docker exec -it --user root my-app bash

또는 다음과 같이 줄여 쓸 수 있습니다.

docker exec -it -u root my-app bash

이제 실제 root 권한을 갖게 되어 모든 파일을 확인하고 모든 설정을 변경할 수 있습니다.

특정 UID로 들어가기

컨테이너 안의 애플리케이션 사용자가 UID 1000인 경우처럼, 특정 사용자 ID로 들어가야 할 때도 있습니다.

# UID 1000으로 진입
docker exec -it --user 1000 my-app bash

# 사용자 이름도 지정 가능(컨테이너 안에 해당 사용자가 있어야 함)
docker exec -it --user appuser my-app bash

# 사용자와 그룹 지정(형식: 사용자:그룹)
docker exec -it --user 1000:1000 my-app bash

이는 권한 문제를 디버깅할 때 특히 유용합니다. 예를 들어 애플리케이션이 특정 디렉터리에 쓸 수 없는 것 같다면 애플리케이션 사용자 권한으로 들어가 직접 확인해 볼 수 있습니다.

# 애플리케이션 사용자 권한으로 진입
docker exec -it --user appuser my-app bash

# 데이터 디렉터리에 파일을 만들 수 있는지 확인
appuser@abc123:/app$ touch /data/test.txt
touch: cannot touch '/data/test.txt': Permission denied

# 문제가 확인됨. 실제로 권한에 문제가 있음

root 권한은 언제 필요한가요?

제 경험상 다음과 같은 경우에는 보통 root 권한이 필요합니다.

  1. 시스템 설정 변경: /etc/ 아래의 각종 설정 파일
  2. 소프트웨어 패키지 설치: apt-get, yum 등에는 root 필요
  3. 시스템 로그 확인: 일반 사용자는 /var/log/ 아래의 여러 로그 파일을 읽을 수 없음
  4. 파일 권한 조정: chmod, chown 등의 작업
  5. 네트워크 문제 디버깅: tcpdump, netstat 등의 네트워크 도구에는 보통 root 필요

하지만 root를 사용하지 않아도 된다면 사용하지 마세요. 특히 프로덕션 환경에서 root로 무언가를 변경했다면 작업 후 원래 상태로 되돌려 보안 위험을 남기지 않아야 합니다.

보안 관련 주의 사항

root로 컨테이너에 들어갈 수는 있지만 몇 가지 주의할 점이 있습니다.

테스트 환경: 자유롭게 사용해도 큰 문제는 없습니다. 컨테이너를 재시작하면 초기화됩니다.

프로덕션 환경:

  • 들어가서 내용 확인 → OK
  • 긴급하게 설정 임시 변경 → 어쩔 수 있다면 OK, 단 무엇을 변경했는지 기록해야 함
  • 컨테이너 안에서 직접 코드 컴파일 또는 소프트웨어 설치 → 허용하지 않음! 이런 변경은 Dockerfile에 작성해야 함

왜 그럴까요? 컨테이너의 설계 철학은 “불변 인프라”이기 때문입니다. 실행 중인 컨테이너에서 바꾼 내용은 컨테이너를 재시작하는 순간 모두 사라집니다. 실제 변경 사항은 재현할 수 있도록 Dockerfile에 반영해야 합니다.

또 다른 보안 위험도 있습니다. 일부 설정에서는 컨테이너의 root와 호스트의 root가 동일한 사용자(UID 0 공유)일 수 있습니다. 네임스페이스로 격리되기는 하지만 설정이 잘못되면 컨테이너의 root가 호스트에 영향을 줄 수 있습니다. 프로덕션 환경에서 root가 아닌 사용자로 컨테이너를 실행하라고 권장하는 이유이기도 합니다.

실전 팁과 자주 마주치는 상황

대화형 셸에 들어가지 않고 단일 명령 실행하기

컨테이너 안에 계속 머물 필요 없이 명령 하나만 빠르게 실행하고 결과를 확인하고 싶을 때가 많습니다. 이때는 -it 옵션을 추가하지 않아도 됩니다.

# 디렉터리 내용 확인
docker exec my-nginx ls -la /etc/nginx/

# 설정 파일 확인
docker exec my-nginx cat /etc/nginx/nginx.conf

# 프로세스 확인
docker exec my-nginx ps aux

# 포트 리스닝 상태 확인
docker exec my-nginx netstat -tlnp

# 네트워크 연결 테스트
docker exec my-nginx curl -I localhost:80

이 방식은 스크립트를 작성하거나 특정 값을 빠르게 확인할 때 특히 유용합니다. 예를 들어 저는 애플리케이션이 정상적으로 응답하는지 확인할 때 다음 명령을 자주 사용합니다.

# 상태 확인 스크립트
if docker exec my-app curl -f http://localhost:8080/health; then
  echo "App is healthy"
else
  echo "App is down!"
fi

컨테이너 디버깅 표준 절차

컨테이너 문제가 생기면 저는 보통 다음 순서로 조사합니다.

1. 먼저 컨테이너 상태 확인

docker ps -a  # 컨테이너 실행 여부 확인

2. 로그에서 단서 찾기

docker logs my-app --tail 100  # 최근 로그 100줄 확인
docker logs my-app -f          # 실시간 로그 추적(tail -f와 유사)

3. 컨테이너 프로세스 확인

docker exec my-app ps aux

실행돼야 할 프로세스가 실제로 시작됐는지 확인합니다. 예를 들어 Nginx 컨테이너라면 nginx master와 worker 프로세스가 보여야 합니다.

4. 포트 리스닝 확인

docker exec my-app netstat -tlnp
# 또는(netstat가 없다면)
docker exec my-app ss -tlnp

애플리케이션이 올바른 포트를 리스닝 중인지 확인합니다.

5. 서비스 가용성 테스트

# 컨테이너 내부에서 테스트
docker exec my-app curl localhost:8080

# curl이 없으면 telnet으로 포트 연결 확인
docker exec my-app telnet localhost 8080

6. 설정 파일 확인

docker exec my-app cat /etc/nginx/nginx.conf
docker exec my-app cat /app/config.yaml

설정이 예상과 일치하는지 확인합니다.

7. 디스크 공간 확인

docker exec my-app df -h

컨테이너의 디스크가 가득 차서 애플리케이션이 파일을 쓰지 못하는 경우도 있습니다.

유용한 디버깅 명령 조합

환경 변수 확인:

docker exec my-app env | grep DATABASE

데이터베이스 연결 설정이 올바른지 확인합니다.

특정 파일 찾기:

docker exec my-app find /app -name "*.log"

파일 권한 확인:

docker exec my-app ls -la /app/

권한 문제를 조사할 때 유용합니다.

컨테이너 리소스 실시간 모니터링:

docker stats my-app

이 명령에는 exec를 사용하지 않고 호스트에서 바로 실행합니다. CPU, 메모리, 네트워크, IO 사용량을 실시간으로 확인할 수 있습니다.

여러 컨테이너 일괄 작업하기

확인해야 할 컨테이너가 여러 개라면 셸 스크립트와 함께 사용할 수 있습니다.

# 실행 중인 모든 컨테이너의 메모리 사용량 확인
for container in $(docker ps -q); do
  echo "Container: $container"
  docker exec $container free -h
  echo "---"
done

네트워크 문제 디버깅하기

컨테이너 간 연결 확인:

# 컨테이너 A에서 컨테이너 B로 ping
docker exec containerA ping containerB

# 컨테이너의 외부 네트워크 접근 테스트
docker exec my-app ping -c 3 google.com

# DNS 조회 확인
docker exec my-app nslookup google.com

컨테이너 IP 확인:

docker inspect my-app | grep IPAddress
# 또는 컨테이너 안에서 확인
docker exec my-app ip addr show

컨테이너가 계속 재시작되면 어떻게 하나요?

컨테이너가 시작하자마자 종료돼 exec로 들어갈 시간조차 없을 때가 있습니다. 이럴 때는 다음 방법을 사용할 수 있습니다.

방법 1: 시작 명령 재정의

# 컨테이너 시작 후 원래 CMD를 실행하지 않고 계속 실행 상태로 유지
docker run -it --name debug-app my-app-image sh

이렇게 하면 컨테이너가 원래 시작 스크립트를 실행하지 않고 셸에서 대기하므로 문제를 확인할 시간이 생깁니다.

방법 2: 종료된 컨테이너 확인

# 종료된 컨테이너 시작
docker start my-app

# 즉시 로그 확인
docker logs my-app

# 아직 컨테이너가 종료되지 않았다면 빠르게 진입
docker exec -it my-app bash

이 절의 팁은 모두 실무에서 하나씩 익힌 것입니다. Docker 컨테이너 디버깅은 처음에는 막막할 수 있지만, 이런 명령에 익숙해지면 훨씬 빠르게 문제를 해결할 수 있습니다.

결론

지금까지 많은 내용을 살펴봤지만 Docker 컨테이너 디버깅의 핵심은 다음과 같습니다.

docker exec로 컨테이너에 들어가는 방법이 가장 안전하며, 나가도 컨테이너 실행에는 영향을 주지 않습니다. docker exec -it container-name bash라는 범용 명령을 기억하고, bash가 안 되면 sh를 시도하세요.

exec와 attach를 혼동하지 마세요. attach는 주 프로세스에 연결하므로 exit하면 컨테이너가 멈춥니다. 무엇을 하는지 정확히 아는 경우가 아니라면 exec를 사용하세요.

도구가 없어도 당황하지 마세요. apt-get, yum, apk로 임시 설치할 수 있습니다. 다만 이는 긴급 조치일 뿐이며, 장기적으로는 도구를 Dockerfile에 추가해야 합니다.

root 권한이 필요하면 --user root 옵션을 추가하세요. 하지만 프로덕션 환경에서는 신중하게 사용하고 변경 사항을 기록한 뒤 가능한 한 빨리 이미지에 반영하는 것이 좋습니다.

체계적인 순서로 디버깅하세요. 먼저 로그를 보고, 프로세스를 확인한 다음 설정을 점검하고 마지막으로 네트워크를 테스트합니다. 이 순서대로 조사하면 대부분의 문제를 해결할 수 있습니다.

다음에 컨테이너 문제가 생기면 성급하게 재시작하지 마세요. 내부를 직접 살펴보면 설정 오류, 잘못된 권한, 포트 충돌처럼 간단한 원인인 경우가 많습니다. exec 명령을 제대로 활용하면 컨테이너 디버깅은 생각보다 어렵지 않습니다.

마지막으로 문제가 생겼을 때 바로 활용할 수 있는 디버깅 체크리스트를 정리했습니다.

컨테이너 디버깅 체크리스트:

  • 컨테이너가 실행 중인가요? (docker ps)
  • 로그에 오류가 있나요? (docker logs)
  • 모든 프로세스가 시작됐나요? (docker exec ps aux)
  • 포트 리스닝이 정상인가요? (docker exec netstat -tlnp)
  • 설정 파일이 올바른가요? (docker exec cat config)
  • 디스크 공간이 충분한가요? (docker exec df -h)
  • 네트워크가 연결되나요? (docker exec curl/ping)

이 항목을 모두 확인하면 대부분 문제의 원인을 찾을 수 있습니다.

Docker 컨테이너 디버깅 전체 절차

exec 명령으로 컨테이너에 들어가 문제를 조사하는 전체 과정으로, 명령 설명과 도구 설치, 권한 관리, 체계적인 디버깅 방법을 다룹니다.

⏱️ Estimated time: 30 min

  1. 1

    Step 1: 컨테이너 진입: exec와 attach의 차이 이해하기

    exec와 attach의 본질적인 차이: exec는 새 프로세스를 생성해 컨테이너에 들어가며(권장, 주 프로세스에 영향을 주지 않음), attach는 주 프로세스의 stdin/stdout에 연결합니다(권장하지 않음, 종료하면 컨테이너가 멈춤).

    기본 명령:
    • docker exec -it container-name /bin/bash(bash 실행)
    • docker exec -it container-name sh(sh 실행, Alpine에서 자주 사용)
    • docker exec container-name command(컨테이너에 들어가지 않고 단일 명령 실행)

    옵션 설명:
    • -i: STDIN을 열린 상태로 유지(대화형)
    • -t: 의사 터미널 할당(출력 형식화)
    • 두 옵션을 함께 사용할 때 가장 효과적

    사용 시나리오: exec는 디버깅, 도구 설치, 설정 변경에 적합하고 attach는 실시간 로그 출력 확인에만 적합합니다.
  2. 2

    Step 2: 도구 누락 및 권한 문제 해결하기

    도구 설치 방법:
    • Debian/Ubuntu: apt-get update && apt-get install -y tool-name
    • Alpine: apk add --no-cache tool-name
    • CentOS/RHEL: yum install -y tool-name

    읽기 전용 파일 시스템 처리: 컨테이너가 읽기 전용 파일 시스템을 사용한다면 먼저 다음을 실행합니다.
    docker exec -u root container-name sh -c 'mount -o remount,rw /'

    사용자 권한 지정:
    • -u root로 root 권한 사용: docker exec -u root container-name
    • --user uid:gid로 특정 사용자 지정
    • 현재 사용자 확인: whoami
    • 파일 권한 확인: ls -la
    • 권한 변경: chmod 755 file, chown user:group file

    주의 사항: 프로덕션 환경에서는 root 권한을 신중하게 사용하고, 변경 사항을 즉시 기록해 Dockerfile에 반영하여 컨테이너 재시작 후 사라지지 않게 하세요.
  3. 3

    Step 3: 체계적인 디버깅 점검 절차

    디버깅 체크리스트(순서대로 실행):
    1) 로그 확인: docker logs container-name 또는 컨테이너 내부의 /var/log 확인
    2) 프로세스 상태 확인: ps aux | grep process-name으로 핵심 프로세스 실행 여부 확인
    3) 포트 리스닝 검증: netstat -tuln | grep port 또는 ss -tuln
    4) 설정 파일 확인: cat /path/to/config로 설정이 올바른지 확인
    5) 디스크 공간 확인: df -h로 여유 공간 확인
    6) 네트워크 연결 테스트: curl http://localhost:port, ping hostname

    디버깅 순서:
    먼저 로그에서 오류 정보 찾기 → 프로세스를 확인해 서비스 실행 여부 점검 → 설정을 검증해 설정 오류 배제 → 마지막으로 네트워크 연결 확인

    이 순서대로 조사하면 컨테이너 문제의 90% 이상을 체계적으로 해결할 수 있습니다.

FAQ

컨테이너에 들어갈 때 attach보다 exec를 권장하는 이유는 무엇인가요?
exec와 attach의 핵심 차이는 프로세스를 처리하는 방식에 있습니다.

• exec: 새 프로세스를 생성해 컨테이너에 들어가므로 주 프로세스에 영향을 주지 않으며, 종료해도 컨테이너가 계속 실행됩니다.
• attach: 주 프로세스의 stdin/stdout에 연결하므로 종료할 때 컨테이너가 멈춥니다.

따라서 exec는 안전하게 컨테이너에 들어가 문제를 확인할 수 있어 디버깅에 더 적합하고, attach는 주로 실시간 로그 출력을 확인할 때 사용합니다.
컨테이너 안에 bash나 sh가 없으면 어떻게 해야 하나요?
컨테이너 안에 bash나 sh가 없다면 다음 방법을 시도해 보세요.

• 다른 셸 사용: docker exec -it container-name /bin/ash(Alpine에서 자주 사용)
• 명령 직접 실행: docker exec container-name command(대화형 셸에 들어갈 필요 없음)
• 사용 가능한 셸 확인: docker exec container-name ls /bin/
• busybox 사용: 일부 경량 이미지에는 busybox만 있을 수 있으므로 docker exec -it container-name busybox sh를 시도

대화형 디버깅이 꼭 필요하다면 Dockerfile에서 bash나 sh를 미리 설치하는 편이 좋습니다.
읽기 전용 파일 시스템을 사용하는 컨테이너에는 어떻게 도구를 설치하나요?
읽기 전용 파일 시스템을 사용하는 컨테이너에서는 먼저 파일 시스템을 쓰기 가능 상태로 다시 마운트해야 합니다.

1. 루트 디렉터리를 쓰기 가능 상태로 다시 마운트합니다.
docker exec -u root container-name sh -c 'mount -o remount,rw /'

2. 그다음 도구를 정상적으로 설치합니다.
docker exec -u root container-name apt-get update
docker exec -u root container-name apt-get install -y tool-name

주의: 컨테이너를 재시작하면 변경 사항이 사라집니다. 도구 설치 단계를 Dockerfile에 추가하거나 멀티 스테이지 빌드로 자주 쓰는 도구를 미리 설치하는 것이 좋습니다.
컨테이너에서 외부 네트워크에 접속할 수 없으면 어떻게 해야 하나요?
다음 순서로 컨테이너 네트워크 문제를 조사합니다.

1. 컨테이너 네트워크 모드 확인:
docker inspect container-name | grep NetworkMode

2. DNS 조회 테스트:
docker exec container-name nslookup google.com

3. 네트워크 연결 테스트:
docker exec container-name ping -c 3 8.8.8.8

4. 방화벽 규칙 확인:
docker exec container-name iptables -L

5. 사용자 정의 네트워크를 사용한다면 네트워크 설정 확인:
docker network inspect network-name

흔한 원인은 잘못된 DNS 설정, 방화벽 규칙 제한, 네트워크 모드 설정 문제입니다.
exec로 컨테이너에 들어간 뒤 컨테이너 실행에 영향을 주지 않고 어떻게 나가나요?
exec로 컨테이너에 들어간 뒤 안전하게 나가는 방법은 여러 가지입니다.

• exit 입력 또는 Ctrl+D: 정상적으로 종료하며 컨테이너에 영향을 주지 않음
• Ctrl+P를 누른 다음 Ctrl+Q: 분리 모드로 종료하고 컨테이너는 계속 실행됨
• 터미널 직접 닫기: -it 옵션을 사용했다면 터미널 창을 바로 닫아도 됨

주의: docker attach로 컨테이너에 연결한 뒤 Ctrl+C를 누르면 컨테이너의 주 프로세스가 멈춥니다. exec로 들어간 경우에는 종료해도 주 프로세스 실행에 영향을 주지 않습니다.

4분 읽기 · 게시일: 2025년 12월 18일 · 수정일: 2026년 9월 4일

댓글

GitHub로 로그인하여 댓글을 남기세요

Easton BlogEaston Blog