Docker Compose는, 여러개의 컨테이너를 정의하고 실행하기 위한 도구입니다.
즉, 한번에 2개 이상 컨테이너를 하나의 세트처럼 실행해야 한다면 Docker Compose를 사용해볼 수 있습니다.
맛보기로 한번 진행 해봅시다!
🐳 step 1. Compose 설치
도커 설치 명령어부터 빠르게 다시 보겠습니다.
공식홈페이지에서도 확인할 수 있습니다.
1. Docker 설치
Docker가 설치될 OS를 확인합니다. 저는 Centos7 에 설치합니다 :)
[root@master /]# rpm -qa | grep release
centos-release-7-8.2003.0.el7.centos.x86_64
yum-utils 를 설치합니다.
[root@master /]# yum install -y yum-utils
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: d36uatko69830t.cloudfront.net
* extras: d36uatko69830t.cloudfront.net
* updates: d36uatko69830t.cloudfront.net
Package yum-utils-1.1.31-54.el7_8.noarch already installed and latest version
Nothing to do
도커 레포지토리를 추가합니다.
[root@master /]# yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
Loaded plugins: fastestmirror
adding repo from: https://download.docker.com/linux/centos/docker-ce.repo
grabbing file https://download.docker.com/linux/centos/docker-ce.repo to /etc/yum.repos.d/docker-ce.repo
repo saved to /etc/yum.repos.d/docker-ce.repo
이제 docker-ce, docker-ce-cli, containerd 를 설치합니다.
[root@master /]# yum install docker-ce docker-ce-cli containerd.io
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
.. 생략 ..
Installed:
containerd.io.x86_64 0:1.3.7-3.1.el7 docker-ce.x86_64 3:19.03.13-3.el7
docker-ce-cli.x86_64 1:19.03.13-3.el7
Dependency Installed:
container-selinux.noarch 2:2.119.2-1.911c772.el7_8
Complete!
docker 설치가 완료되었다면, docker 데몬을 시작합니다.
[root@master /]# systemctl start docker
[root@master /]# systemctl enable docker
Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service.
2. Docker Compose 설치
docker Compose을 다운받습니다.
[root@master /]# sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 651 100 651 0 0 1273 0 --:--:-- --:--:-- --:--:-- 1273
100 11.6M 100 11.6M 0 0 3077k 0 0:00:03 0:00:03 --:--:-- 5060k
바이너리파일에 실행 권한을 주고, 심볼릭 링크를 생성하여 명령어처럼 사용할 수 있도록 합니다.
[root@master /]# sudo chmod +x /usr/local/bin/docker-compose
[root@master /]# sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
docker-compose 명령어가 잘 동작하는지 확인하기 위해서 아래처럼 버전을 확인해봅시다.
[root@master /]# docker-compose --version
docker-compose version 1.27.4, build 40524192
🐳 step2. Compose 시작하기
자, 이제 테스트 파일을 이용하여 도커 컴포즈를 사용해보겠습니다.
모든 내용은 도커 공식홈페이지에 이미 나와있는 내용입니다.
1. 기본 설정
먼저, 테스트를 진행할 디렉토리를 생성하고. 그 안에 테스트 어플리케이션에서 루트디렉토리로 사용될 디렉토리를 생성합니다.
[root@master /]# mkdir Docker && cd Docker
[root@master Docker]# mkdir compose_test && cd compose_test/
2. Application 생성
먼저, app.py 파일을 생성합니다. 복사 붙여넣기 하세요.
[root@master /]# vim Docker/compose_test/app.py
import time
import redis
from flask import Flask
app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)
def get_hit_count():
retries = 5
while True:
try:
return cache.incr('hits')
except redis.exceptions.ConnectionError as exc:
if retries == 0:
raise exc
retries -= 1
time.sleep(0.5)
@app.route('/')
def hello():
count = get_hit_count()
return 'Hello World! I have been seen {} times.\n'.format(count)
두번째로, requirements.txt 파일을 생성합니다.
[root@master compose_test]# vim requirements.txt
flask
redis
3. Dockerfile 생성
이번에는, Dockerfile을 생성합니다.
Dockerfile 이란, 이 전 포스팅에서 다루었던 내용으로, Docker이미지를 빌드하는데 필요한 레시피가 적힌 파일입니다.
[root@master compose_test]# vim Dockerfile
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]
각 내용은 아래와 같습니다.
- Python 3.7 이미지로 시작하는 이미지를 빌드합니다.
- 작업 디렉토리를로 설정하십시오 /code.
- flask명령에 사용되는 환경 변수를 설정합니다 .
- gcc 및 기타 종속성 설치
- requirements.txtPython 종속성을 복사 하고 설치합니다.
- 이미지에 메타 데이터를 추가하여 컨테이너가 포트 5000에서 수신 중임을 설명합니다.
- .프로젝트 의 현재 디렉토리 를 .이미지 의 workdir 에 복사하십시오 .
- 컨테이너의 기본 명령을 flask run.
4 . docker-compose.yml 파일 생성
docker-compose.yml 을 생성합니다.
[root@master compose_test]# vim docker-compose.yml
version: "3.8"
services:
web:
build: .
ports:
- "5000:5000"
redis:
image: "redis:alpine"
각 내용은 아래와 같습니다.
- version:
- services: 실행할 컨테이너 목록입니다.
- web 서비스 (컨테이너)는 현재 디렉토리에 있는 Dockerfile로 빌드된 이미지를 사용하며, 포트를 바인딩 합니다 (5000:5000)
- redis 서비스는 Redis 공개이미지를 사용합니다.
자, 이제 4개의 파일을 모두 생성하였습니다.
tree 명령어를 이용해서 보면 이런 결과가 보일겁니다. 만들때 대소문자/오타에 주의하세요.
[root@master /]# tree /Docker/compose_test/
/Docker/compose_test/
├── Dockerfile
├── app.py
├── docker-compose.yml
└── requirements.txt
5 . Compose로 어플리케이션 실행
이제, 대망의 도커 컴포즈 업! 입니다.
[root@master compose_test]# docker-compose up
Creating network "compose_test_default" with the default driver
Building web
Step 1/10 : FROM python:3.7-alpine
3.7-alpine: Pulling from library/python
df20fa9351a1: Pull complete
36b3adc4ff6f: Pull complete
4db9de03f499: Pull complete
cd38a04a61f4: Pull complete
9a3838385f13: Pull complete
Digest: sha256:9fbee97d521b846689f4dbf0d5f2770c734d4a09e6d0a0991efc916c58970e99
Status: Downloaded newer image for python:3.7-alpine
---> 295b051ee125
Step 2/10 : WORKDIR /code
---> Running in 6699ada8855b
Removing intermediate container 6699ada8855b
---> 9740cfe088f6
Step 3/10 : ENV FLASK_APP=app.py
---> Running in a837433ea544
Removing intermediate container a837433ea544
---> dc1486d931c3
Step 4/10 : ENV FLASK_RUN_HOST=0.0.0.0
---> Running in f18e93d7fddf
Removing intermediate container f18e93d7fddf
---> ff9b48cde18c
Step 5/10 : RUN apk add --no-cache gcc musl-dev linux-headers
---> Running in 121818e10c32
fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/community/x86_64/APKINDEX.tar.gz
(1/13) Installing libgcc (9.3.0-r2)
(2/13) Installing libstdc++ (9.3.0-r2)
(3/13) Installing binutils (2.34-r1)
(4/13) Installing gmp (6.2.0-r0)
(5/13) Installing isl (0.18-r0)
(6/13) Installing libgomp (9.3.0-r2)
(7/13) Installing libatomic (9.3.0-r2)
(8/13) Installing libgphobos (9.3.0-r2)
(9/13) Installing mpfr4 (4.0.2-r4)
(10/13) Installing mpc1 (1.1.0-r1)
(11/13) Installing gcc (9.3.0-r2)
(12/13) Installing linux-headers (5.4.5-r1)
(13/13) Installing musl-dev (1.1.24-r9)
Executing busybox-1.31.1-r16.trigger
OK: 153 MiB in 48 packages
Removing intermediate container 121818e10c32
---> 6dc320445e5f
Step 6/10 : COPY requirements.txt requirements.txt
---> 891a41cc48a5
Step 7/10 : RUN pip install -r requirements.txt
---> Running in 6ed6c7af768b
Collecting flask
Downloading Flask-1.1.2-py2.py3-none-any.whl (94 kB)
Collecting redis
Downloading redis-3.5.3-py2.py3-none-any.whl (72 kB)
Collecting click>=5.1
Downloading click-7.1.2-py2.py3-none-any.whl (82 kB)
Collecting itsdangerous>=0.24
Downloading itsdangerous-1.1.0-py2.py3-none-any.whl (16 kB)
Collecting Jinja2>=2.10.1
Downloading Jinja2-2.11.2-py2.py3-none-any.whl (125 kB)
Collecting Werkzeug>=0.15
Downloading Werkzeug-1.0.1-py2.py3-none-any.whl (298 kB)
Collecting MarkupSafe>=0.23
Downloading MarkupSafe-1.1.1.tar.gz (19 kB)
Building wheels for collected packages: MarkupSafe
Building wheel for MarkupSafe (setup.py): started
Building wheel for MarkupSafe (setup.py): finished with status 'done'
Created wheel for MarkupSafe: filename=MarkupSafe-1.1.1-cp37-cp37m-linux_x86_64.whl size=16913 sha256=fdfbd33f72c6753a24891ac61ed9448a83ca12b7f11fc2248164388cf0dea9ea
Stored in directory: /root/.cache/pip/wheels/b9/d9/ae/63bf9056b0a22b13ade9f6b9e08187c1bb71c47ef21a8c9924
Successfully built MarkupSafe
Installing collected packages: click, itsdangerous, MarkupSafe, Jinja2, Werkzeug, flask, redis
Successfully installed Jinja2-2.11.2 MarkupSafe-1.1.1 Werkzeug-1.0.1 click-7.1.2 flask-1.1.2 itsdangerous-1.1.0 redis-3.5.3
Removing intermediate container 6ed6c7af768b
---> da6859d6dc07
Step 8/10 : EXPOSE 5000
---> Running in 856d2ddff942
Removing intermediate container 856d2ddff942
---> ccc506260293
Step 9/10 : COPY . .
---> c336b88dd79c
Step 10/10 : CMD ["flask", "run"]
---> Running in b67224eaff17
Removing intermediate container b67224eaff17
---> 2a0a01a5be7b
Successfully built 2a0a01a5be7b
Successfully tagged compose_test_web:latest
이미지는 어떤것이 있는지, 컨테이너는 잘 동작하는지 확인해보겠습니다.
터미널 창을 하나 켜서 아래 명령어로 잘 동작하고 있는지 확인하겠습니다. :)
먼저 이미지를 확인해봅니다.
[root@master compose_test]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
compose_test_web latest 2a0a01a5be7b 14 minutes ago 196MB
redis alpine bd71e6db4a54 3 weeks ago 32.2MB
python 3.7-alpine 295b051ee125 3 weeks ago 41.7MB
이제 컨테이너 목록을 확인해봅니다.
[root@master compose_test]# docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
18012056d099 compose_test_web "flask run" 14 minutes ago Up 14 minutes 0.0.0.0:5000->5000/tcp compose_test_web_1
05f968a0fc78 redis:alpine "docker-entrypoint.s…" 14 minutes ago Up 14 minutes 6379/tcp compose_test_redis_1
웹브라우저에서도 잘 동작하네요 ;)
6 . Compose 파일 수정해보기
이번에는, docker-compose.yml파일을 수정해보겠습니다. 9~12줄을 복사 붙여넣기 하세요 :)
[root@master compose_test]# vim docker-compose.yml
version: "3.8"
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
environment:
FLASK_ENV: development
redis:
image: "redis:alpine"
각 내용은 아래와 같습니다.
- volumes은 호스트의 현재 디렉토리를 컨테이너의 /code 디렉토리에 마운트하여 사용하겠다는 뜻입니다. 이렇게 하면 이미지를 다시 빌드하지 않고도 코드를 즉시 수정할 수 있습니다.
- envirenment는 FLASK_ENV 환경변수를 지정합니다. 개발자 모드에서 실행하며, 개발에서만 사용하도록 합니다.
아직, 컨테이너가 실행중이라면 ctrl+C 를 눌러 프로세스를 종료하고 다시한번 docker-compose up을 실행합니다.
[root@master compose_test]# docker-compose up
Recreating compose_test_web_1 ... done
Starting compose_test_redis_1 ... done
Attaching to compose_test_redis_1, compose_test_web_1
redis_1 | 1:C 05 Oct 2020 02:49:34.173 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_1 | 1:C 05 Oct 2020 02:49:34.173 # Redis version=6.0.8, bits=64, commit=00000000, modified=0, pid=1, just started
redis_1 | 1:C 05 Oct 2020 02:49:34.173 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
redis_1 | 1:M 05 Oct 2020 02:49:34.175 * Running mode=standalone, port=6379.
redis_1 | 1:M 05 Oct 2020 02:49:34.175 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
redis_1 | 1:M 05 Oct 2020 02:49:34.175 # Server initialized
redis_1 | 1:M 05 Oct 2020 02:49:34.176 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
redis_1 | 1:M 05 Oct 2020 02:49:34.176 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo madvise > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled (set to 'madvise' or 'never').
redis_1 | 1:M 05 Oct 2020 02:49:34.176 * Loading RDB produced by version 6.0.8
redis_1 | 1:M 05 Oct 2020 02:49:34.176 * RDB age 32 seconds
redis_1 | 1:M 05 Oct 2020 02:49:34.176 * RDB memory usage when created 0.79 Mb
redis_1 | 1:M 05 Oct 2020 02:49:34.176 * DB loaded from disk: 0.000 seconds
redis_1 | 1:M 05 Oct 2020 02:49:34.176 * Ready to accept connections
web_1 | * Serving Flask app "app.py" (lazy loading)
web_1 | * Environment: development
web_1 | * Debug mode: on
web_1 | * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
web_1 | * Restarting with stat
web_1 | * Debugger is active!
web_1 | * Debugger PIN: 171-548-060
7 . Application 수정하기
호스트의 디렉토리와 컨테이너의 /code 디렉토리가 공유되었으므로, 이미지를 다시 빌드하지 않고도 코드를 수정할 수 있습니다.
app.py를 수정하여 확인해보도록 하겠습니다. (맨 마지막 한줄만 바뀌었습니다)
[root@master compose_test]# vim app.py
import time
import redis
from flask import Flask
app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)
def get_hit_count():
retries = 5
while True:
try:
return cache.incr('hits')
except redis.exceptions.ConnectionError as exc:
if retries == 0:
raise exc
retries -= 1
time.sleep(0.5)
@app.route('/')
def hello():
count = get_hit_count()
# return 'Hello World! I have been seen {} times.\n'.format(count)
return 'Hello Docker?! I have been seen {} times.\n'.format(count)
다시 빌드할 필요없이, 정말 코드가 바로 반영이 됐습니다.
8 . 다른 명령어 사용해보기
백그라운드에서 실행하기위해서 -d 옵션을 넣어 실행하고, docker-compose ps 명령으로 상태를 확인해볼 수 있습니다.
[root@master compose_test]# docker-compose up -d
Starting compose_test_web_1 ... done
Starting compose_test_redis_1 ... done
잘 동작하는지 확인헤봅시다.
[root@master compose_test]# docker-compose ps
Name Command State Ports
--------------------------------------------------------------------------------------
compose_test_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp
compose_test_web_1 flask run Up 0.0.0.0:5000->5000/tcp
docker-compose run 명령어는 서비스에 대한 일회성 명령을 실행할 수 있습니다.
예를들어 docker-compuse run web env 명령으로 web서비스에서 사용할 수 있는 환경변수를 확인할 수 있습니다.
[root@master compose_test]# docker-compose run web env
Creating compose_test_web_run ... done
PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=6ff69d334701
TERM=xterm
FLASK_ENV=development
LANG=C.UTF-8
GPG_KEY=0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D
PYTHON_VERSION=3.7.9
PYTHON_PIP_VERSION=20.2.3
PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/fa7dc83944936bf09a0e4cb5d5ec852c0d256599/get-pip.py
PYTHON_GET_PIP_SHA256=6e0bb0a2c2533361d7f297ed547237caf1b7507f197835974c0dd7eba998c53c
FLASK_APP=app.py
FLASK_RUN_HOST=0.0.0.0
HOME=/root
docker-compose stop 명령어는 현재 compose로 운영중인 컨테이너를 중지합니다.
중지해봅시다 :)
[root@master compose_test]# docker-compose stop
Stopping compose_test_web_1 ... done
Stopping compose_test_redis_1 ... done
컨테이너의 상태를 확인해보면 Exited 입니다.
[root@master compose_test]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6ff69d334701 compose_test_web "env" 42 minutes ago Exited (0) 42 minutes ago compose_test_web_run_e394dfbcb003
9739bd2f069d compose_test_web "flask run" 58 minutes ago Exited (0) 26 seconds ago compose_test_web_1
05f968a0fc78 redis:alpine "docker-entrypoint.s…" 2 hours ago Exited (0) 26 seconds ago compose_test_redis_1
docker-compose down 명령어는 모든 컨테이너를 중단하고 삭제합니다. --volumes 옵션을 사용하면 도커 볼륨도 함께 삭제됩니다.
[root@master compose_test]# docker-compose down --volumes
Removing compose_test_web_run_e394dfbcb003 ... done
Removing compose_test_web_1 ... done
Removing compose_test_redis_1 ... done
Removing network compose_test_default
컨테이너 목록을 확인해보니 전부 잘 지워졌네요 :)
[root@master compose_test]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
이번 포스팅은 여기까지 입니다.
고생하셨습니다. 😊😊😊 뿅⭐️
참조 링크
www.44bits.io/ko/post/almost-perfect-development-environment-with-docker-and-docker-compose
docs.docker.com/compose/