본문 바로가기

Backend/Docker, k8s

Docker Compose - tutorial

*목차

 - Intro

 - 1단계 : Application 종속성 정의

 - 2단계 : Dockerfile 생성

 - 3단계 : compose file에 service를 정의

 - 4단계 : compose build & run

 - 5단계 : compose수정, mount bind

 - 6단계 : compose로 re-build & run

 - 7단계 : application 최신화

 

 

* 환경은 EC2의 ubuntu으로 진행합니다. 아래 링크를 참조해 주세요

 

AWS - EC2 초 간단 생성 + vscode 원격연결 (2023년 version)

독립된 서버가 급히 필요한데 주변에 아무것도 없다면? Linux OS가 필요한 상황인데 집에 Windows만 있는 상황이라면? Docker를 windows 환경에서 또 새로 구축하긴 귀찮죠... 그럴 때는 EC2를 사용해 봅시

tyoon9781.tistory.com

 

* 사전 Docker 지식이 필요한 글입니다.

 

Docker - Tutorial

* 목차 - Docker Engine 설치 - Docker Image 제작 (flask) - Docker Image 실행 - Docker Image 배포 * 환경은 EC2의 ubuntu으로 진행합니다. 아래 링크를 참조해 주세요 [간단 정리] EC2 초 간단 생성 + vscode 원격연결 (202

tyoon9781.tistory.com


Intro

Dockerfile만으로는 부족한가?

이전 Tutorial에서는 Docker Engine 설치, Dockerfile로 image 설계, image build, image run으로 container 구현, 배포를 다뤄보았습니다. 그러면 이미 Dockerfile로도 충분히 Docker를 사용할 수 있을 것 같은데 왜 Docker Compose가 필요한 것일까요?

 

Docker Compose란?

Compose는 Multi Container Application을 정의하고 실행하기 위한 도구입니다. 이전에는 Flask로 간단하게 Web application server를 open 했지만 만약에 Nginx, gunicorn, Flask, DB가 각각 Docker image로 만들어지고 묶여야 한다면 어떻게 정의할 수 있을까요? 이런 경우 Dockerfile만으로는 관리하기 매우 어렵습니다. 그렇기에 Dockerfile의 상위 개념으로 docker-compose.yml를 통해 여러 image를 container화 하여 관리하게 됩니다.

 

 

Docker Compose 설치

위의 Tutorial을 진행하셨던 분이라면 이미 docker-compose-plugin을 설치하셨을 것입니다. 혹시 install이 안되신 분들은 설치해 줍시다.

sudo apt-get install docker-compose-plugin

 

설치가 되었는지 여부를 확인하시고 싶다면 아래와 같은 명령어를 검색 후 installed가 뜨는지 확인해 봅시다.

apt list --installed | grep docker-compose

 

위와 같이 docker-compose-plugin이 출력되어야 한다.

설치가 완료되었으면 시작합니다.

 


1단계 : Application 종속성 정의

이번 docker compose tutorial에서는 2가지의 image를 가지고 Test를 진행합니다.

 1. python기반 Web application Flask

 2. 조회수를 저장해 줄 데이터 저장소인 Redis

 

먼저 project의 directory를 만듭니다.

mkdir docker_compose_test
cd docker_compose_test

 

 

docker_compose_test에 app.py파일을 만들고 flask web 실행 code를 작성합니다.

import time

import redis
from flask import Flask

app = Flask(__name__)
cache = redis.Redis(host='redis_host', 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 f"hello World! I have been seen {count} times."

def main():
    app.run(host="0.0.0.0", port=5000)    


if __name__ == "__main__":
    main()

 

이 예제에서는 redis_host를 redis의 host name으로 정의했습니다. port는 6379입니다.

그리고 requirements.txt에는 사용된 python library를 작성합니다.

flask
redis

 

2단계 : Dockerfile 만들기

Dockerfile에는 python을 base으로 하여 flask service를 실행할 수 있도록 해보겠습니다.

## custom dockerfile syntax. latest stable release of the version 1 syntax
# syntax=docker/dockerfile:1

# python 3.7 저용량
FROM python:3.7-alpine

# work directory
WORKDIR /code

# gcc, 기타 종속성 설치
RUN apk add --no-cache gcc musl-dev linux-headers

# python library list 복사
COPY requirements.txt requirements.txt

# python library 설치
RUN pip install -r requirements.txt

# flask port 노출
EXPOSE 5000

# app.py 복사
COPY . .

# python flask 실행
CMD ["python", "app.py"]

 

3단계 : compose file에 service를 정의

docker-compose.yml파일을 만들고 내용을 작성합니다.

services:
  web:
    build: .
    ports:
      - "5000:5000"
  redis_host:
    image: "redis:alpine"

 

이 compose 파일은 service를 web과 redis를 정의합니다.

web은 현재 위치(".")에 있는 Dockerfile 내용으로 build 하고 port는 5000:5000으로 binding 합니다.

redis_host는 redis의 host명을 그대로 적었습니다.(다르면 동작하지 않습니다)

redis는 base image를 redis:alpine으로 가져갑니다.

 

docker-compose.yml file을 적는 규칙은 아래 docker compose spec 문서를 참조해 주세요

 

GitHub - compose-spec/compose-spec: The Compose specification

The Compose specification. Contribute to compose-spec/compose-spec development by creating an account on GitHub.

github.com

 

4단계 : compose build & run

현재 파일 tree는 다음과 같습니다.

 

docker compose up을 실행합니다.

sudo docker compose up

 

Dockerfile이나 docker-compose.yml 파일에 오타, 에러가 있다면 console창에 안 되는 이유에 대해서 설명해 줍니다. 특히 yml은 공백이 매우 중요하므로 잘 지켜주도록 합시다.

compose up 결과 flask가 실행되었음을 확인할 수 있다.

 

docker image가 2개가 추가 되었고 container도 2개가 추가 되었음을 확인할 수 있다.

 

7번정도 재접속 했더니 7 times라고 출력해준다.

 

docker compose down이나 "ctrl + C"를 입력해서 application을 종료할 수 있습니다. 다음단계를 위해 종료해 줍시다.

sudo docker compose down

 

docker compose application이 종료되었다.

 

5단계 : compose수정, mount bind

compose에서 volumes key를 사용하게 되면 container 내부에 코드를 수정하기 위해 다시 빌드할 필요 없이 즉시 코드를 수정할 수 있습니다.

services:
  web:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/code
    environment:
      FLASK_DEBUG: "true"
  redis_host:
    image: "redis:alpine"

 

volumes 키워드에서 현재폴더(".")와 container의 /code를 binding 했습니다. 이 /code라는 container의 path는 Dockerfile에 명시되어 있습니다.

# python 3.7 저용량
FROM python:3.7-alpine

# work directory
WORKDIR /code

 

추가로 environment에 FLASK_DEBUG를 true로 설정합니다.

 

6단계 : compose로 re-build & run

다시 docker compose를 재실행합니다.

sudo docker compose up

 

이번에는 debug mode가 on이 된 것을 확인해 볼 수 있습니다.

* Debug mode : on

 

7단계 : application 최신화

이번에는 application을 끄지 않은 상태에서 python file을 변경해 보도록 합시다.

hello() method의 return string을 다음과 같이 바꿔봅시다.

@app.route('/')
def hello():
    count = get_hit_count()
    return f"Hello Docker! I have been seen {count} times."

 

그리고 저장을 누르면 바로 application이 반응합니다.

python file을 저장만 해도 reloading이 동작한다.

 

Hello World에서 Hello Docker로 변경됐다.

 

* 마무리 단계 명령어 설명

만약 docker를 daemon으로 실행시키고 싶다면 -d 옵션을 사용하시면 됩니다.

sudo docker compose up -d

 

daemon으로 실행

 

daemon으로 돌아가고 있는 compose 목록을 보려면 docker compose ps를 입력하시면 됩니다.

sudo docker compose ps

 

docker ps와 docker compose ps는 서로 보여주는 것이 다르다.

 

만약 daemon으로 돌아가는 compose application을 멈추고 싶다면 docker compose stop을 입력하면 됩니다.

sudo docker compose stop

 

daemon으로 돌아가던 compose가 멈췄다.

 

binding 된 volume을 제거하려면 --volumns option을 활용하면 됩니다.

sudo docker compose down --volumes

 

혹시 volume이 어떻게 container와 mount되어 있었는지 확인하려면 docker inspect를 입력하면 됩니다.

sudo docker inspect {image} | grep Mounts -A9

 

Type은 binding, Source와 Destination이 명시되어 있다.

 

Type은 volume, Source와 Destination 중에 Source가 docker에서 자동으로 생성한 경로로 연결되어 있다.

 

docker가 생성한 volume의 list는 docker volumn ls를 입력하면 됩니다.

sudo docker volume ls

 

다양한 volume들이 나열되어 있다.

 

ee11180로 시작하는 volume명이 익숙합니다. 이제 docker compose down --volumes으로 저 volume이 사라지는지 확인해 보겠습니다.

sudo docker compose down --volumes

 

container 삭제가 완료됨을 확인할 수 있다.

 

ee11180으로 시작하는 volume도 사라졌음을 확인할 수 있다.

 

 

남아있는 volume은 아마도 기존에 container를 삭제하면서 같이 지워지지 않은 volume일 것입니다. 사용 중이지 않은 volume을 삭제하는 docker volume prune 명령어를 입력합니다.

sudo docker volume prune

 

남은 3개의 volume이 삭제되었음을 확인할 수 있다.

 

마치며...

사실 이번에는 docker compose 쉬운 예제를 다뤄보았습니다.

다음에는 DB + backend + frontend를 docker compose로 구성하는 예제를 다뤄보도록 하겠습니다.

 


* reference

https://github.com/compose-spec/compose-spec/blob/master/spec.md

https://docs.docker.com/compose/

https://docs.docker.com/compose/gettingstarted/

 

'Backend > Docker, k8s' 카테고리의 다른 글

Windows에서 Docker 설치  (0) 2024.02.11
Docker + Frontend(Nginx, React) + Backend(Nginx, Gunicorn, Django, PostgreSQL)  (7) 2023.06.20
Docker - Tutorial  (0) 2023.06.17
k8s - Service  (0) 2023.04.28
k8s - Pod  (0) 2023.04.27