Docker 실습 (Spring Boot 배포, MariaDB, Redis)

작성일

Docker 설치

  • https://docs.docker.com/desktop/ 각 OS에 맞게 Docker 설치
  • https://hub.docker.com/ 무료 플랜으로 회원 가입 및 로그인 인증

설치를 하였으면 아래 명령어를 입력하여 설치가 되었는지 확인

docker -v
docker-compose -v

docker login

Jar 파일 생성 및 Dockerfile 작성 후 실행

Jar 파일 생성

이제 Jar 파일을 생성해보자. 아래 명령어를 입력하면 ./build/libs 경로에 jar 파일이 2개 생성된다.

./gradlew build

1

*-plain.jar는 의존성이 포함되지 않은 파일이므로 배포를 할 수 없다.

jar 파일 이름을 지정하기 위해 build.gradle에 아래 내용을 추가한다.

bootJar {
    archiveFileName = 'app.jar'
}

다시 빌드를 하면 build.gradle에서 작성했던 파일 이름이 생성된다.

./gradlew clean # 기존에 빌드했던 파일을 삭제
./gradlew build

2

Dockerfile 작성

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

작성한 Dockerfile을 이미지로 만드는 작업을 하기 위해 아래 명령어를 입력한다.

마지막에 .은 Dockerfile이 있는 경로를 의미한다.

docker build -t yessm621/pharmacy .

이제 생성된 이미지 확인해보자.

docker images

3

생성한 이미지를 사용해서 컨테이너를 시작하자.

docker run yessm621/pharmacy -p 8080:8080

정상적으로 컨테이너가 시작되었는지 확인하기 위해 다음 명령어를 입력한다.

docker ps

4

컨테이너 아이디(CONTAINER ID)를 이용하여 터미널에 접근할 수 있다.

# 컨테이너를 sh, bash 등의 터미널 환경으로 접근
docker exec -it 3820884166d7 bash

5

도커 컴포즈 파일 작성

도커 컴포즈 버전

Compose file versions and upgrading

로컬에서 사용할 DB, Redis 도커 파일(Dockerfile) 작성 후 docker-compose 파일을 작성하겠다.

./redis/Dockerfile

FROM redis:6

ENV TZ=Asia/Seoul

./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
  • docker mariaDB 컨테이너 내에 /etc/mysql/conf.d 경로에 .cnf 설정 파일을 넣어주면 해당 내용을 바탕으로 설정이 초기화 된다.

이제 도커 컴포즈 파일을 작성하자.

version: "3.8"
services:
  pharmacy-redis:
    container_name: pharmacy-redis
    build:
      dockerfile: Dockerfile
      context: ./redis
    image: yessm621/pharmacy-redis
    ports:
      - "6379:6379"
  pharmacy-database:
    container_name: pharmacy-database
    build:
      dockerfile: Dockerfile
      context: ./database
    image: yessm621/pharmacy-database
    environment:
      - MARIADB_DATABASE=pharmacy
      - MARIADB_ROOT_PASSWORD=${SPRING_DATASOURCE_PASSWORD}
    volumes:
      - ./databases/config:/etc/mysql/conf.d
    ports:
      - "3306:3306"

  • ${SPRING_DATASOURCE_PASSWORD}와 같은 환경 변수는 .env 파일에 추가로 작성했다.
  • Docker compose 에서 환경 변수 정보들을 분리하여 별도의 파일로 구성할때 간편한 방법은 Compose 파일이 위치한 경로에 .env 파일을 구성
  • 현재는 작은 프로젝트이므로 .env에 작성했지만 현업에서는 HashiCorp Vault를 많이 사용한다. (암호화를 통해 더 높은 보안을 제공하는 오픈소스 HashiCorp Vault 고려)

.env

SPRING_DATASOURCE_USERNAME=root
SPRING_DATASOURCE_PASSWORD=1234
  • 작성한 .env 파일은 별다른 설정 없이 Docker Compose에 바로 반영
  • 비밀번호가 코드에 노출되지 않도록 .gitignore에 .env 파일 추가

이제 도커 컴포즈 실행 명령어를 통해 Redis, Database를 실행한다.

# 실행
docker-compose -f docker-compose-local.yml up
# 중지 및 컨테이너 정리
docker-compose -f docker-compose-local.yml down

실행 후 docker ps 명령어를 통해 도커 컴포즈에 작성한 컨테이너들이 생성되고 실행된 것을 확인 할 수 있다.

6

이제 스프링 부트 애플리케이션을 실행하기 위해 applicaiton.yml을 수정하고 실행 해보자.

spring:
  profiles:
    active: local # default
    group:
      local:
        - common
      prod:
        - common

---
spring:
  config:
    activate:
      on-profile: common

---
spring:
  config:
    activate:
      on-profile: local
  datasource:
    driver-class-name: org.mariadb.jdbc.Driver
    url: jdbc:mariadb://localhost:3306/pharmacy
    username: ${SPRING_DATASOURCE_USERNAME}
    password: ${SPRING_DATASOURCE_PASSWORD}
  data:
    redis:
      host: 127.0.0.1
      port: 6379
  jpa:
    hibernate:
      ddl-auto: create

---
spring:
  config:
    activate:
      on-profile: prod

스프링 부트 환경 변수는 아래 사진 처럼 Edit Configurations…에서 설정할 수 있다.

7

8

이제 스프링 부트를 실행하면 잘 실행되는 것을 확인할 수 있다.

데이터 셋업

데이터베이스에 데이터를 넣고 싶을 때 다음과 같이 사용한다.

MariaDB에 테이블을 생성하고 데이터를 넣기 위해 아래 사진과 같이 파일을 생성했다.

9

init 폴더에 ddl과 dml을 작성한 sql 파일을 넣어둔다.

그 후 docker-compose-local.yml 파일에 다음 코드를 추가한다.

environment:
  - MARIADB_DATABASE=pharmacy
  - MARIADB_ROOT_PASSWORD=${SPRING_DATASOURCE_PASSWORD}
volumes:
  - ./database/config:/etc/mysql/conf.d
  - ./database/init:/docker-entrypoint-initdb.d # 추가한 코드
ports:
  - "3306:3306"
  • 추가한 코드의 의미는 도커 컨테이너 생성 시 초기 데이터를 만들기 위한 코드이다.
  • 디렉토리 /docker-entrypoint-initdb.d/ 에 .sql 또는 .sh 파일을 넣어두면 컨테이너 실행 시 실행된다.

추가한 데이터가 삭제되지 않도록 application.yml에서 ddl-auto를 validate로 변경한다.

---
spring:
  config:
    activate:
      on-profile: local
  datasource:
    ...
  jpa:
    hibernate:
      ddl-auto: validate # create -> validate으로 변경
    database-platform: org.hibernate.dialect.MariaDB103Dialect

이제 다시 docker-compose를 실행하면 테이블과 데이터가 생성된 것을 확인할 수 있다.

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

테이블과 데이터가 생성되었는지 확인하는 방법은 도커 컨테이너 아이디를 사용해서 bash로 접속하면 된다.

docker ps
docker exec -it 컨테이너 아이디 bash

10

11

12

그런데 나의 경우 테이블도 생성되지 않고 데이터도 생성되지 않았다.

원인을 찾아보니 기존에 사용하던 도커 이미지를 그대로 사용하고 있어서 문제가 되는 경우가 있다고 한다.

이럴땐 아래와 같이 처리한다.

먼저, docker-compose로 실행하던 컨테이너를 종료한다.

docker-compose -f docker-compose-local.yml down

그리고 현재 사용하지 않는 리소스를 정리하기 위해 아래 명령어를 입력한다.

  • 멈춰있는 컨테이너 제거
  • 컨테이너에서 사용되지 않는 네트워크 제거
  • 불필요한 이미지 및 빌드 캐시 제거
docker system prune

docker-compose로 실행할 때 재빌드하기 위해 —build 옵션을 추가한다.

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

이제 다시 bash에 접속해 확인해보면 테이블과 데이터가 생성된 것을 확인할 수 있다.

Github 코드