뉴스타 서비스의 경우 Docker를 이용하여 어플리케이션을 띄우기로 했다. 그래서 Dockerfile과 Docker-compose 작성법에 대해서 알아보고 뉴스타 서비스에 적용하는 과정까지 살펴보도록 하겠다.
1. Dockerfile 문법
명령
설명
FROM
베이스 이미지 설정
LABEL
이미지의 Metadata 설정
CMD
Docker Container를 생성할 때, 실행하는 쉘 명령 (docker run)
RUN
이미지를 생성할 때, 실행하는 쉘 명령
ENTRYPOINT
Docker Container가 시작할 때, 실행하는 쉘 명령 (docker start)
EXPOSE
Docker Container 외부에 오픈할 Port 설정
ENV
Docker Container 내부에서 사용할 환경 변수 설정
WORKDIR
Docker Container 내부에서 작업 디렉토리 설정
COPY
파일, 디렉토리를 Docker Container에 복사
ADD
파일, 디렉토리, URL를 Docker Container에 복사 및 압축 해제
SHELL
Docker Container 기본 Shell 설정
ARG
Dockerfile내에서 변수 설정
USER
Docker Container 내부에서 작업을 하는 사용자 ID 설정
ONBUILD
생성한 이미지를 기반으로 새로운 이미지를 생성할 때 명령어를 설정
VOLUME
이미지를 위한 볼륨 생성
MAINTAINER
이미지를 생성한 개발자 정보 설정
STOPSIGNAL
Docker Container를 STOP 할 때 Signal을 설정
HEALTHCHECK
Docker Container의 프로세스 상태를 체크
2. Docker Compose 주요 문법
명령
설명
version
Docker Compose 파일의 버전 설정
services
Docker Container의 그룹을 설정
image
사용할 Docker Image의 이름 설정
build
이미지를 빌드할 Dockerfile의 경로를 설정
ports
호스트와 Container 간의 네트워크 포트 매핑을 설정
env_file
Docker Container에서 사용할 환경 변수를 포함하는 파일의 경로를 설정
environment
Docker Container에서 사용할 환경 변수를 설정
depends_on
해당 서비스가 시작하기 전에 먼저 시작해야 하는 서비스를 설정
command
Docker Container가 시작할 때, 실행할 명령을 설정
links
해당 서비스와 연결할 다른 서비스를 설정
networks
서비스 간의 네트워킹을 설정
volumes
Docker Container의 데이터를 유지하기 위해 설정
3. Dockerfile / Docker compose 실습
3.1. Spring Boot
# 베이스 이미지 설정
FROM openjdk:17 AS builder
# 워킹 디렉토리 설정
WORKDIR /usr/src/app
# 빌드 파일 복사
COPY build.gradle gradlew settings.gradle gradle src .
# 실행 권한 부여
RUN chmod +x gradlew
# 프로젝트 빌드
RUN ./gradlew clean bootJar
# 빌드 파일 변수 설정
ARG JAR_FILE=build/libs/*.jar
# 빌드 파일 복사
COPY ${JAR_FILE} app.jar
# 타임존 설정
RUN apk add tzdata && ln -snf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
RUN echo Asia/Seoul > /etc/timezone
# jar 파일 실행
ENTRYPOINT ["java","-jar", "-Dspring.profiles.active=prod", "app.jar"]
gradle을 따로 설치하지 않고 빌드 파일들을 복사했다. 또한, Docker Container의 시간을 맞추기 위해 타임존을 설정했다.
docker build -t newstar_back .
newstar_back 이름을 가진 이미지로 빌드 수행
3.2. FastAPI
# 베이스 이미지 설정
FROM python:3.9.13
# 워킹 디렉토리 설정
WORKDIR /app/
# 코드 및 의존성 등 프로젝트 파일 복사
COPY . .
# 패키지 업데이트
RUN pip install --upgrade pip
# 패키지 설치
RUN pip install -r requirements.txt
# 타임존 설정
RUN ln -snf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
RUN echo Asia/Seoul > /etc/timezone
# 환경 변수 production 모드 설정
ENV APP_ENV=prod
# unicorn을 통해 프로젝트 실행
CMD uvicorn --host=0.0.0.0 --port 8000 app.main:app
ENV 명령어를 이용하여 APP_ENV에 prod 값을 부여하고 있다. 뉴스타 프로젝트는 dev, prod, create 등으로 환경을 분리해서 관리하고 있기 때문이다.
docker build -t fastapi_back .
fastapi_back 이름을 가진 이미지로 빌드 수행
3.3. React
# 베이스 이미지 설정
FROM node:alpine AS builder
# 워킹 디렉토리 설정
WORKDIR /usr/src/app
# 의존성 목록 복사
COPY package.json .
# 의존성 설치
RUN npm install --force
# 프로젝트 파일 복사
COPY . .
# 프로젝트 빌드
RUN npm run build
# 베이스 이미지 다시 설정
FROM nginx:latest
# nginx 설정 파일 복사
COPY ./default.conf /etc/nginx/conf.d/default.conf
# React Build 파일 nginx 정적 파일 반환 경로에 복사
COPY --from=builder /usr/src/app/dist /usr/share/nginx/html
# Nginx 실행
CMD [ "nginx", "-g", "daemon off;"]
# default.conf
server {
listen 3000;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
React의 경우 Node 이미지에서 프로젝트 파일을 빌드하고 있다.
Nginx 베이스 이미지를 가져와서 커스텀 설정을 적용하고 React에서 빌드해서 나온 결과물을 가져와서 / 경로의 반환 파일 경로에 복사했다.
뉴스타 서비스는 Nginx를 Reverse Proxy로도 사용하고 WebServer로도 활용을 했다. 그러면 가장 외부와 가까운 Nginx에서 정적 파일들을 반환하면 될 것인데 왜 이렇게 역할을 나눈 것인지 궁금할 수도 있다.
가장 앞단에 존재하는 Nginx가 forwarding 업무를 수행하고 정적 파일도 반환하고 추후에는 로드 밸러싱까지 담당할 것이라 부하가 많아질 것이라 판단해서 2개로 나눠서 운영을 하기로 결정했다.