Dockerfile이란?
Dockerfile은 애플리케이션을 패키징하기 위한 스크립트이다. 그러나 분산 애플리케이션을 기준으로 보면 Dockerfile 스크립트는 애플리케이션의 한 부분을 패키징하는 수단에 지나지 않는다. 여러 서버가 필요한 경우, 각각의 Dockerfile을 만들 것이다. 그렇다면 이들 컨테이너는 누가 실행해야 할까? 직접 순서대로 각각의 컨테이너를 도커 명령행을 통해 일일이 옵션을 지정해가며 실행할 수도 있겠지만, 이런 방법 대신 도커 컴포즈 파일에 애플리케이션 구조를 정의하면 된다.
Docker Compose란?
도커 컴포즈 파일은 애플리케이션의 '원하는 상태', 즉 컴포넌트가 실행 중일 때 어떤 상태여야 하는지를 기술하는 파일이다. 또한, docker container run 명령으로 컨테이너를 실행할 때 지정하는 모든 옵션을 한데 모아 놓은 단순한 형식의 파일이다. YAML 문법으로 기술되며 이는 들여쓰기를 통해 구조를 정의하기 때문에 들여쓰기가 중요하다. “무엇을 원하는지”만 적으면 docker compose up 명령어를 통해 필요한 리소스(컨테이너, 네트워크, 볼륨)를 알아서 생성/연결한다. docker compose down을 하면 애플리케이션이 중지되며 모든 컨테이너가 제거된다.
- `services:` 에는 이미지, 포트, 환경변수, 볼륨, 네트워크, 커맨드, 헬스체크 등 “컨테이너의 실행 규칙(템플릿)”이 들어가며, 이 규칙을 바탕으로 컨테이너를 1개 이상 만들 수 있다. 예를 들어 docker compose up -d --scale [서비스명]=3 이라고 하면 services: 밑에 정의한 [서비스명] 설정값으로 컨테이너 3개를 띄운다.
- `networks:` 에는 컨테이너가 연결될 모든 도커 네트워크를 열거하는 부분이다. 도커 컴포즈는 한 호스트 내에서 여러 컨테이너가 동작하게 만드는 설정이기 때문에 컨테이너끼리 서로 통신하는 가상의 격리 네트워크가 필요하다. 같은 네트워크에 붙은 컨테이너끼리는 서로 서비스 이름으로 접근이 가능하다. Docker 데몬이 올라오면 기본 격리 네트워크가 자동으로 생기고, 그 밖의 “프로젝트 전용 네트워크”는 컨테이너/Compose를 올릴 때 필요에 따라 생성하면 된다. 한 호스트 내에서 여러 컨테이너를 띄우는 것이기 때문에 실제 운영 서버를 띄울 때보다는 개발/테스트할 때 필요한 기술이라고 볼 수 있다.
아래 예시를 보자.
version: "3.9"
services:
proxy:
image: nginx:alpine
ports:
- "8080:80" # 외부 공개는 proxy만
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
depends_on: [web]
networks: [app]
web:
image: myorg/my-web:1.0 # 내부 포트 3000에서 리슨한다고 가정
expose:
- "3000" # 내부 컨테이너들만 접근 (호스트 공개 X)
networks: [app]
api:
image: myorg/my-api:1.0
expose: ["8000"]
networks: [app]
redis:
image: redis:7
networks: [app]
networks:
app:
driver: bridge
docker compose up -d --build
docker compose up -d --scale web=3
- 내부 통신엔 ports 불필요하고, 같은 네트워크에서 http://서비스이름:포트로 접근하면 되므로 proxy 템플릿에만 외부 접근 가능 포트가 명시되어 있다. 나머지는 expose로 포트가 명시되어 있는데 이는 내부에서만 해당 포트로 접근 가능하다는 뜻이다.
- 위와 같이 외부는 프록시 한 곳만 ports 공개하면 깔끔한 라우팅/보안/관측을 달성한다.
- --build는 컨테이너를 올리기 전에 이미지부터 빌드하라는 옵션이다. 정확히는 도커 컴포즈 파일에 'build:'가 있는 서비스들에 대해, docker compose up 실행 전에 docker compose build를 먼저 수행한다. 만약 이 옵션이 없는 경우에는 이미지가 없을 때만 빌드한다.
- 첫 번째 명령어를 통해 이미지를 먼저 빌드하고, 각 서비스당 컨테이너 1개씩 올릴 것이다. 그 다음 명령어를 수행하면 이미 떠 있는 web_1을 유지한 채, 추가 컨테이너(web_2, web_3)만 더 띄워서 총 3개로 맞춘다. 'docker compose up -d --build --scale web=3' 처럼 한 번에 할 수도 있다.
도커 컨테이너 간의 통신
컨테이너는 도커 엔진으로부터 부여받은 자신만의 가상 IP 주소를 가지며 모두 같은 도커 네트워크로 연결돼 이 IP 주소를 통해 서로 통신할 수 있다. 그러나 애플리케이션 생애주기 동안에 컨테이너가 교체되면 IP 주소도 변경된다. IP 주소가 변경돼도 문제가 없도록 도커에서 DNS를 이용해 서비스 디스커버리 기능을 제공한다. 컨테이너 이름을 도메인 삼아 조회하면 해당 컨테이너의 IP 주소를 찾아준다. 서비스명을 nslookup 명령어로 검색하면 해당 서비스의 컨테이너들의 주소가 출력된다. (nslookup은 웹 애플리케이션 컨테이너의 기반 이미지에 있는 유틸리티)
도커 네트워크에 연결된 모든 컨테이너는 이 네트워크 범위에 포함되는 IP 주소를 부여받는다. 그리고 이 네트워크를 통해 통신이 가능하다. DNS 조회를 사용하면 컨테이너가 교체되어 IP 주소가 변경되더라도 항상 새로 만들어진 컨테이너에 접근할 수 있다.
참고: Docker Compose와 Kubernetes
| 항목 | Docker Compose | Kubernetes |
| 적용 범위 | 단일 호스트 중심 | 멀티 노드 클러스터 |
| 목적 | 개발/테스트, 소규모 배포 간편화 | 대규모/고가용성 프로덕션 운영 |
| 원하는 상태 관리 | 부분적(명령형에 가까움) | 선언적 Desired State + 컨트롤러가 지속 보정 |
| 자가치유(Self-healing) | 제한적(재시작 정책 정도) | 파드 재스케줄, 노드 장애시 자동 복원 |
| 배포/업데이트 | 수동 재시작/교체, --scale | RollingUpdate/Blue-Green, HPA(오토스케일) |
| 네트워킹 | 사용자 정의 브리지 네트워크, 서비스명 DNS | 클러스터 네트워크, Service/Ingress, 서비스 디스커버리 |
| 스토리지 | 로컬/호스트 볼륨 중심 | PV/PVC로 스토리지 추상화, 동적 프로비저닝 |
| 시크릿/설정 | env/파일 마운트 위주 | Secret/ConfigMap 자원, RBAC |
| 관측/보안 | 기본 로그/포트포워딩 | 프로브(Readiness/Liveness), 네임스페이스 격리, 네트워크 정책 |
| 러닝 커브 | 낮음 | 높음(대신 운영 자동화 강력) |
'development' 카테고리의 다른 글
| 인증 구현하기 (JWT, Oauth) (0) | 2026.01.05 |
|---|---|
| Docker: 헬스 체크와 디펜던시 체크로 신뢰성 확보하기 (0) | 2025.09.14 |
| 서버 환경 구성하기4 - 성능과 가용성을 보장하기 (0) | 2025.09.07 |
| 서버 환경 구성하기3 - 정적 콘텐츠를 낮은 비용으로 (0) | 2025.09.07 |
| 서버 환경 구성하기2 - AWS 기초 공부하기 (0) | 2025.09.03 |