터칭 데이터

Docker-Compose로 다수의 Container 프로그램 실행하기 (실습) 본문

Docker & K8S

Docker-Compose로 다수의 Container 프로그램 실행하기 (실습)

터칭 데이터 2023. 12. 21. 17:42

 

 

 

앞서 매뉴얼하게 실행해본 voting application를 docker-compose를 통해 실행해보자

 

1. Docker 명령 정리와 2장 퀴즈


2. Docker Volume이란?


3. 다수의 Container로 구성된 소프트웨어 실행


4. Docker-Compose로 다수 Container로 실행해보기


5. Airflow Docker docker-compose.yml 리뷰

 

지난 시간 voting application을 메뉴얼하게 구성하는 실습으로 1~3번을 진행했습니다.

 

이번에는 같은 프로그램을 docker-compose 방식으로 실습하며 4번 과정을 진행하겠습니다.

 

 

 

 

 

 

 

 

 

데모(실습) - 사전 준비

 

1. git clone https://github.com/learndataeng/example-voting-app.git

주의) https://github.com/dockersamples/example-voting-app 와는 다른 repo입니다.

위는 example-voting-app의 원본이고 우리가 데모를 진행할 repo는 원본을 fork한 멘토님의 repo입니다.

 

2. cd example-voting-app

 

3. 먼저 청소 한번 하기

docker container rm -f $(docker container ls -aq)
docker image rm -f $(docker image ls -q)

 

4. 확인해보기

docker ps -a
docker images

 

5. 그리고나서 앞의 docker-compose.mac.yml의 내용을 바탕으로 실행해보기

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1. git clone https://github.com/learndataeng/example-voting-app.git

 

 

 

실습을 진행할 적당한 디렉토리로 이동합니다.

 

저는 D드라이브의 Dev_KDT에 voting-app_dc라는 디렉토리를 만들고 이곳에 git clone과 기타 docker-compose 관련 실습을 진행하겠습니다.

 

 

 

 

터미널에서 위의 폴더로 이동한 후에 git clone 합니다.

 

 

git clone https://github.com/learndataeng/example-voting-app.git

PS D:\Dev_KDT\voting-app_dc> git clone https://github.com/learndataeng/example-voting-app.git
Cloning into 'example-voting-app'...
remote: Enumerating objects: 1087, done.
remote: Total 1087 (delta 0), reused 0 (delta 0), pack-reused 1087
Receiving objects: 100% (1087/1087), 1.14 MiB | 12.57 MiB/s, done.
Resolving deltas: 100% (407/407), done.

 

 

 

 

 

 

 

 

 

 

 

 

2. cd example-voting-app

 

clone된 repository로 이동합니다.

PS D:\Dev_KDT\voting-app_dc> cd example-voting-app
PS D:\Dev_KDT\voting-app_dc\example-voting-app>

 

 

 

 

 

 

 

 

 

 

 

3. 먼저 컨테이너와 이미지들 청소 한번 하기

 

컨테이너를 먼저 중지하고 삭제해야 이미지들도 삭제할 수 있다고 했습니다.

 

컨테이너 정리

docker ps로 컨테이너 ID들 조회 후

 

맥(Mac): docker container rm -f $(docker container ls -aq)

윈도우(Windows): docker container ls -aq | ForEach-Object { docker container rm -f $_ }

 

맥&윈도우: docker container rm -f (worker, result, vote, postgres, redis 컨테이너 ID들 공백으로 구분하여 나열)

 

 

 

 

이미지 정리

docker images로 이미지 ID들 조회 후

 

맥(Mac): docker image -f rm $(docker image ls -q)

윈도우(Windows): docker image ls -q | ForEach-Object { docker image rm -f $_ }

 

맥&윈도우: docker image rm -f (worker, result, vote, postgres, redis 이미지 ID들 공백으로 구분하여 나열)

 

 

 

 

 

 

 

 

 

 

4. 확인해보기

 

docker ps -a

남은 Container가 있는지 확인 -a옵션을 붙이면 실행여부와 관계없이 모든 컨테이너를 조회 가능합니다.

 

docker images

남은 이미지가 있는지 확인

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

5. 그리고나서 앞의 docker-compose.mac.yml의 내용을 바탕으로 실행해보기

 

이제 docker-compose 명령으로 docker-compose.yml 파일을 이용해 실행하려 합니다.

 

그런데 여기서 잠깐 우리가 git clone으로 받은 repo를 보시면

 

 

위와 같이 yml 파일들이 여러개 존재합니다. 

 

 

기본형태인 docker compose 명령은 아래의

docker-compose.yaml 혹은 docker-compose.yml 둘 중의 하나의 파일을 찾습니다.

만일 둘 이상이 존재하면 에러가 발생합니다.


여러 yaml 파일 중에서 특정(다른) 이름의 파일을 사용하고 싶다면 -f 옵션을 사용한다고 말씀드렸습니다.

 

우리가 사용할 yml 파일은 docker-compose.mac.yml 파일입니다.

그러므로 입력해야 할 명령어는 docker compose가 아닌 docker-compose -f docker-compose.mac.yml입니다.

 

docker-compose.mac.yml

# v2 and v3 are now combined!
# docker-compose v1.27+ required
# % docker-compose version
# Docker Compose version v2.15.1
services:
  vote:
    build: ./vote
    # use python rather than gunicorn for local dev
    command: python app.py
    ports:
      - "5001:80"

  result:
    build: ./result
    # use nodemon rather than node for local dev
    entrypoint: nodemon server.js
    ports:
      - "5002:80"

  worker:
    build: ./worker

  redis:
    image: redis:alpine

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: "postgres"
      POSTGRES_PASSWORD: "postgres"

 

일단은 vote, result, worker service(container)에 build가 적혀있고 이 3개의 각 디렉토리에 존재하는 Dockerfile을 우선 빌드 해보기 위해 docker-compose -f docker-compose.mac.yml build를 진행하겠습니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

docker-compose build

 

up과 build의 차이

up은 build, create, start 모든 것을 실행하고

build는 말 그대로 이미지를 빌드하기만 합니다.

 

 

 

 

result, vote, worker 이미지 bulid

 

docker-compose -f docker-compose.mac.yml build

PS D:\Dev_KDT\voting-app_dc\example-voting-app> docker-compose -f docker-compose.mac.yml build
(생략..)

 

설치가 끝난 뒤에는

 

 

 

 

 

 

docker images

 

PS D:\Dev_KDT\voting-app_dc\example-voting-app> docker images
REPOSITORY                  TAG       IMAGE ID       CREATED          SIZE
example-voting-app-result   latest    b19f347ce056   22 seconds ago   220MB
example-voting-app-vote     latest    e28691242d22   25 seconds ago   145MB
example-voting-app-worker   latest    8e029549f930   24 hours ago     194MB

 

docker images로 이미지들을 조회해보니 yml 파일이 존재하던 디렉토리 이름 example-voting-app이 prefix로 접두사가 되어 container(services)에 붙어 있는 것을 보실 수 있습니다.

 

Official Image를 사용하는 postgres와 redis는 없는데 이는 이 둘은 build로 Dockerfile을 사용하지 않고 Docker Hub에서 공식 이미지를 pull해서 사용하기 때문에 docker-compose.yaml build 의 명령을 듣지 않기 때문입니다.

 

이를 보여드리려고 build를 우선 해보았습니다.

 

 

 

 

 

 

 

 

postgres와 redis(db) 이미지 pull하기

 

 

 

docker-compose -f docker-compose.mac.yml pull

PS D:\Dev_KDT\voting-app_dc\example-voting-app> docker-compose -f docker-compose.mac.yml pull
(생략..)

 

이제 pull 옵션으로 postgres(db)와 redis Image를 다운 받겠습니다.

 

 

 

 

 

PS D:\Dev_KDT\voting-app_dc\example-voting-app> docker images
REPOSITORY                  TAG         IMAGE ID       CREATED         SIZE
example-voting-app-result   latest      b19f347ce056   9 minutes ago   220MB
example-voting-app-vote     latest      e28691242d22   9 minutes ago   145MB
example-voting-app-worker   latest      8e029549f930   24 hours ago    194MB
postgres                    15-alpine   c94362bdb5ee   7 days ago      240MB
redis                       alpine      d2d4688fcebe   13 days ago     41MB

 

docker images로 이제는 5개 모든 이미지가 다운 받아졌습니다.

 

postgres와 redis는 prefix가 없군요.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

docker-compose up

다시 한번 더 up에 대해 설명드리면

 

 

1. 이미지가 없다면 Dockerfile을 사용하면 build, Official Image가 있다면 pull로 다운

 

2. 컨테이너들을 create

 

3. 컨테이너들을 실행하는 start

 

 

build(pull), create, start 3가지를 한번에 실행하는 유용한 기능입니다.

 

 

 

 

 

 

docker-compose -f docker-compose.mac.yml up

PS D:\Dev_KDT\voting-app_dc\example-voting-app> docker-compose -f docker-compose.mac.yml up
(생략..)
example-voting-app-worker-1  | Connected to db
example-voting-app-worker-1  | Connecting to redis
example-voting-app-worker-1  | Found redis at 172.21.0.4
example-voting-app-result-1  | Connected to db

 

up을 실행했습니다.

 

이제 브라우저에서 vote와 result 앱을 살펴보겠습니다.

 

 

 

 

 

 

 

 

 

 

 

 

실행이 잘 되는지 확인하기

 

 

 

왼쪽은 투표를 하는 voting 앱 (포트 5001)

오른쪽은 투표 결과를 보여주는 result 앱 (포트 5002)입니다.

 

현재 투표를 진행하지 않아 우측하단에 no votes yet이 떠있고 50:50이군요

 

 

 

 

 

 

 

이 상황에서 투표로 DOGS를 선택하니 오른쪽 result에 결과가 실시간으로 반영되는 것을 보실 수 있습니다.

우측 하단의 No votes yet도 방금 제가 행사한 1표를 계산해 1vote로 바뀌어 있습니다.

 

좌측에서 DOGS 투표를 CATS로 바꾸어도 실시간으로 반영됩니다.

 

 

지난 시간 메뉴얼하게 voting application 프로그램을 구현했을 때보다 docker-compose를 사용하는 것이 설치, 실행, 기능 모든 면에서 더 간단하고 확실합니다.

 

 

 

 

 

 

 

 

 

 

 

더 보완해야 할 부분들

 

그런데 voting-application이 정상적으로 동작하는 것 같지만 아직 불완전한 상태입니다.

 

보완해야 할 부분들이 몇가지 존재하는데

 

 

 

 

첫번째, 의존성

먼저 서비스들간의 의존성(dependency)도 제대로 걸려있지 않은데

 

 

voting-app이 동작하려면 redis가 먼저 정상 작동하고 있어야 하고

 

result는 PostgreSQL이 제대로 작동하고 있어야 합니다.

 

이런 의존성들을 확실히 잡아주어야 합니다.

 

 

 

 

 

두번째, Volume과 Data Persistency

또 PostgreSQL에 담긴 데이터들이 Docker Volume으로 제대로 Data Persistency가 보장되도록해야 db로서 더욱 안정적인 상태가 될 수 있습니다.

 

 

 

세번째, 네트워크 분리

네트워크야 docker-compose 자체적으로 5개의 서비스들을 default network로 묶어주어 별다른 세팅없이 돌아가기는 합니다만 사실은 back-end(redis, db, worker)와 front-end(voting, result)로 분리하는 것이 더 권장됩니다.

 

그래야 앱 사용자는 프론트 엔드에만 접근 가능해 보안이 더 강화되기 때문입니다.

 

 

 

이후에 과정에서 위의 문제들을 보완하며 학습을 진행해겠습니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

PostgreSQL db와 환경변수

 

일단 지금 실시한 데모를 마무리하기 전에 Postgres 연결을 위해 지정한 환경변수가 어떻게 그리고 제대로 역할을 하고 있는지 하나만 확인해보겠습니다.

 

 

 

docker-compose.mac.yml

# v2 and v3 are now combined!
# docker-compose v1.27+ required
# % docker-compose version
# Docker Compose version v2.15.1
services:
  vote:
    build: ./vote
    # use python rather than gunicorn for local dev
    command: python app.py
    ports:
      - "5001:80"

  result:
    build: ./result
    # use nodemon rather than node for local dev
    entrypoint: nodemon server.js
    ports:
      - "5002:80"

  worker:
    build: ./worker

  redis:
    image: redis:alpine

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: "postgres"
      POSTGRES_PASSWORD: "postgres"

 

 

 

 

 

 

 

 

 

 

 

 

 

 

docker ps와 docker-compose ps

PS D:\dev_kdt\voting-app_dc\example-voting-app> docker ps
CONTAINER ID   IMAGE                       COMMAND                   CREATED          STATUS          PORTS                  NAMES
3585c3c0975e   example-voting-app-vote     "python app.py"           35 minutes ago   Up 35 minutes   0.0.0.0:5001->80/tcp   example-voting-app-vote-1
eb4feb2f0acf   postgres:15-alpine          "docker-entrypoint.s…"   35 minutes ago   Up 35 minutes   5432/tcp               example-voting-app-db-1
405e4c78049a   redis:alpine                "docker-entrypoint.s…"   35 minutes ago   Up 35 minutes   6379/tcp               example-voting-app-redis-1
fd4b370081a8   example-voting-app-worker   "dotnet Worker.dll"       35 minutes ago   Up 35 minutes                          example-voting-app-worker-1
162ed1e3e3fc   example-voting-app-result   "nodemon server.js"       35 minutes ago   Up 35 minutes   0.0.0.0:5002->80/tcp   example-voting-app-result-1


PS D:\dev_kdt\voting-app_dc\example-voting-app> docker-compose ps
NAME                          IMAGE                       COMMAND                   SERVICE   CREATED          STATUS          PORTS
example-voting-app-db-1       postgres:15-alpine          "docker-entrypoint.s…"   db        35 minutes ago   Up 35 minutes   5432/tcp
example-voting-app-redis-1    redis:alpine                "docker-entrypoint.s…"   redis     35 minutes ago   Up 35 minutes   6379/tcp
example-voting-app-result-1   example-voting-app-result   "nodemon server.js"       result    35 minutes ago   Up 35 minutes   0.0.0.0:5002->80/tcp
example-voting-app-vote-1     example-voting-app-vote     "python app.py"           vote      35 minutes ago   Up 35 minutes   0.0.0.0:5001->80/tcp
example-voting-app-worker-1   example-voting-app-worker   "dotnet Worker.dll"       worker    35 minutes ago   Up 35 minutes

 

docker ps는 실행 중인 컨테이너들을, docker-compose ps는 docker-compose로 실행 중인 컨테이너들을 그룹핑해 보여줍니다.

 

우리가 postgreSQL에 interactive하게 로그인하는데 필요한 db의 ID example-voting-app-db-1이 보입니다.

 

 

 

 

 

docker exec -it --user=postgres example-voting-app-db-1 sh

PS D:\dev_kdt\voting-app_dc\example-voting-app> docker exec -it --user=postgres example-voting-app-db-1 sh

 

postgres 유저로 로그인 합니다.

 

 

 

 

 

 

/ $ whoami
postgres

/ $ psql
psql (15.5)
Type "help" for help.


postgres=# \c
You are now connected to database "postgres" as user "postgres".


postgres=# \dt
         List of relations
 Schema | Name  | Type  |  Owner
--------+-------+-------+----------
 public | votes | table | postgres
(1 row)

 

리눅스 커맨드에 whoami로 postgres로 로그인한 것을 확인할 수 있고

 

psql로 postgres shell을 실행했습니다.

 

\c 명령으로 postgres라는 database에 postgres 유저로 연결되었다는 것을 확인했습니다.

 

\dt로 postgres DB에 어떤 테이블들이 있는지 확인할 수 있습니다.

public이라는 스키마 아래에 votes라는 테이블이 있는 모습입니다.

 

 

 

 

 

 

postgres=# SELECT * FROM VOTES;
       id        | vote
-----------------+------
 1234567abcdefgh | b
 
(1 row)

 

votes 테이블 내용을 보니 제가 실습 때 투표를 했던 브라우저의 id와 DOGS에 투표했다는 vote b가 보입니다. CATS에 투표 했다면 vote가 a로 표시될 겁니다.

 

이제 exit으로 example-voting-app까지 나오겠습니다.

 

 

 

 

 

 

 

Docker Container들을 셧다운 해보겠습니다.

 

docker-compose down를 사용하겠습니다.

Container들을 중지하고 삭제하는 편리한 기능입니다. 단 Image는 로컬에 계속 남아있습니다.

그런데 우리가 디폴트 형태의 docker-compose.yaml이 아닌 docker-compose.mac.yaml을 사용했으므로

번거롭지만 -f옵션을 사용하겠습니다.

 

 

 

docker-compose -f docker-compose.mac.yml down

PS D:\dev_kdt\voting-app_dc\example-voting-app> docker-compose -f docker-compose.mac.yml down
[+] Running 1/5
[+] Running 2/5xample-voting-app-result-1  Removed                                                                  1.0s
 ✔ Container example-voting-app-result-1  Removed                                                                  1.0s[+] Running 3/5ample-voting-app-db-1      Stopping                                                                 1.1s
 ✔ Container example-voting-app-result-1  Removed                                                                  1.0s - Container example-voting-app-vote-1    Stopping                                                                 1.2s
[+] Running 3/5ample-voting-app-db-1      Stopping                                                                 1.3s
 ✔ Container example-voting-app-result-1  Removed                                                                  1.0s
[+] Running 4/5ample-voting-app-db-1      Stopping                                                                 1.4s
 ✔ Container example-voting-app-result-1  Removed                                                                  1.0s
 - Container example-voting-app-db-1      Stopping                                                                 1.5s
[+] Running 5/5xample-voting-app-vote-1    Removed                                                                  1.3s
 ✔ Container example-voting-app-result-1  Removed                                                                  1.0s ✔ Container example-voting-app-worker-1  Removed                                                                  1.4s
 ✔ Container example-voting-app-db-1      Removed                                                                  1.5s ✔ Container example-voting-app-redis-1   Removed                                                                  1.2s
[+] Running 5/6xample-voting-app-vote-1    Removed                                                                  1.3s
 ✔ Container example-voting-app-result-1  Removed                                                                  1.0s ✔ Container example-voting-app-worker-1  Removed                                                                  1.4s
 ✔ Container example-voting-app-db-1      Removed                                                                  1.5s ✔ Container example-voting-app-redis-1   Removed                                                                  1.2s
[+] Running 5/6xample-voting-app-vote-1    Removed                                                                  1.3s
 ✔ Container example-voting-app-result-1  Removed                                                                  1.0s ✔ Container example-voting-app-worker-1  Removed                                                                  1.4s
 ✔ Container example-voting-app-db-1      Removed                                                                  1.5s ✔ Container example-voting-app-redis-1   Removed                                                                  1.2s
[+] Running 6/6xample-voting-app-vote-1    Removed                                                                  1.3s
 ✔ Container example-voting-app-result-1  Removed                                                                  1.0s ✔ Container example-voting-app-worker-1  Removed                                                                  1.4s
 ✔ Container example-voting-app-db-1      Removed                                                                  1.5s ✔ Container example-voting-app-redis-1   Removed                                                                  1.2s
 ✔ Container example-voting-app-vote-1    Removed                                                                  1.3s - Network example-voting-app_default     Removing                                                                 0.3s
 ✔ Container example-voting-app-worker-1  Removed                                                                  1.4s
 ✔ Container example-voting-app-redis-1   Removed                                                                  1.2s
 ✔ Network example-voting-app_default     Removed

 

5개의 컨테이너가 제거되었고 맨 아래줄을 보시면 5개의 컨테이너들이 공용으로 사용하던 default 네트워크 역시 삭제되었습니다.

 

 

 

 

 

 

 

 

 

 

 

 

숙제

 

앞서 내용을 다 따라한 후 아래처럼 본인 컴퓨터에서 vote와 result 앱을 실행한 결과의 스크린샷을 공유 (아래 참조)