[Docker] docker-compose로 빌드하기

merci·2023년 6월 13일
0

Docker

목록 보기
3/4

도커를 공부하면서 docker run 이나 docker-compose 명령어로 설정한 환경으로 서버를 활성화 하는 과정이 신기해서 docker-compose up을 이용해서 프론트 + DB + 서버를 한번에 실행하는 코드를 만들었습니다.
한번에 실행되는 뽕에 취해서 시도한 방법이지만 단점이 더 많아서 다음부터는 무조건 분리해야겠습니다.

우선 도커를 어떤 과정으로 만들었는지 소개합니다.

docker-compose.yml

로컬 환경에서 테스트 서버를 만드는 설정파일 입니다.
docker-compose up --build 명령어를 통해서 코드에 변화가 생긴다면 아래 yml설정대로 새로운 이미지를 만들게 됩니다.

version: '3.9'
services:
  database:
    build: ./database
    restart: always
    volumes:
      - mysql-volume:/var/lib/mysql
    environment:
      - MYSQL_USER=${HS512_SECRET}
      - MYSQL_PASSWORD=${HS512_SECRET}
      - MYSQL_ROOT_PASSWORD=${HS512_SECRET}
      - MYSQL_DATABASE=${HS512_SECRET}
    expose:
      - 3306
    ports:
      - "3306:3306"

  springboot-server:
    depends_on:
      - database
    build: ./springboot-server
    restart: always
    volumes:
      - ./springboot-server:/build/app
    expose:
      - 8080
    ports:
      - "8080:8080"
    environment:
      - MYSQL_HOST=database
      - MYSQL_USER=${HS512_SECRET}
      - MYSQL_PASSWORD=${HS512_SECRET}
      - MYSQL_DATABASE=${HS512_SECRET}
      - MYSQL_PORT=3306
      - HS512_SECRET=${HS512_SECRET}

volumes:
  mysql-volume:

depends_on 은 의존하는 서비스가 실행될 때 해당 서비스를 시작하게 됩니다.
이때 스프링의 jdbc manager가 연결할 때 db가 아직 켜지는 중이면 에러가 발생하므로 restart를 추가해서 다시 시도하도록 했습니다.
도커를 처음해서 테스트 한다고 db와 서버를 동시에 켰는데 db는 RDS로 켜놓는게 정신건강에 좋을것 같습니다.

docker-compose.yml 에서 volumes:로 프로젝트 파일을 볼륨에 복사할 수 있지만 권한 설정을 줄 수 없어서 Dockerfile에서 복사를 했습니다.
마찬가지로 db생성 시 필요한 설정을 추가하기 위해서 command:를 이용했지만 적용되지 않아서 스크립트를 만들어 Dockerfile에서 권한을 부여한 후 복사를 했습니다.

각 서비스에서 사용하는 환경변수는 environment:로 넣어줬습니다.

DB설정 - Dockerfile

Dockerfile 에서는 이미지를 만들기 위한 파일 복사와 실행할 스크립트 생성 및 권한 부여를 했습니다.
From 다음에는 도커허브에서 다운받을 이미지를 명시합니다. ( mysql:5.7 )

FROM mysql:5.7

# 도커 디렉토리로 설정 파일 복사
COPY ./scripts/ /docker-entrypoint-initdb.d/

COPY ./01-database.sh /docker-entrypoint-initdb.d/
RUN sed -i 's/\r$//' /docker-entrypoint-initdb.d/01-database.sh

COPY ./my.cnf /etc/mysql/conf.d/my.cnf

RUN chmod 644 /etc/mysql/conf.d/my.cnf

RUN chmod 755 /docker-entrypoint-initdb.d/01-database.sh

sed -i 's/\r$//' 를 이용해서 윈도우 환경에서 작성된 스크립트를 리눅스 환경에서 작동하도록 개행문자를 수정합니다.

docker는 /etc/mysql/conf.d/my.cnf를 참조해서 db를 설정합니다.
아래 코드로 타임과 utf-8설정을 추가합니다.

[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
default-time-zone=Asia/Seoul
[mysql]
default-character-set=utf8mb4
[client]
default-character-set=utf8mb4
[mysqldump]
default-character-set=utf8mb4

테이블을 생성하기 전에 설정할 데이터베이스를 스크립트로 만들었습니다.

#!/bin/bash

# 데이터베이스 생성
mysql -u root -p$MYSQL_ROOT_PASSWORD -e "CREATE DATABASE ${MYSQL_DATABASE};"

# 사용자에게 데이터베이스에 대한 권한 부여
mysql -u root -p$MYSQL_ROOT_PASSWORD -e "GRANT ALL PRIVILEGES ON ${MYSQL_DATABASE}.* TO $MYSQL_USER@'%';"

# 생성한 데이터베이스 선택
mysql -u $MYSQL_USER -p$MYSQL_PASSWORD -e "USE $MYSQL_DATABASE;"

도커에서 mysql 이미지를 만들때 /docker-entrypoint-initdb.d/를 참조합니다.
내부에 있는 파일들을 이름 순서대로 실행하므로 숫자로 순서를 지정했습니다.
01-database.sh -> 02-create_table.sql -> 03-insert_data.sql


서버 설정 - Dockerfile

FROM gradle:7.4-jdk-alpine AS builder

# 작업 디렉토리 설정
WORKDIR /build

# 도커 캐시 사용 - 새로운 Gradle만 다운로드
COPY build.gradle settings.gradle /build/
RUN gradle build -x test --parallel --continue > /dev/null 2>&1 || true

# 스프링 프로젝트 복사
COPY . /build
RUN gradle clean build --parallel 

# Java 11 JDK 가 설치된 Docker 이미지를 기반으로 새 이미지 생성
FROM openjdk:11.0-slim
WORKDIR /app

# 빌드한 jar파일을 /app.jar 로복사
COPY --from=builder /build/build/libs/*.jar /app.jar 

#  root 권한 x, nobody 권한으로 실행함
USER nobody
ENTRYPOINT [                                                            \
   "java",                                                              \
   "-Dspring.profiles.active=prod",                                     \
   "-Dfile.encoding=UTF-8",                                             \
   "-Djava.security.egd=file:/dev/./urandom",                           \
   "-Dsun.net.inetaddr.ttl=0",                                          \
   "-jar",                                                              \
   "/app.jar"                                                         \
]

jar를 만들기 위해서 Gradle이미지를 복사합니다.
이때 캐시를 이용해서 새로운 버전이 생길 경우만 새로운 이미지를 다운 받습니다.
RUN gradle clean build --parallel 명령어로 jar파일을 생성합니다.
이때 제가 만든 서버에서는 clean build 시 테스트를 하고 RestDocs 문서를 만들어 jar에 넣게됩니다.
jar를 실행하기 위해 jdk 이미지를 넣은 뒤 이미지를 실행하는 ENTRYPOINT를 추가합니다.


도커로 서버 활성화

# 변경을 감지해 새로운 이미지 빌드 후 싪행
docker-compose up --build

# 이미지를 실행
docker-compose up

루트 프로젝트 위치에서 터미널에 위 커맨드를 입력하면 docker-compose 가 루트 디렉토리의 docker-compose.yml을 찾아서 설정파일대로 이미지를 만들기 시작합니다.
한번 설정하면 다음부터는 손쉽게 서버를 켜서 개발을 진행할 수 있게 됩니다.

이미지를 빌드 했었다면 Docker Desktop을 이용해서 클릭 한 번으로 서버를 켤 수도 있습니다.


프론트 추가

만약 리액트 서버를 도커에 추가한다면 아래 방법을 이용합니다.

version: '3.9'
services:
  react-app:
    build: ./react-app
    volumes:
      - ./react-app:/home/node/app
    expose:
      - 3000
    ports:
      - "3000:3000"

Dockerfile

FROM node:14.18.1-bullseye

WORKDIR /home/node/app

# package.json 을 Docker 이미지에 복사
COPY package*.json ./

RUN npm cache clean --force
RUN npm install

# 앱 소스를 Docker 이미지에 복사
COPY . .

CMD ["npm", "start"]    

node이미지를 다운받아 npm을 이용해서 package*.json 설정대로 리액트 의존성을 다운받습니다.
이후 npm start명령어를 실행해서 리액트 서버를 실행합니다.

profile
작은것부터

0개의 댓글