[Docker] Docker compose ๊ฐœ๋…, ๋ฌธ๋ฒ•, ์˜ˆ์ œ

Docker Compose ๋ž€?

  • ์‘์ง‘๋ ฅ ์žˆ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์œผ๋กœ ํ•จ๊ป˜ ์ž‘๋™ํ•˜๋Š” ์—ฌ๋Ÿฌ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰ํ•˜๋ ค๋Š” ๋กœ์ปฌ ๊ฐœ๋ฐœ ๋ฐ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์„ ์œ„ํ•ด ์„ค๊ณ„๋œ ๋„๊ตฌ
  • docker compose yaml์ฝ”๋“œ๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ docker run ์‹คํ–‰๊ณผ ์œ ์‚ฌํ•˜๋ฉฐ ๋„คํŠธ์›Œํฌ, ๋ณผ๋ฅจ ๋“ฑ์„ ํ•œ๋ฒˆ์— ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
  • docker compose๋กœ ์ƒ์„ฑ๋œ ์ปจํ…Œ์ด๋„ˆ๋“ค์€ ๋…๋ฆฝ๋œ ๋„คํŠธ์›Œํฌ๋กœ ๊ตฌ์„ฑ๋˜๋ฏ€๋กœ ์ปจํ…Œ์ด๋„ˆ  ๊ฐ„ ํ†ต์‹ ์ด ์‰ฝ๋‹ค.
  • Docker file ์ž‘์„ฑ -> docker-compose.yml ์ž‘์„ฑ -> docker compose up
  • ์žฅ์ 
    • ์„œ๋กœ ๋‹ค๋ฅธ OSํ™˜๊ฒฝ์ด๋ผ๋„ ๋™์ผํ•œ ํ™˜๊ฒฝ๊ตฌ์„ฑ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. 
    • ๋™์ผํ•œ ํ™˜๊ฒฝ์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐœ๋ฐœํ™˜๊ฒฝ์— ์ด์Šˆ๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ํŒ€๊ฐ„ ์†Œํ†ต์ด ์‰ฝ๋‹ค.
    • ๋ณต์žกํ•œ ํ™˜๊ฒฝ๋„ YAML ์ฝ”๋“œ๋กœ ์Šคํฌ๋ฆฝํŠธํ™” ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ž๋™ํ™”๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.
    • docker compose CLI๋ฅผ ์ด์šฉํ•˜์—ฌ ์‰ฝ๊ฒŒ "๋ฉ€ํ‹ฐ ์ปจํ…Œ์ด๋„ˆ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜"์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋‹จ์ 
    • ๋™์‹œ์— ๋‹ค์ˆ˜์˜ ์ปจํ…Œ์ด๋„ˆ ์„œ๋น„์Šค๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ ์ž์› ํ™œ์šฉ๋ฅ ์ด ์ˆœ๊ฐ„ ๋†’์•„์งˆ ์ˆ˜ ์žˆ๋‹ค.

 

 

Docker compose ์™€ Kubernetes์˜ ์ฐจ์ด

etc-image-0

 

 

Docker compose ํŠน์ง•

  • docker compose๋Š” ์—ฌ๋Ÿฌ ๋ฒˆ์˜ docker cli๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ , ํ•œ๋ฒˆ์— ๊ด€๋ จ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๋“ค์„ YAMLํŒŒ์ผ๋กœ ๊ตฌ์„ฑํ•˜์—ฌ ๋‚ด๋ถ€ ํ™˜๊ฒฝ ๊ตฌ์„ฑ๊ณผ ์†์„ฑ์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์„ค์ • ๊ฐ’์„ ์บ์‹ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์žฌ์‹œ์ž‘ ์‹œ ๋ณ€๊ฒฝ์ด ์—†๋‹ค๋ฉด ์บ์‹ฑ๋œ ์ •๋ณด๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜์—ฌ ๋น ๋ฅธ ์„œ๋น„์Šค ์‹คํ–‰์„ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. 
  • YAML ์ฝ”๋“œ์— ํฌํ•จ๋œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๋“ค์€ ๋™์ผ ๋„คํŠธ์›Œํฌ์— ํฌํ•จ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋ณต์žกํ•œ ์—ฐ๊ฒฐ ๊ตฌ์„ฑ ์—†์ด๋„ ์‰ฝ๊ฒŒ API ํ†ต์‹ ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. 

 

 

์ž์ฃผ ์“ฐ๋Š” Docker compose ๋ฌธ๋ฒ•

build

mydiary-front: 
	build: 
		context: ./my-diary-front 	#Dockerfile ์œ„์น˜ (๋™์ผ ๊ฒฝ๋กœ๋ฉด ์ƒ๋žต ๊ฐ€๋Šฅ)
		dockerfile: Dockerfile 		#์ œ๊ณตํ•˜๋Š” Dockerfile ์ด๋ฆ„

container_name

  • ์ƒ๋žต ์‹œ ์ž๋™์œผ๋กœ ๋ถ€์—ฌ, "๋””๋ ‰ํ† ๋ฆฌ๋ช…_์„œ๋น„์Šค๋ช…_n"
  • docker run์˜ --name ์˜ต์…˜๊ณผ ๋™์ผ

 

ports

  • ์„œ๋น„์Šค ๋‚ด๋ถ€ ํฌํŠธ์™€ ์™ธ๋ถ€ ํ˜ธ์ŠคํŠธ ํฌํŠธ๋ฅผ ์ง€์ •ํ•˜์—ฌ ๋ฐ”์ธ๋“œ. ์™ธ๋ถ€ ๋…ธ์ถœ ํฌํŠธ ์ง€์ •
  • docker run์˜ -p ์˜ต์…˜๊ณผ ๋™์ผ

 

networks

  • ์ตœ์ƒ์œ„ ๋ ˆ๋ฒจ์˜ networks์— ์ •์˜๋œ ๋„คํŠธ์›Œํฌ ์ด๋ฆ„์„ ์ž‘์„ฑ
  • docker run์˜ --net(--network) ์˜ต์…˜๊ณผ ๋™์ผ

 

volumes

  • ์„œ๋น„์Šค ๋‚ด๋ถ€ ๋””๋ ‰ํ† ๋ฆฌ์™€ ํ˜ธ์ŠคํŠธ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์—ฐ๊ฒฐํ•˜์—ฌ ๋ฐ์ดํ„ฐ ์ง€์†์„ฑ ์„ค์ •.
  • docker run์˜ -v

 

environment

  • ์„œ๋น„์Šค ๋‚ด๋ถ€ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ •
  • ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ๋งŽ์€ ๊ฒฝ์šฐ, ํŒŒ์ผ (.env)๋กœ ๋งŒ๋“ค์–ด ์ง€์ • (env_file: ./envfile.env)

 

command

  • ์„œ๋น„์Šค๊ฐ€ ๊ตฌ๋™ ์ดํ›„ ์‹คํ–‰ํ•  ๋ช…๋ น์–ด ์ž‘์„ฑ
  • docker run์˜ ๋งˆ์ง€๋ง‰์— ์ž‘์„ฑ๋˜๋Š” ๋ช…๋ น์–ด

 

restart

  • ์„œ๋น„์Šค ์žฌ์‹œ์ž‘ ์˜ต์…˜ ์ง€์ •
  • docker run์˜ --restart ์˜ต์…˜๊ณผ ๋™์ผ

 

depends_on

  • ์„œ๋น„์Šค ๊ฐ„์˜ ์ข…์†์„ฑ์„ ์˜๋ฏธ.
  • ๋จผ์ € ์‹คํ–‰ํ•ด์•ผ ํ•˜๋Š” ์„œ๋น„์Šค๋ฅผ ์ง€์ •ํ•˜์—ฌ ์ˆœ์„œ ์ง€์ •

 

deploy.replicas

  • ํ•ด๋‹น ์„œ๋น„์Šค์˜ ๋ณต์ œ ์ปจํ…Œ์ด๋„ˆ ์ˆ˜ ์ง€์ •
  • replica๋ฅผ ์‚ฌ์šฉํ•  ๋• ์ปจํ…Œ์ด๋„ˆ ์ด๋ฆ„์„ ์ง€์ •ํ•˜๋ฉด ์•ˆ ๋œ๋‹ค. (์œ ์ผํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ)

 

 

 

์˜ˆ์‹œ1 Docker compose file [Nodejs+ Spring + MySQL + Nginx] 

etc-image-1

 

docker-compose.yml

version: '3.8'

services:
 mydiary-db:
  image: mysql:5.7-debian
  container_name: rolling-db
  environment:
   MYSQL_ROOT_PASSWORD: pass123
   MYSQL_DATABASE: paperdb
   MYSQL_ROOT_HOST: '%'
   MYSQL_USER: user
   MYSQL_PASSWORD: user
  ports:
   - '3306:3306'
  networks:
   - mydiary-net
  restart: always
  command:
   - --character-set-server=utf8
   - --collation-server=utf8_general_ci

 mydiary-back:
  build:
   context: ./my-diary-back
   dockerfile: Dockerfile
  deploy:
   replicas: 3
  restart: always
  depends_on:
   - mydiary-db
  ports:
   - '8081-8083:8080'
  environment:
   SPRING_DATASOURCE_URL: jdbc:mysql://rolling-db:3306/paperdb?serverTimezone=Asia/Seoul
   SPRING_DATASOURCE_USERNAME: user
   SPRING_DATASOURCE_PASSWORD: user
  networks:
   - mydiary-net

 mydiary-front:
  build:
   context: ./my-diary-front
   dockerfile: Dockerfile
  deploy:
   replicas: 3
  restart: always
  depends_on:
   - mydiary-back
  ports:
   - '3000-3002:3000'
  networks:
   - mydiary-net

 proxy-be:
  image: nginx:1.21.5-alpine
  container_name: rolling-server-lb
  restart: always
  depends_on:
   - mydiary-back
  ports:
   - '8080:80'
  volumes:
   - ${PWD}/proxy/nginx-be.conf:/etc/nginx/nginx.conf
  networks:
   - mydiary-net

 proxy-fe:
  image: nginx:1.21.5-alpine
  container_name: rolling-front-lb
  restart: always
  ports:
   - '80:80'
  volumes:
   - ${PWD}/proxy/nginx-fe.conf:/etc/nginx/nginx.conf
  networks:
   - mydiary-net

networks:
 mydiary-net:
  driver: bridge
  ipam:
   driver: default
   config:
   - subnet: 172.20.0.0/24
     ip_range: 172.20.0.0/24
     gateway: 172.20.0.1

 

Nginx backend conf

  • ์œ„์—์„œ ์„ค์ •ํ•œ ๋ฐฑ์—”๋“œ ์ปจํ…Œ์ด๋„ˆ service name์ธ  "mydiray-back" ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.
  • ํ”„๋ก ํŠธ์—์„œ ํŠธ๋ž˜ํ”ฝ์„ ์ „๋‹ฌ๋ฐ›์„ ๋•Œ mydiary-back์—๋‹ค ํ•˜๋‚˜์”ฉ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ. 
events { worker_connections 1024; }
http{
    upstream mydiary-back { # upstream์˜ ์ด๋ฆ„์„ rolling-server๋กœ ์„ค์ •
    server mydiary-back:8081;
    server mydiary-back:8082;
    server mydiary-back:8083;
    }
    server {
            listen *:8080 default_server; # ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์š”์ฒญํ•˜๋Š” ํฌํŠธ ๋ฒˆํ˜ธ
    location / {
            proxy_pass http://mydiary-back; # ์„ค์ •ํ•œ upstream์œผ๋กœ ์š”์ฒญ ๋ณด๋‚ด๊ธฐ
            }
    }
}

 

Nginx front conf

events { worker_connections 1024; }
http {
    upstream front-servers {
        server mydiary-front:3000;
        server mydiary-front:3001;
        server mydiary-front:3002;
    }
    server {
        listen 80 default_server;
        location / {
            proxy_pass http://front-servers;
        }
    }
}

 

 

 

 

์˜ˆ์‹œ2 Docker compose file [Spring+ MariaDB + Redis] 

MariaDB

  • /database/Dockerfile
FROM mariadb:10

ENV TZ=Asia/Seoul
  • /database/config/mariadb.cnf
[client]
default-character-set=utf8mb4

[mysql]
default-character-set=utf8mb4

[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
skip-character-set-client-handshake

[mysqldump]
default-character-set=utf8mb4

 

Redis

  • /redis/Dockerfile
FROM redis:6

ENV TZ=Asia/Seoul

 

Spring

  • ./Dockerfile
FROM openjdk:11
ARG JAR_FILE=build/libs/app.jar
COPY ${JAR_FILE} ./app.jar
ENV TZ=Asia/Seoul
ENTRYPOINT ["java", "-jar", "./app.jar"]

 

docker-compose.yml

  • ./docker-compose.yml
version: "3.8"                                          # ํŒŒ์ผ ๊ทœ๊ฒฉ ๋ฒ„์ „
services:                                               # ์ด ํ•ญ๋ชฉ ๋ฐ‘์— ์‹คํ–‰ํ•˜๋ ค๋Š” ์ปจํ…Œ์ด๋„ˆ๋“ค์„ ์ •์˜
  pharmacy-recommendation-redis:                        # ์„œ๋น„์Šค๋ช…
    container_name: pharmacy-recommendation-redis       # ์ปจํ…Œ์ด๋„ˆ ๋ช…
    build:
      dockerfile: Dockerfile
      context: ./redis
    image: dgjinsu/pharmacy-recommendation-redis
    ports:
      - "6380:6379"
  pharmacy-recommendation-database:
    container_name: pharmacy-recommendation-database
    build:
      dockerfile: Dockerfile
      context: ./database
    image: dgjinsu/pharmacy-recommendation-database
    environment:
      - MARIADB_DATABASE=pharmacy-recommendation
      - MARIADB_ROOT_PASSWORD=${SPRING_DATASOURCE_PASSWORD}
    volumes:
      - ./database/config:/etc/mysql/conf.d
      - ./database/init:/docker-entrypoint-initdb.d
    ports:
      - "3307:3306"      # ์ ‘๊ทผ ํฌํŠธ ์„ค์ • (์ปจํ…Œ์ด๋„ˆ ์™ธ๋ถ€:์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€)
  pharmacy-recommendation-app:
    container_name: pharmacy-recommendation-app
    build: .
    depends_on:          # DB, REDIS ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์‹คํ–‰๋œ ๋‹ค์Œ WEB์„ ์‹คํ–‰์‹œํ‚จ๋‹ค.
      - pharmacy-recommendation-database
      - pharmacy-recommendation-redis
    image: dgjinsu/pharmacy-recommendation-app
    environment:
      - SPRING_DATASOURCE_USERNAME=${SPRING_DATASOURCE_USERNAME}
      - SPRING_DATASOURCE_PASSWORD=${SPRING_DATASOURCE_PASSWORD}
      - SPRING_PROFILES_ACTIVE=${SPRING_PROFILES_ACTIVE}
      - KAKAO_REST_API_KEY=${KAKAO_REST_API_KEY}
    ports:
      - "80:8080"
    restart: always # depends on์€ ์‹คํ–‰ ์ˆœ์„œ๋งŒ ์ปจํŠธ๋กค ํ• ๋ฟ,
      # ์ปจํ…Œ์ด๋„ˆ ์•ˆ์˜ ์„œ๋น„์Šค๊ฐ€ ์‹คํ–‰๊ฐ€๋Šฅํ•œ ์ƒํƒœ์ธ์ง€๊นŒ์ง€๋Š” ํ™•์ธ ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—
    # DB ๋˜๋Š” Redis๊ฐ€ ์•„์ง ์‹คํ–‰๊ฐ€๋Šฅํ•œ ์ƒํƒœ๊ฐ€ ์•„๋‹ˆ์—ฌ์„œ ์‹คํŒจํ•˜๋Š” ๊ฒฝ์šฐ ์žฌ์‹œ์ž‘ ํ•˜๋„๋ก ์„ค์ •