Dockerfile과 Docker compose 사용법

김가영

Updated:

Intro

안녕하세요. 김가영대리입니다. Dockerfile과 docker-compose.yml 파일을 이용하여 도커 이미지와 컨테이너를 생성하여 서버 띄우는 방법을 정리하였습니다.

Dockerfile

Foo

Dockerfile은 컨테이너에 설치해야 하는 패키지, 소스코드, 명령어, 환경변수설정 등을 기록한 하나의 파일입니다. Dockerfile를 빌드하면 Docker가 Dockerfile에 나열된 명령문을 차례대로 수행하여 이미지를 생성해줍니다.

Dockerfile의 장점

  • 코드 형태로 되어 있어 버전 관리가 용이
  • 이미지의 기능을 파악하기 쉬움
  • 배포에 용이
    • 어떠한 이미지를 배포할 떄, 몇 기가씩이나 되는 이미지 파일 자체를 배포하기보다는 그 이미지를 만들 수 있는 스크립트인 Dockerfile로 만든 이미지를 배포한다면 매우 편리할 것이다.

Dockerfile 작성 지시어

지시어 설명
FROM 베이스 이미지 지정
ARG 빌드 시점에 쓰는 변수
RUN 이미지를 지정하면서 실행할 명령 지정
ENTRYPOINT 컨테이너의 어플 지정 (컨테이너 시작할 때 실행할 명령어)
EXPOSE 컨테이너의 포트 지정
ADD 이미지 생성 시 파일 추가
COPY 이미지 생성 시 파일 복사
WORKDIR 컨테이너 작업 디렉토리 지정
MAINTAINER 이미지 작성자 명시
CMD 컨테이너의 어플 지정 (컨테이너 시작할 떄 실행할 명령어)
LABEL 이미지의 라벨 지정
ENV 컨테이너의 환경 변수 지정
VOLUME 컨테이너의 볼륨 지정
USER 컨테이너의 사용자 지정

Dockerfile 빌드

hello 출력 API만 포함된 스프링부트 프로젝트를 아래 Dockerfile을 이용하여 image build하여 보겠습니다.

docker build -t {image이름:tag명} .

Dockerfile

Foo

Dockerfile Build

Foo

docker image 생성된 모습

Foo
  • Dockerfile은 base image를 이용하여 그 위에 명령어 하나를 실행 한 후 image에 commit을 하여 image를 만들어 나갑니다.
  • 각 명령어는 하나의 Step을 의미하고 Step은 하나의 commit이 됩니다. 작업 내용은 docker history {image명}에서 확인 가능합니다.

docker history로 image 이력 확인

Foo

참고 (inspect로 확인 시)

  • docker inspect {image명}의 맨 마지막 Layers를 보면 몇줄만 추가 된 것을 볼 수 있습니다.
  • 이는 layer에서는 image에 변경된 사항만 추가하기 떄문입니다.

docker inspect

Foo

이제 컨테이너를 생성하여 서버를 띄워보겠습니다.

docker image로 docker container 생성 및 실행

Foo
  • -d: 백그라운드모드로 실행
  • -p: [호스트포트]:[컨테이너포트] 포트 연결
  • –name: 컨테이너 이름

접속 확인

Foo

Public DNS를 8080번 포트로 접속해 접속을 확인하였습니다.

Docker Compose

여러 개의 컨테이너로부터 이루어진 서비스를 구축, 실행하는 순서를 자동으로 하여, 관리를 간단히 하는 기능입니다.

Docker compose에서는 compose 파일을 준비하여 커맨드를 1회 실행하는 것으로, 그 파일로부터 설정을 읽어들여 모든 컨테이너 서비스를 실행시키는 것이 가능합니다.

compose 파일은 YAML 문법을 통해 작성되므로 가독성도 좋습니다.

docker-compose.yml 파일 구성

문법 설명
version - 파일 맨 앞에 선언
- 파일의 내용을 해석하는데 필요한 문법 버전 선언
services - 생성하고자 하는 컨테이너 항목들
- service 아래 항목들은 하나하나의 생성할 컨테이너
image - 컨테이너가 만들어질 수 있는 기반인 이미지를 지정
- 현재 도커 위에 있는 이미지를 지정해야 한다.
ports - 포트 포워딩 할 포트를 지정
- <호스트 포트="">:<컨테이너 포트=""> 순서대로
- 호스트포트는 중복될 수 없다.
- - 여러개가 올 수 있다는 의미이다.
volumes - 볼륨 마운트 디렉터리 지정
networks - 네트워크 지정
command - 컨테이너 생성 시 실행시킬 명령어
depends_on - 컨테이너 생성 우선순위를 지정

Docker compose 주요 명령어

명령어 설명
up 파일의 내용에 따라 이미지를 빌드하고 서비스를 실행
down 실행 중인 서비스를 삭제
stop,start 서비스를 멈추거나, 멈춰 있는 서비스를 시작
ps 현재 환경에서 실행 중인 각 서비스의 상태를 표시
exec 실행 중인 컨테이너에서 명령어를 실행
실행되어있는 컨테이너에 접속
run 특정 명령어를 일회성으로 실행
실행 시에 새로운 컨테이너를 띄운다
logs output으로 나온 log들을 확인할 떄 사용
-f 옵션을 사용하면 실시간으로 로그 확인 가능
config docker-compose에 최종적으로 적용된 설정을 보여준다

Docker Compose 예제

docker-compose를 이용해 SpringBoot Application에 mysql DB 연결하여 User 목록 조회 API를 호출해보겠습니다.

현재 docker images

Foo

mysql 이미지와 User 목록 조회 API를 추가한 소스로 docker-practice:2 이미지를 만들어 놓았습니다.

docker-compose.yml

version: '2'

services:
  compose-db:
    image: mysql:8.0.17
    container_name: compose-db
    volumes:
      - db_data:/var/lib/mysql
    ports:
      - "3307:3306"
    networks:
      - compose-network
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_DATABASE=docker_practice
      - MYSQL_USER=gayoung
      - MYSQL_PASSWORD=password
    command: ['--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci']

  compose-app:
    image: docker-practice:2
    container_name: compose-app
    ports:
      - "8081:8080"
    networks:
      - compose-network
    depends_on:
      - compose-db

networks:
  compose-network:
    driver: bridge

volumes:
  db_data

위 compose를 실행했을 때의 과정은 아래와 같습니다.

  1. compose-network 네트워크 생성
  2. db_data 볼륨 생성
  3. compose-db 컨테이너 생성 및 실행(compose-db 이름으로 compose-network에 접속)
  4. compose-app 컨테이너 생성 및 실행(compose-app 이름으로 compose-network에 접속)

docker-compose를 이용하면 이 모든 과정을 압축하여 한 번에 실행할 수 있습니다.

프로젝트 루트폴더에 docker-compose.yml이라는 이름으로 파일을 만들고 위와 같이 작성해줍니다. 참고로 파일은 Dockerfile과는 다르게 yml 형식만 지켜주면 파일 이름은 아무렇게나 바꿔도 상관 없습니다.

docker compose로 컨테이너 생성 및 실행

Foo

User 목록 API 호출 확인

Foo

Public DNS를 8081번 포트로 접속하여 getUserList API 호출시 응답값을 확인하였습니다.

Docker Volume

도커는 container 안의 파일 변경 사항을 UnionFS를 통해 관리합니다.

UnionFS은 이미지 layer와 write layer를 합쳐 container의 데이터를 관리하는데, container 삭제 시 write layer도 삭제 됩니다. (Write layer에는 이미지 layer의 데이터에서 변경된 사항을 저장하므로 write layer 삭제 시 데이터가 사라진다. => 데이터 휘발성)

따라서 container의 데이터 휘발성 때문에 데이터를 container가 아닌 호스트에 저장할 때 사용합니다.

대표적인 Volume 사용법

Foo
  • 호스트의 특정 디렉토리(or 파일)을 container와 매핑
  • Volume의 위치를 사용자가 정할 수 있으므로 데이터를 찾기 쉽다.
  • 컨테이너에서 /data 디렉토리에 파일을 생성/삭제/변경 등의 작업을 하게되면, 호스트의 /root/data 디렉토리에 같은 내용이 있음

Docker Network

같은 Docker Host 내에서 실행중인 Container 간에 연결할 수 있도록 돕는 논리적 네트워크 입니다. docker container로써 실행된 spring boot에서 마찬가지로 container로 실행중인 mysql server에 접근하기 위해서 각각의 컨테이너의 IP를 지정하여 통신하여야 했는데 통신하여야 하는 컨테이너들을 같은 네트워크 안에 연결해주면 컨테이너 name만으로 손쉽게 네트워크를 연결할 수 있다는 장점이 있습니다.

위의 docker compose를 사용한 예제를 보면 yml 파일에 compose-network로 compose-db와 compose-app을 연결해주었습니다.

compose-network 확인

Foo

inspect로 network에 포함된 container 확인

Foo

Spring boot Application application.properties DB 설정 주소

spring.datasource.url=jdbc:mysql://compose-db/docker_practice?characterEncoding=UTF-8&serverTimezone=Asia/Seoul

Tags:

Categories:

Updated:

Leave a comment