본문 바로가기
개인공부

Dockerfile, Docker-compose 특징 및 차이

by 리승우 2023. 4. 18.

실제 사용예시 (핵심만 보기용도)

  1. docker-compose를 사용할만한 상황으로, multimodule 환경을 구성해보았다.

Multimodule(루트 프로젝트)

- api-other (모듈)

- api_center (모듈)

- api_common (모듈)

 

여기서 나는 이미지를 찍고 컨테이너화 하고싶은 모듈이 api-other와 api_center이다.

2. 컨테이너화 하고싶은 모듈인 api-other와 api_center 모듈 안에 각각 Dockerfile을 생성한다

 

현재 api-other와 api_center의 application 내용은 아래와 같다

  • api-other
package com.example.apiother;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@SpringBootApplication
public class ApiOtherApplication {

    @GetMapping("/")
    public String show() {
        return "api-other 모듈 노출내용";
    }

    public static void main(String[] args) {
        SpringApplication.run(ApiOtherApplication.class, args);
    }
}
  • api_center

*현재 module 연동을 해놓은 것이여서 아래와 코드가 있으나, 해당 HTTP method로 접근하게 되면 "Common 모듈을 연동하여 Center에서 출력" 문구가 출력됨

package com.center.module.controller;

import com.center.module.ExService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RestController
public class ExController {

    private final ExService exService;

    @GetMapping("/")
    public String selectName(){
        return exService.selectName();
    }
}

 

3. 이전에 생성했던 Dockerfile 2개를 관리하기 용이하게, 루트 프로젝트 단위에 docker-compose.yml 파일 생성

 

전체 코드는 아래와 같다

# 버전 정의, 버전마다 지원하는 형식이 다름
version: '3.8'

# docker-compose로 생성할 container의 옵션을 정의
services:
  api-other:

#  docker-compose build 옵션에서 사용되는 build 옵션을 기재
    build:
      # Dockerfile의 위치를 파악 후 지정
      context: ./api-other
      # Dockerfile 이름 파악 후 지정
      dockerfile: Dockerfile

    # 저장할 컨테이너 이름 지정
    container_name: api-other
    # 컨테이너 내부에서 구동하는 애플리케이션은 8080포트 (오른쪽)을 사용하고 있음
    # 아래와 같이 포트포워딩을 함으로써, 호스트에서 8080포트 (왼쪽)으로 들어오는 요청은 컨테이너 내부 8080포트 (오른쪽)으로 전달됨
    # 이로써 호스트 컴퓨터와 컨테이너간에 통신이 가능해지며, 컨테이너 내부의 애플리케이션에 접근할 수 있게됨
    ports:
      - "8080:8080"

  # 이하 동일함
  api-center:
    build:
      context: ./api_center
      dockerfile: Dockerfile
    container_name: api-center
    ports:
      - "8081:8080"

추가정보

  • 서로 다른 호스트 포트를 지정하는 이유가 뭘까?
    여러 개의 컨테이너를 호스트에서 실행할 때 포트 충돌을 피하기 위해서 서로 다른 포트를 지정하는 것!!!

아래와 같이 작성해야 두 개의 서비스를 포트 충돌없이 동시에 실행할 수 있습니다.

version: '3.8' 
services: 
	service1: 
    	image: my-image1 
        container_name: my-service1 
        ports: 
        	- "8001:80" 
            
    service2: 
    	image: my-image2 
        container_name: my-service2 
        ports: 
        	- "8002:80"

4. 위에 언급되었던 docker-compose 명령문을 통해 이미지 생성 및 실행을 진행!!!

  • docker-compose up -d 명령문 실행

도커 이미지 생성 및 실행이 모두 완료됨.

 

5. 정상작동 되는지 확인
    아주 좋습니다



도커를 공부하다보니 궁금한 점이 생겼다. 원하는 어플리케이션을 도커에 띄울 때 

dockerFile 을 사용하기도 하고 docker-compose.yml 을 사용하기도 한다.

왜 둘이 분리해놓은 것일까? 다른 점은 무엇일까?

Dockerfile

  • Dockerfile은 DockerImage를 생성하기 위한 스크립트(설정파일)
  • base image 파일로 수정된 image 만드는 일련의 과정들을 정리해 놓은 파일
  • 여러가지 명령어를 토대로 Dockerfile을 작성한 후 빌드하면 Docker는 Dockerfile에 나열된 명령문을 차례대로 수행하며 DockerImage를 생성
    ⇒ Dockerfile을 읽을 줄 안다는 것은 해당 이미지가 어떻게 구성되어 있는지 알 수 있다는 의미

→ Dockerfile : 이미지를 어셈블하기 위해 호출할 수 있는 명령이 포함된 간단한 텍스트 파일

즉, base image 파일로부터 수정된 image를 만드는 일련의 과정들을 정리해 놓은 파일이며, docker는 이 Dockerfile을 이용해 손쉽게 바로 동일한 이미지를 반복적으로 생성할 수 있다.

Dockerfile의 장점

  • (1) 이미지가 어떻게 만들어졌는지를 기록한다.
    • 보통 사람들은 완성된 이미지를 가져다 쓰기 때문에 이미지가 어떻게 만들어졌는지에 대해서는 알 필요가 없다. 그러나 개발자의 경우라면 조금 다르다. 어떠한 애플리케이션을 담고 있는 이미지가 설치 되기 위한 과정은 어떠한지, 중간에 어떠한 과정을 수정해야 하는지 등을 알아야 하는 경우가 있다.
    예를 들어 raw한 상태의 우분투 이미지에서 자신이 원하는 애플리케이션을 담은 이미지를 만들어내기까지, 그 과정들을 기록하고 수정하며 바꿔나갈 수 있다는 것이다.
  • 이는 Dockerfile이 자동화된 스크립트 형태이기 때문이다.
  • (2) 배포에 용이하다.
    • 어떠한 이미지를 배포할 때, 몇 기가씩이나 되는 이미지 파일 자체를 배포하기보다는 그 이미지를 만들 수 있는 스크립트인 Dockerfile만을 배포한다면 매우 편리할 것이다.
    • 사용자는 그 스크립트를 실행시키기만 하면 스스로가 그 Dockerfile에 해당하는 이미지를 얻을 수 있기 때문이다.
    • 실제로 Docker Hub에 가면, Dockerfile로 이미지를 배포하고 있는 사람들을 심심찮게 볼 수 있다. 물론 이미지로 배포하는 사람도 있지만.
  • (3) 컨테이너(이미지)가 특정 행동을 수행하도록 한다.
    • 컨테이너 환경에서 애플리케이션을 개발하다 보면, 특정 행동을 취하도록 하는 컨테이너를(이미지를) 만들어야 할 때가 있다.
    • 이는 사실 말로서 설명하기는 좀 어렵고, 실제 개발을 하다보면 '아, 이거 Dockerfile 쓰면 좀 간단해 지겠구나...' 라는 생각이 머릿속에서 불현듯 번개처럼 스칠때가 있다.

여기까지 Dockerfile을 통한 이미지 생성방식이다.

하지만 이런 식으로 이미지를 만들 시에는 통상 아래와 같이 작업이 진행될 것이다.

  1. 애플리케이션 build를 통해 jar 혹은 war 파일 만듦
  2. Dockerfile을 통하여 원하는 베이스 이미지에 빌드된 결과물을 저장
  3. 이지미 생성

여기서 의문점이 하나 생긴다

“하나의 서비스를 만들 때 오직 1개의 도커 이미지를 활용하는 것도 좋지만 세세하게 관리하는데 있어서는 좋지 않은 편인 것 같다.

그러면 세세하게 나눠 배포하는 게 관리 측면에서 여러모로 좋을텐데?

 

즉, 하나의 서비스를 만들 때 복수의 도커 이미지를 핸들링하는 상황이 필요하게 된다면?”

 

그래서 생겨난 것이 docker-compose이다.

docker-compose는 Docker에 대한 새롭고 특수한 기능을 사용하는 것이 아닌, 기존 Docker에 대한 기능을 거의 다 그대로 사용한다. 단지 복수의 컨테이너를 동시에 시작하거나, 리로드하거나, 등의 핸들링 기능 위주로 존재한다.

 

즉! docker-compose를 사용하지 않는다는 이유로 특정 기능을 사용하지 못해 서비스 배포에 문제가 생기는 건 전혀없다. 단지 조금 더 체계적이고 깔끔해진다는 점이 존재한다.




docker-compose

  • 연결된 다수의 container를 하나로 통합하여 관리하는 도구
  • 다중 컨테이너 Docker 애플리케이션을 정의하고 실행하기 위한 도구로 앱을 구성하는 서비스를 docker-compose.yml에 정의하여 docker-compose up 명령어로 앱을 실행할 수 있다.
  • docker-compose.yml은 container실행 옵션을 미리 정의한 문서이다.
  • docker-compose.yml에 빌드 명령을 추가하면 Docker compose는 DockerFile를 사용한다.
  • 웹 서비스는 일반적으로 프론트엔드 서버, 백엔드 서버, DB서버로 구성되기 때문에 각 서버를 docker container로 연결하여 동작시키고 docker compose를 사용하여 해당 컨테이너들을 관리하는 것 권장

→ Docker Compose : 앱을 구성하는 서비스를 docker-compose.yml에 정의하여 docker-compose up을 실행하여 하나의 명령으로 앱을 실행

즉, 앱이 실행되는 동안 컨테이너를 관리하는 역할앱이 시작되면 컨테이너를 띄우고 앱이 실행되는 중에 컨테이너가 종료되면 다시 띄워줌

조금 더 쉽게 말하자면, docker-compose는 연결된 다수의 Container를 하나로 통합하여 관리하는 도구이고, host level에서만 동작하며, Container 실행 옵션을 미리 정의한 문서인 docker-compose-yml을 기반으로 Container를 실행한다.

Dockerfile에 빌드 관련 내용이 다 기재되어 있기 때문에 docker-compose.yml에서는 따로 빌드 관련 내용을 기재할 필요 없이 Dockerfile의 경로를 지정하기만 하면 된다.

docker-compose.yml 기본형식

# 버전을 정의하는 것으로 버전에 따라 지원하는 형식이 다르다.
version: "3.0"
# docker-compose로 생성 할 container의 옵션을 정의한다.
services:
	# 생성 할 container 이름을 지정한다.
	[container 이름]: 
		# container 생성시 사용 할 이미지를 지정한다.
		image: [image 이름]:[버전] 
		# docker-compose build 옵션에서 사용되는 build 옵션을 기재한다.
		# dockerfile에 명시된 FROM의 image를 사용하여 위에 명시된 image 이름과 tag로 새로운 image를 생성한다.
		build:
			# dockerfile의 위치를 지정한다.
			context: 
		# container port mapping 정보
		ports:
				- "80:80"
		# 도커 컨테이너가 실행되었을 때 요청 대기할 포트를 지정한다.
		# 여러 포트 지정도 가능하다.
		expose:
				- "80"
		# 환경 변수 리스트 정의
		environment:
				key: "value"
		# 실행 환경 설정
		stdin_open: true # docker run -i
		tty: true # docker run -t
		entrypoint: /bin/bash # exec /bin/bash

dockerfile, docker-compose.yml 예시

아래의 docker-compose.yml 파일의 내용은 아래의 docker 명령어 두 개를 수행하는 내용이다.

  • docker build -t ubuntu_base_web:v1 ./
  • docker run -p 80:80

dockerfile

FROM openjdk:17-jdk

# JAR_FILE 변수 정의 -> 기본적으로 jar file이 2개이기 때문에 이름을 특정해야함
# 나는 그냥 bootJar해서 jar file 1개만 생성한 후 아래와 같이 진행했음
ARG JAR_FILE=./build/libs/docker-0.0.1-SNAPSHOT.jar

# JAR 파일 메인 디렉토리에 복사
COPY ${JAR_FILE} app.jar

# 시스템 진입점 정의
ENTRYPOINT ["java","-jar","/app.jar"]

docker-comopse.yml

version: "3"

service:
  db:
    image: mysql:5.7
    restart: always
    volumes:
      - ./mysqldata:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=dgkcoding
      - MYSQL_DATABASE=dgkdb
    ports:
      - "3306:3306"

기본적으로 docker-compose.yml은 version, services, volumes, networks의 카테고리로 작성된다.

하지만, 주로 version과 services가 많이 사용된다.

  • version

docker compose의 파일 포맷 버전을 지정한다.

기본적으로 버전 3을 사용하는 것이 일반적이다.

  • services

한개 또는 여러 개의 docker container를 설정한다.

  • image

docker container의 이름을 정의한다.

Docker Hub에 있는 이미지를 사용하여 docker container를 작성할 경우 image를 설정할 수 있다.

  • restart

docker container가 다운되었을 경우, 항상 재시작하라는 설정이다.

  • volumes

docker run 명령의 -v 옵션과 동일한 역할을 한다.

여러 개의 volume을 지정할 수 있으며 리스트처럼 작성하면 된다.

  • environment

dockerfile의 ENV 옵션과 동일한 역할을 한다.

  • ports

docker run 명령의 -p 옵션과 동일한 역할을 한다.

참고로, 포트번호를 입력할 때에는 반드시 쌍따옴표 안에 작성해야 한다. (YAML 문법에서 숫자:숫자 는 시간으로 해석하기 때문)

  • networks

docker container 간의 네트워크 분리를 위해 추가로 설정을 한다. (옵션)

docker-compose 커맨드 사용법

f 옵션

Docker Compose는 기본적으로 커맨드가 실행하는 디렉토리에 있는 docker-compose.yml 또는 docker-compose.yaml를 설정 파일로 사용합니다. 다른 이름이나 경로의 파일을 Docker Compose 설정 파일로 사용하고 싶다면 -f 옵션으로 명시를 해줍니다.

$ docker-compose -f docker-compose-local.yml up

-f 옵션은 여러 개의 설정 파일을 사용할 때도 사용할 수 있습니다. 이 때는 나중에 나오는 설정이 앞에 나오는 설정보다 우선하게 됩니다.

$ docker-compose -f docker-compose.yml -f docker-compose-test.yml up

up

docker-compose up 커맨드는 아마도 Docker Compose에서 가장 자주 사용되는 커맨드일 텐데요. Docker Compose에 정의되어 있는 모든 서비스 컨테이너를 한 번에 생성하고 실행하기 위해서 사용합니다.

보통 -d 옵션을 사용하여 백그라운드에서 컨테이너를 띄우는 경우가 많습니다.

$ docker-compose up -d
Creating network "django-app_default" with the default driver
Creating django-app_db_1 ... done
Creating django-app_web_1 ... done
$

-d 옵션을 사용하지 않으면 현재 터미널이 컨테이너의 로그가 출력되고 Ctrl + C를 눌러서 탈출하는 순간 컨테이너가 모두 정지되기 때문입니다.

down

docker-compose down 커맨드는 docker-compose up 커맨드와 정반대의 동작을 합니다. Docker Compose에 정의되어 있는 모든 서비스 컨테이너를 한 번에 정지시키고 삭제합니다.

$ docker-compose down
Stopping django-app_web_1 ... done
Stopping django-app_db_1  ... done
Removing django-app_web_1 ... done
Removing django-app_db_1  ... done
Removing network django-app_default

start

docker-compose start 커맨드는 내려가 있는 있는 특정 서비스 컨테이너를 올리기 위해서 사용합니다. 대부분의 경우에는 docker-compose up 커맨드를 사용해도 내려간 서비스를 알아서 올려주므로 무방합니다.

$ docker-compose start web
Starting web ... done

stop

docker-compose stop 커맨드는 docker-compose start 커맨드와 정반대의 동작을 합니다. 돌아기고 있는 특정 서비스 컨테이너를 정지시키기 위해서 사용합니다.

$ docker-compose stop web
Stopping django-app_web_1 ... done

ps

docker-compose ps 커맨드는 Docker Compose에 정의되어 있는 모든 서비스 컨테이너 목록을 조회할 때 사용합니다.

$ docker-compose ps
      Name                    Command               State           Ports
----------------------------------------------------------------------------------
django-app_db_1    docker-entrypoint.sh postgres    Up      5432/tcp
django-app_web_1   python manage.py runserver ...   Up      0.0.0.0:8000->8000/tcp

logs

docker-compose logs 커맨드는 서비스 컨테이너의 로그를 확인하고 싶을 때 사용하며, 보통 -f 옵션을 붙여서 실시간 로그를 확인합니다.

$ docker-compose logs -f web
Attaching to django-app_web_1
web_1  | Watching for file changes with StatReloader
web_1  | Performing system checks...
web_1  |
web_1  | System check identified no issues (0 silenced).
web_1  |
web_1  | May 30, 2020 - 22:16:29
web_1  | Django version 3.0.6, using settings 'our_project.settings'
web_1  | Starting development server at <http://0:8000/>
web_1  | Quit the server with CONTROL-C.

exec

docker-compose exec 커맨드는 실행 중인 서비스 컨테이너를 대상으로 어떤 명령어를 날릴 때 사용합니다.

$ docker-compose exec db psql postgres postgres
psql (12.2 (Debian 12.2-2.pgdg100+1))
Type "help" for help.

postgres=#

run

docker-compose run 커맨드는 서비스 컨테이너의 특정 명령어를 일회성으로 실행할 때 사용합니다.

$ docker-compose run web env
PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=10757eb6642e
TERM=xterm
LANG=C.UTF-8
GPG_KEY=E3FF2839C048B25C084DEBE9B26995E310250568
PYTHON_VERSION=3.8.2
PYTHON_PIP_VERSION=20.1
PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/1fe530e9e3d800be94e04f6428460fc4fb94f5a9/get-pip.py
PYTHON_GET_PIP_SHA256=ce486cddac44e99496a702aa5c06c5028414ef48fdfd5242cd2fe559b13d4348
PYTHONUNBUFFERED=1
HOME=/root

config

docker-compose config 커맨드는 Docker Compose 설정을 확인할 때 사용합니다. -f 옵션으로 여러 개의 설정 파일을 사용할 때, 최종적으로 어떻게 설정이 적용되는지 확인해볼 때 유용합니다.

docker-compose config
services:
  db:
    environment:
      POSTGRES_PASSWORD: postgres
      POSTGRES_USER: postgres
    image: postgres
  web:
    build:
      context: /Users/dale/temp/django-app
    command: python manage.py runserver 0:8000
    depends_on:
    - db
    ports:
    - 8000:8000/tcp
    volumes:
    - /Users/dale/temp/django-app:/web:rw
version: '3.0'

'개인공부' 카테고리의 다른 글

자동 build Tool별 특징 및 장단점  (0) 2023.05.20
헥사고날 아키텍처 개념 및 사용법  (0) 2023.05.05
Multimodule(멀티모듈) 개념 및 사용법  (0) 2023.04.14
jib란?  (0) 2023.04.04
java record 개념 및 사용법  (0) 2023.03.23

댓글