컨테이너 배포 (Deployment)
왜 배포에 컨테이너를 사용하는가?
컨테이너는 애플리케이션 코드와 실행 환경을 하나의 독립적인 패키지로 묶어준다.
- 도커가 설치된 곳이라면 어디서든 동일하게 실행 가능
- 로컬 머신에서 작동하는 코드가 리모트 머신에서도 그대로 작동
- 머신 자체에 NodeJS 같은 도구를 직접 설치할 필요 없음 (컨테이너 내부에 모두 포함)
핵심 아이디어는 아래와 같다.
로컬에서 작동하면, 배포 후에도 작동한다
개발 vs 프로덕션
1. 바인드 마운트
- 개발: 바인드 마운트를 많이 사용 (코드 변경 즉시 반영)
- 프로덕션: 바인드 마운트를 사용하면 안 됨
2. 빌드 단계
- React 앱 같은 경우, 배포 전에 코드 변환 및 최적화를 위한 빌드 단계가 필요
- 개발과 프로덕션에서 다른 설정이 필요할 수 있음
3. 다중 컨테이너 프로젝트
- 로컬에서는 Docker Compose로 하나의 머신에서 테스트
- 배포 시에는 여러 호스트 머신에 분할 배포를 고려할 수 있음
4. 통제 vs 책임의 트레이드오프
- 리모트 호스트를 직접 관리하면 통제력은 높지만 책임도 큼 (보안 등)
- 관리형 서비스를 사용하면 통제력은 낮지만 책임도 줄어듦
기본 배포 흐름
단일 컨테이너, 단일 서버 배포의 기본 흐름은 아래와 같다.
- 리모트 서버 설정 (예: AWS EC2)
- SSH로 리모트 서버에 연결
- 리모트 서버에 Docker 설치
- 로컬에서 Docker Hub로 이미지 푸시
- 리모트 서버에서 이미지 풀
- 컨테이너 실행 및 포트 노출
- 브라우저에서 테스트
호스팅 프로바이더
도커를 지원하는 호스팅 프로바이더는 정말 많다.
주요 클라우드 서비스 프로바이더
- AWS (Amazon Web Services): 가장 큰 클라우드 프로바이더
- Microsoft Azure
- Google Cloud Platform (GCP)
이들은 단순 호스팅을 넘어 머신 러닝, 데이터베이스 등 다양한 클라우드 서비스를 제공한다.
개발 vs 프로덕션: 바인드 마운트
개발 중 (Development)
- 컨테이너는 런타임 환경만 캡슐화
- 코드는 컨테이너 외부에서 제공 (바인드 마운트)
- 코드 변경 시 이미지 리빌드나 컨테이너 재시작 불필요
- 즉각적인 업데이트 가능
프로덕션 (Production)
- 컨테이너는 stand alone으로 작동해야 함
- 리모트 머신의 주변 설정에 의존하면 안 됨
- 이미지 = 애플리케이션에 필요한 모든 것의 단일 소스
- 호스팅 머신에 소스 코드를 별도로 이동시킬 필요 없어야 함
왜 프로덕션에서 바인드 마운트를 쓰면 안 되는가?
- 호스팅 머신을 추가로 구성해야 한다면 컨테이너의 핵심 사상이 무너짐
- 컨테이너 안에 애플리케이션이 필요로 하는 모든 것이 포함되어야 함
- 주변 구성이나 외부 코드 없이 실행 가능해야 함
해결책: COPY 명령 사용
- 프로덕션 빌드 시 COPY 명령으로 소스 코드를 이미지에 복사
- 빌드된 이미지에 소스 코드 + 애플리케이션 환경 모두 포함
- 컨테이너 실행 위치에 관계없이 동일하게 작동
개발/프로덕션 구분 방법
- Dockerfile에는 COPY 명령 포함
- 개발 시: docker run -v 플래그로 바인드 마운트 추가
- 프로덕션 시: 바인드 마운트 없이 실행
- 동일한 Dockerfile로 개발과 프로덕션 모두 대응 가능
AWS EC2 실습: 수동 배포 프로세스
1. 인스턴스 생성 및 연결
- 인스턴스 설정: Amazon Linux AMI, t2.micro(프리 티어) 등을 선택하여 가상 서버를 생성한다.
- 키 페어(Key Pair) 관리:
- SSH 접속을 위한 암호화 키(.pem) 파일이다.
- 중요: 인스턴스 생성 시 단 한 번만 다운로드 가능하며, 분실 시 해당 인스턴스에 영구적으로 접속할 수 없다. 보안을 위해 타인과 공유해서는 안 된다.
- SSH 연결: Windows(PuTTY/WSL2), Mac/Linux(터미널)를 통해 리모트 서버에 접속한다.
2. 리모트 머신 설정 (Docker 설치)
- 필수 패키지 업데이트: sudo yum update -y로 시스템을 최신 상태로 만든다.
- 도커 설치
- sudo yum update -y - 시스템 패키지 업데이트
- sudo yum install -y docker - Docker 설치
- sudo service docker start - Docker 서비스 시작
- sudo usermod -a -G docker ec2-user - ec2-user에게 Docker 권한 부여
- 로그아웃 후 재접속 (권한 적용을 위해)
- 핵심: 리모트 머신에는 오직 Docker만 설치하면 된다. Node.js나 Python 같은 런타임을 설치할 필요가 없다. (모든 환경은 이미지 안에 있으므로)
3. 배포 전략: 이미지 기반 배포
리모트 서버로 소스 코드를 복사해서 빌드하는 방식은 비효율적이다.
- 권장 워크플로우:
- 로컬 빌드: 로컬 머신에서 이미지를 빌드한다.
- 푸시(Push): Docker Hub(또는 레지스트리)에 이미지를 업로드한다.
- 풀(Pull) & 런(Run): 리모트 서버에서 이미지를 다운로드하여 실행한다.
- 이를 위해 docker tag 명령어로 이미지 이름을 리포지토리 이름과 일치시켜야 한다.
4. 네트워크 및 보안 그룹(Security Group) 설정
컨테이너를 실행해도 브라우저에서 접속이 안 될 수 있다. 이는 EC2의 보안 기능 때문이다.
- 기본 설정: EC2는 기본적으로 SSH(22번 포트)를 제외한 모든 외부 접속을 차단한다.
- 인바운드 규칙 수정: AWS 콘솔의 'Security Groups'에서 HTTP(80번 포트) 트래픽을 'Anywhere(모든 위치)'에서 허용하도록 규칙을 추가해야 한다.
- 설정 후 퍼블릭 IP로 접속하면 배포된 앱을 확인할 수 있다.
5. 애플리케이션 업데이트 과정
코드가 변경되었을 때 자동 반영되지 않으므로 수동 절차가 필요하다.
- 로컬: 코드 수정 -> 이미지 리빌드 -> Docker Hub 푸시.
- 리모트:
- docker stop [컨테이너] (중지)
- docker rm [컨테이너] (삭제 - 이름 충돌 방지)
- docker pull [이미지] (필수: 최신 이미지 다운로드)
- docker run [옵션] [이미지] (재실행)
수동(DIY) 배포의 한계와 관리형 서비스
1. DIY(Do-It-Yourself) 방식의 장점
- 단순함: 리모트 호스트에 도커 외에 다른 설치가 필요 없다.
- 환경 일치: 로컬 개발 환경과 완벽히 동일한 환경을 리모트에서 실행한다.
2. 과도한 책임
AWS EC2와 같은 인프라를 직접 빌려 쓰는 방식(IaaS)은 리모트 머신에 대한 완전한 소유권과 책임을 사용자에게 부여한다.
- 운영 체제 관리: OS 업데이트, 시스템 소프트웨어 패치를 직접 해야 한다.
- 보안 책임: 방화벽(보안 그룹) 구성 실수 시 해킹 위험이 있으며, 보안 패치를 놓치면 취약해진다.
- 확장성 관리: 트래픽 증가 시 직접 서버 사양을 업그레이드하거나 관리해야 한다.
- 비효율적 워크플로우: 배포할 때마다 SSH 접속, 명령어 입력 등 수작업이 많다.
3. 결론: 관리형 서비스(Managed Service)의 필요성
- 개발자는 서버 관리(Ops)보다 애플리케이션 개발(Dev)에 집중해야 한다.
- 관리형 서비스(예: AWS ECS): 서버 설정, OS 업데이트, 보안 관리를 클라우드 제공자가 대행해준다.
- 다음번엔 수동 제어의 부담을 줄이고 배포를 자동화할 수 있는 관리형 서비스에 대해 다룰 예정이다.
트러블슈팅
문제 상황
- Mac M1/M2/M3/M4 사용자가 로컬에서 빌드한 이미지를 EC2에서 실행하면 다음과 같은 에러가 발생한다.
no matching manifest for linux/amd64
또는 컨테이너가 실행되자마자 종료되는 현상이 나타난다.
이는 CPU 아키텍쳐의 불일치로 인해 발생하는 것이다.
| Mac (Apple Silicon) | ARM64 (aarch64) |
| AWS EC2 (대부분) | AMD64 (x86_64) |
Docker는 기본적으로 호스트 머신의 아키텍처에 맞춰 이미지를 빌드한다. 따라서 ARM64로 빌드된 이미지는 AMD64 서버에서 실행되지 않는다.
해결 방법
- 로컬(Mac)에서 --platform 옵션을 추가하여 다시 빌드한다
# 1. AMD64용으로 빌드
docker build --platform linux/amd64 -t [이미지명] .
# 2. Docker Hub에 푸시
docker push [이미지명]
이후 EC2에서 docker pull 또는 docker run을 실행하면 정상 작동한다.
반응형
'Infra > Docker' 카테고리의 다른 글
| 컨테이너 배포: 자동(관리형 서비스) (0) | 2025.12.15 |
|---|---|
| Docker Networks (0) | 2025.12.12 |
| Docker Data & Volumes (0) | 2025.12.12 |
| Docker Image & Container 명령어 정리 (0) | 2025.12.12 |
| Container의 근반이 되는 기술에 대해 알아보자(완) UnionFS (0) | 2025.12.11 |