Docker에서 작동하는 웹 애플리케이션을, 제품 환경에서 운용할 때는 애플리케이션 서버, 로그 서버, 프록시 서버 등과 같이 여러 개의 컨테이너들을 연계하여 작동시킨다.
이 장에서는 여러 개의 컨테이너를 운용 관리하는 법을 살펴보기로 한다.
웹 시스템의 실행 환경은 웹 서버, 프록시 서버 등과 같이 역할이 다른 여러 개의 서버를 연계하여 작동시키는 것이 일반적이다.
웹 3계층 아키텍처는 웹 애플리케이션의 대표적인 인프라 아키텍처 중 하나로, 웹 시스템의 서버들을 역할별로 프론트 서버, 애플리케이션 서버, 데이터베이스 서버 3개로 나누는 것을 의미한다.
대부분의 웹 시스템은 웹 3계층 아키텍처 구성을 취하고 있다. 논리적인 분할이므로 부하가 적은 시스템에서는 동일한 노드 상에서 실행하는 것도 가능하며, 클라우드 시스템 등에서 실행시킬 때는 부하에 따른 오토스케일 기능을 사용하는 것이 좋다.
클라이언트의 웹 브라우저가 보낸 HTTP 요청을 받아, HTTP 응답을 반환하는 서버 기능을 가진다. 이 서버 기능은 웹 프론트 서버 또는 웹 서버라고 한다.
애플리케이션 서버는 업무 처리를 실행하는 서버다.
데이터베이스 서버는 영구 데이터를 관리하기 위한 서버이다.
Docker 컨테이너는 웹 프론트 서버와 같이 트래픽의 증감 등에 맞춰 필요할 때 실행하고 필요 없어지면 파기시키는 일회성 운용에 적합하다. 한편 데이터베이스에는 영구적으로 관리해야하는 중요한 정보가 저장되어 있기 때문에, 쉽게 생성하고 삭제할 수 있는 컨테이너에 영구 데이터를 저장하는 것은 적합하지 않을 수 있다. 따라서, 어떤 시스템을 컨테이너에서 운용하는 것이 적절한지 고민해볼 필요가 있다.
웹 시스템에서는 여러 개의 Docker 컨테이너가 협력하며 작동한다. Docker Compose는 여러 컨테이너를 모아서 관리하기 위한 툴이다. Docker Compose는 'docker-compose.yml'라는 파일에 컨테이너의 구성 정보를 정의함으로써 동일 호스트 상의 여러 컨테이너를 일괄적으로 관리할 수 있다.
# 샘플 애플리케이션 클론
$ git clone https://github.com/asashiho/dockertext2
$ cd dockertext2/chap07/
# Compose 정의 파일 확인
$ cat docker-compose.yml
version: '3.3'
services:
# WebServer config
webserver:
build: . #현재 디렉토리에 이미지 빌드
ports:
- "80:80" #외부에 80번 포트공개
depends_on:
- redis #redis 서비스에 의존
# Redis config
redis:
image: redis:4.0
# 샘플 애플리케이션의 컨테이너 시작
$ docker-compose up
# (다른 터미널에서 실행) 가동중인 컨테이너 확인
$ docker-compose ps
http://localhost:80 에 접속하면 샘플 애플리케이션이 정상적으로 시작된걸 확인할 수 있다.
# 컨테이너 정지
$ docker-compose stop
# 리소스 삭제
$ docker-compose down
여러 컨테이너를 일괄 관리할 수 있는 Docker Compose의 구성 관리 파일인 docker-compose.yml을 작성하는 방법에 대해 알아보자.
# Compose 정의 파일의 예
# 버전을 지정
version: "3"
# 서비스 정의
services:
webserver:
image: ubuntu
ports:
- "80:80"
networks:
- webnet
redis:
image: redis
networks:
- webnet
# 네트워크 정의
networks:
webnet:
# 데이터 볼륨 정의
volumes:
data-volume:
Docker 컨테이너의 바탕이 되는 베이스 이미지를 저장하려면 image를 사용한다. image에는 이미지의 이름 또는 이미지 ID 중 하나를 지정한다.
# 이미지의 태그를 지정하지 않는 경우
services:
webserver:
image: ubuntu
# 이미지의 태그를 지정한 경우
services:
webserver:
image: asashiho/dockersample:1.0
이미지의 작성을 Dockerfile에 기술하고 그것을 자동으로 빌드하여 베이스 이미지를 지정할 때는 build를 지정한다. build에는 Dockerfile의 파일 경로를 지정한다.
# build 지정
services:
webserver:
build: . # docker-compose.yml이 있는 디렉토리를 현재 디렉토리로 했을 때의 Dockerfile의 위치를 지정한다.
# 임의의 이름으로 된 Dockerfile 빌드 시
services:
webserver:
build:
context: /data
dockerfile: Dockerfile-alternate
# Docker 이미지 빌드시 인수 지정
services:
webserver:
build:
args:
projectno: 1
user: asa
# docker-compose.yml 안에서 지정한 Dockerfile이 자동으로 빌드되어 컨테이너가 생성
$ docker-compose up --build
다른 컨테이너에 대한 링크 기능을 사용하여 연결하고 싶을 때는 links를 사용하여 연결할 컨테이너명을 설정한다.
# 링크 지정
links:
- logserver
- logserver:log01 # 서비스명:앨리어스명으로 지정할 수도 있다.
컨테이너가 공개하는 포트는 ports로 지정한다.
# 공개 포트 지정
ports:
- "3000"
- "8000:8000"
- "49100:22"
- "127.0.0.1:8001:8001"
호스트 머신에 대한 포트를 공개하지 않고 링크 기능을 사용하여 연결하는 컨테이너에게만 포트를 공개할 때는 expose를 지정한다.
# 컨테이너 내부에만 공개하는 포트 지정
expose:
- "3000"
- "8000"
여러 서비스의 의존관계를 정의할 때는 depends_on을 지정한다.
# 의존관계 지정
services:
webserver:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: postgress
webserver 컨테이너를 시작하기 전에 db 컨테이너와 redis 컨테이너를 시작하고 싶을 때는 위와 같이 정의한다. 단, depends_on은 컨테이너의 시작 순서만 제어할 뿐 컨테이너상의 애플리케이션이 이용 가능해질 때까지 기다리고 제어하지는 않으므로 주의해야 한다.
컨테이너 안의 환경변수를 지정할 때는 environment를 지정한다.
# 환경변수 지정
# 배열 형식으로 지정
environment:
- HOGE=fuga
- FOO
# 해시 형식으로 지정
environment:
HOGE: fuga
FOO:
설정하고 싶은 환경변수의 수가 많을 때는 다른 파일에서 환경변수를 정의하고 그 파일을 읽어 들일 수도 있다. 환경변수 파일을 읽어 들일 때는 env_file을 지정한다.
# 환경변수 파일 읽어들이기
env_file: envfile
# 여러 개의 환경변수 파일 읽어 들이기
env_file:
- ./envfile1
- ./app/envfile2
- /tmp/envfile3
Docker Compose로 생성되는 컨테이너에 이름을 붙일 때는 container_name을 지정한다. 단, Docker 컨테이너명은 고유해야하므로 커스텀명을 지정하면 여러 컨테이너로 스케일할 수 없어진다.
# 컨테이너명 지정
container_name: web-container
컨테이너에 라벨을 붙일 때는 labels를 지정한다. 여러 개의 라벨을 붙일 때는 YAML의 배열 또는 해시 형식 중 하나로 변수를 지정한다.
# 컨테이너 라벨 설정
# 배열 형식으로 지정
labels:
- "com.example.description=Accounting webapp"
- "com.example.department=Finance"
# 해시 형식으로 지정
lables:
com.example.description: "Accounting webapp"
com.example.department: "Finance"
설정한 라벨을 확인할 때는 docker-compose config
명령을 사용한다.
컨테이너에 볼륨을 마운트할때는 volumes를 지정한다. 호스트 측에서 마운트할 경로를 지정하려면 '호스트의 디렉토리 경로:컨테이너의 디렉토리 경로'를 지정한다.
# 볼륨 지정
volumes:
- /var/lib/mysql
- cache/:/tmp/cache
# 읽기 전용 볼륨 지정
volumes:
- ~/configs:/etc/configs/:ro
# 볼륨 마운트 지정
volumes_from:
- log #log라는 컨테이너로 마운트할 때
Docker Compose는 Docker for Mac 또는 Docker for Windows에 미리 설치되어 있으며, docker-compose --version
을 통해 버전을 확인할 수 있다.
# 여러 컨테이너의 일괄 생성 및 시작
$ docker-compose up
# 여러 컨테이너를 백그라운드로 시작
$ docker-compose up -d
# Docker 이미지 빌드
$ docker-compose up --build
# 컨테이너 개수 지정
$ docker-compose up --scale server_a=10 --scale server_b=20
# 여러 컨테이너의 상태 확인
$ docker-compose ps
NAME COMMAND SERVICE STATUS PORTS
chap07_redis_1 "docker-entrypoint.s…" redis running 6379/tcp
chap07_webserver_1 "python /opt/imagevi…" webserver running 0.0.0.0:80->80/tcp, :::80->80/tcp
# 컨테이너 ID 확인
$ docker-compose ps -q
05f714da81b84f598e2b0ef745b8a154435247f72da5aca2095897d077df2131
e671cb389faf0f26a0417beb6b9686ccbdb5c5a46e12755a19d60eb494d369ef
# Docker 명령을 사용한 컨테이너 확인
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
NAMES
e671cb389faf chap07_webserver "python /opt/imagevi…" About a minute ago Up About a minute 0.0.0.0:80->80/tcp, :::80->80/tcp chap07_webserver_1
05f714da81b8 redis:4.0 "docker-entrypoint.s…" About a minute ago Up About a minute 6379/tcp
chap07_redis_1
# Docker 명령을 사용한 로그 확인
$ docker-compose logs
# 컨테이너에서 명령 실행
$ docker-compose run redis /bin/bash
root@aa4b78e287fc:/data#
Docker Compose를 사용하면 여러 개의 서비스를 일괄적으로 시작, 정지, 재시작 할 수 있다.
$ docker-compose start
$ docker-compose stop
$ docker-compose restart
# 특정 컨테이너 재시작
$ docker-compose restart redis
```shell
### 여러 컨테이너 일시 정지/재개(pause/unpause)
Docker Compose를 사용하면 여러 개의 서비스를 일괄적으로 일시정지, 재개할 수 있다.
```shell
$ docker-compose pause
$ docker-compose unpause
# 공개 포트 확인
$ docker-compose port webserver 80
0.0.0.0:80
# 컨테이너에 시그널 송신
$ docker-compose kill -s SIGINT
# 여러 컨테이너 일괄 삭제
$ docker-compose rm
실행중인 컨테이너를 정지시키고, Docker 이미지, 네트워크, 데이터 볼륨을 일괄적으로 삭제하는 명령이다.
# 여러 이미지 삭제
$ docker-compose down --rmi all
본문은 'Asa Shijo, <완벽한 IT 인프라 구축을 위한 Docker>, 정보문화사(2020)' 를 참고하여 정리한 글입니다.
[참고: 완벽한 IT 인프라 구축을 위한 Docker]