티스토리 뷰

반응형

✏️ 발단

서버 배포 방식을 점검하다가 위험한 부분을 발견했다. 현재 배포 흐름은 아래와 같다.

GitHub Actions
→ Docker 이미지 빌드
→ Docker Hub push
→ EC2 SSH 접속
→ 기존 컨테이너 삭제
→ 새 컨테이너 실행

문제는 기존 컨테이너를 삭제하는 명령어였다. 이 명령어는 EC2에 떠 있는 모든 Docker 컨테이너를 삭제한다. 지금은 애플리케이션 컨테이너 하나만 실행 중이라 문제가 없어 보이지만, 나중에 같은 EC2에 Nginx, Redis, 모니터링 도구 같은 컨테이너가 추가되면 배포할 때 전부 같이 날아갈 수 있다. 운영 서버에서는 위험한 방식이다.

sudo docker rm -f $(docker ps -qa)

 

✏️ 기존 배포 스크립트의 문제

기존 스크립트는 대략 이런 형태였다.

sudo docker ps
sudo docker rm -f $(docker ps -qa)
sudo docker pull eatssu/eatssu-dev
sudo docker run -d -p 9000:9000 \
  --log-driver=awslogs \
  --log-opt awslogs-region=ap-northeast-2 \
  --log-opt awslogs-group=dev-ec2-group \
  eatssu/eatssu-dev

문제를 정리하면 다음과 같다.

  1. EC2의 모든 컨테이너를 삭제한다.
  2. 컨테이너 이름이 고정되어 있지 않다 (dazzling_spence 같은 랜덤 이름).
  3. EC2 재부팅 시 컨테이너 자동 재시작 정책이 없다.

랜덤 이름 컨테이너 문제

Docker에서 --name을 지정하지 않으면 랜덤 이름이 붙는다. 이 상태에서 단순히 배포 스크립트를 아래처럼 바꾸면 문제가 생긴다. 기존 컨테이너 이름은 eatssu-dev가 아니므로 삭제되지 않는다. 그러면 새 컨테이너를 실행할 때 9000 포트가 이미 점유되어 있어 실패한다. 그래서 기존 랜덤 이름 컨테이너도 안전하게 정리하는 전환 과정이 필요했다.

sudo docker rm -f eatssu-dev || true

port is already allocated

 

✏️ 개선 방향

이번 개선의 목표는 다음과 같았다.

  • 전체 컨테이너 삭제 금지
  • 애플리케이션 컨테이너만 삭제
  • 컨테이너 이름 고정
  • restart policy 추가
  • 기존 랜덤 이름 컨테이너도 안전하게 정리

최종적으로 수정한 스크립트는 다음과 같다.

sudo docker ps

# 이름 기반으로 먼저 삭제 시도 (이미 이름이 고정된 경우 대응)
sudo docker rm -f eatssu-dev || true

# 9000 포트를 점유한 컨테이너 정리 (랜덤 이름 컨테이너 대응)
PUBLISHED_CONTAINERS=$(sudo docker ps -q --filter publish=9000)
if [ -n "$PUBLISHED_CONTAINERS" ]; then
  sudo docker rm -f $PUBLISHED_CONTAINERS
fi

sudo docker pull eatssu/eatssu-dev

sudo docker run -d --name eatssu-dev --restart unless-stopped -p 9000:9000 \
  --log-driver=awslogs \
  --log-opt awslogs-region=ap-northeast-2 \
  --log-opt awslogs-group=dev-ec2-group \
  eatssu/eatssu-dev

 

✏️  의사결정 기록

1. publish=9000으로 컨테이너를 찾은 이유

처음에는 이미지 이름 기준으로 찾는 방법도 고려했다.

sudo docker ps -aq --filter ancestor=eatssu/eatssu-dev

하지만 이미지 이름이나 태그가 바뀌면 신뢰하기 어렵다.

이 서버에서는 애플리케이션이 항상 9000 포트를 사용하므로, 포트 기준으로 찾는 방식이 더 단순하고 확실했다.

sudo docker ps -q --filter publish=9000

이 방식은 컨테이너 이름이 랜덤이어도 잡을 수 있다. 단, 해당 EC2에서 9000 포트를 사용하는 컨테이너는 이 애플리케이션뿐이어야 한다는 전제가 있다. 실제로 서버에서 확인해보니 9000 포트를 사용하는 컨테이너는 하나뿐이었다.

 

2. xargs 대신 if 문을 사용한 이유

처음에는 이렇게 작성했다.

sudo docker ps -q --filter publish=9000 | xargs -r sudo docker rm -f

xargs -r은 GNU xargs 옵션으로, Ubuntu EC2에서는 문제없지만 macOS에서는 동작하지 않는다.
이식성과 가독성을 위해 if 문으로 바꿨다. 조금 길어졌지만 의도가 더 명확하고 환경 의존성도 줄었다.

PUBLISHED_CONTAINERS=$(sudo docker ps -q --filter publish=9000)
if [ -n "$PUBLISHED_CONTAINERS" ]; then
  sudo docker rm -f $PUBLISHED_CONTAINERS
fi

3. restart policy 추가

기존에는 restart policy가 없었다.

docker run -d -p 9000:9000 ...

이 경우 EC2가 재부팅되거나 Docker daemon이 재시작되면 컨테이너가 자동으로 다시 올라오지 않는다. --restart unless-stopped 옵션을 추가했다. unless-stopped는 사용자가 직접 중지하지 않은 컨테이너를 Docker 재시작 시 자동으로 다시 실행한다. 운영 서버에서는 기본적으로 넣는 것이 좋다.

sudo docker run -d --name eatssu-dev --restart unless-stopped -p 9000:9000 ...

 

✏️  배포 후 확인

1. 컨테이너 상태

컨테이너 이름이 랜덤에서 eatssu-dev로 고정된 것을 확인했다.

2. restart policy 확인

3. Health check

4. CloudWatch 에러 로그 확인

아무 로그도 출력되지 않았다. 최근 10분간 ERROR 로그 없음.

 

✏️ 최종 결과

항목 기존  개선
컨테이너 삭제 범위 EC2 전체 애플리케이션 컨테이너만
컨테이너 이름 랜덤 eatssu-dev 고정
restart policy 없음 unless-stopped
기존 랜덤 이름 컨테이너 정리 포트 기반 정리

 

✏️ 마무리

이번 작업은 무중단 배포까지 적용한 것은 아니다. 여전히 기존 컨테이너를 내리고 새 컨테이너를 올리는 방식이다.

하지만 전체 컨테이너 삭제라는 위험한 동작을 제거했고, 컨테이너 관리 기준을 명확히 했다. 무중단 배포로 가기 전 단계에서 반드시 해야 하는 안정화 작업이라고 볼 수 있다.

https://github.com/EAT-SSU/Server/pull/369

 

fix: 배포 스크립트 컨테이너 관리 안정화 by pooreumjung · Pull Request #369 · EAT-SSU/Server

#️⃣ Issue Number resolved fix: 배포 스크립트 컨테이너 관리 안정화 #368 📝 요약(Summary) sudo docker rm -f $(docker ps -qa) 제거 → 이름 기반(eatssu-prod / eatssu-dev) 삭제로 변경하여 다른 컨테이너가 함께 종

github.com

 

 

반응형
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/07   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함