🌱 Infra/Container_Docker

[Docker-Basic (11)] Docker Compuser 사용하기 :P

mini_world 2020. 10. 5. 10:59
목차 접기


 

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/
728x90