Docker Compose 사용하지 않고 Dockerfile로 개별 배포하기

ekgns0508·2024년 1월 21일

Docker

목록 보기
5/5

앞서 docker-compose를 사용하여 서비스들을 묶어 실행하는 방법을 배웠다. 하지만 이런 방식은 개발 및 테스트 단계에서만 사용하거나 프로젝트 규모가 작은 경우에 사용한다고 한다. 서비스 하나의 코드를 수정하거나 재배포를 하게 되면 모든 서비스를 중단하고 다시 실행해야 하기 때문이다.

이 때문에 서비스별 Dockerfile을 사용하여 개별 배포하는 방법을 알아보았다.


Dockerfile

사용한 파일들은 이전 글에서 사용한 파일들을 그대로 사용했다.

mysql

FROM mysql:8.0

ENV MYSQL_ROOT_PASSWORD=root1234
ENV MYSQL_DATABASE=metadb

# 해당경로에 sql파일이 들어가면 실행과 동시에 수행된다. (기본 데이터들 삽입)
COPY init.sql /docker-entrypoint-initdb.d

CMD ["--character-set-server=utf8mb4", "--collation-server=utf8mb4_unicode_ci"]

SpringBoot

FROM openjdk:11-jdk-slim

WORKDIR /app

COPY . .

RUN chmod +x ./gradlew
RUN ./gradlew clean build

ENV JAR_PATH=/app/build/libs
RUN mv ${JAR_PATH}/*.jar /app/app.jar

ENV SPRING_DATASOURCE_URL=jdbc:mysql://mysql-container:3306/metadb?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false&allowPublicKeyRetrieval=true
ENV SPRING_DATASOURCE_DRIVER=com.mysql.cj.jdbc.Driver
ENV SPRING_DATASOURCE_USERNAME=root
ENV SPRING_DATASOURCE_PASSWORD=root1234

# application-prod.yml 사용
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=prod", "app.jar"]

Nginx 설정파일

user nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    sendfile on;
    keepalive_timeout 65;

    upstream backend {
        server spring-container:8080;
    }

    server {
        listen 80;

        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
            try_files $uri $uri/ /index.html;

            proxy_redirect     off;
            proxy_set_header   Host $host;
            proxy_set_header   X-Real-IP $remote_addr;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Host $server_name;
            
            proxy_set_header X-NginX-Proxy true;
        }

        location /api/ {
            proxy_pass http://backend;

            rewrite ^/api(/.*)$ $1 break; # /api/ 제거 된다.

            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';

            proxy_redirect     off;
            proxy_set_header   Host $host;
            proxy_set_header   X-Real-IP $remote_addr;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Host $server_name;
         }
    }
}

기존에는 upstream 블록에서 docker-compose.yml에서 생성한 서비스명(backend)을 사용했지만 이번에는 사용하지 않을 것이므로 스프링 컨테이너를 실행할 때 사용할 이름을 지정한다. 나머지는 동일하다.


React

FROM node:alpine as build
WORKDIR /app

# 라이브러리 설치
COPY package.json /app
RUN npm install --silent

# node_modules가 이미 생성된 시점이기 때문에 복사해오지 않는다.
COPY . /app

RUN npm run build

FROM nginx
# 생성된 build 이미지로부터 리엑트의 build 폴더 내부의 내용(결과물)을 /usr/share/nginx/html 로 옮긴다.
COPY --from=build /app/build /usr/share/nginx/html
# 내가 설정한 nginx.conf 파일 덮어씌우기
COPY ./nginx/nginx.conf /etc/nginx/nginx.conf

ENTRYPOINT ["nginx", "-g", "daemon off;"]

실행 명령어

도커 네트워크

생성한 이미지들을 컨테이너로 실행시키더라도 docker-compose 처럼 묶지 않는다면 서로간의 통신이 되지 않는다. 이를 위해 두가지 옵션을 사용할 수 있다. --link--network 옵션이다.

--link는 예전에 사용하던 방식으로 지금은 권장하지 않고 --network 옵션을 주로 사용한다고 한다.

--network를 사용하기 위해서는 먼저 도커 네트워크를 생성해야 한다.

# 도커 네트워크 생성 (docker-network라는 이름의 네트워크 생성)
$ docker network create docker-network

# 도커 네트워크 리스트 조회
$ docker network ls

# 도커 네트워크에 연결된 컨테이너 목록 확인
$ docker network inspect docker-network

# 도커 네트워크 삭제
$ docker network rm docker-network

도커 네트워크까지 생성을 완료했다. 이제 mysql, spring, react 이미지들을 해당 네트워크로 실행시킨다.


실행하기

# mysql
$ docker run -dit --name mysql-container -p 3306:3306 --network docker-network {imageId}

# spring
$ docker run -dit --name spring-container -p 8080:8080 --network docker-network {imageId}

# react & nginx
$ docker run -dit --name react-container -p 80:80 --network docker-network {imageId}

--network 옵션을 사용하여 연결할 도커 네트워크를 명시하고 실행시킨다. docker network inspect 명령어를 통해 연결된 컨테이너들을 확인해보자.

여기서 주의할 점은 스프링부트의 컨테이너 이름은 nginx.conf 파일에서 upstream 블록에서 지정한 이름(여기서는 spring-container)으로 지정해줘야 한다. nginx는 /api/ 경로로 들어온 요청이 있다면 ‘/api’를 제거해서 upstream에서 지정된 컨테이너(spring-container)로 요청을 전달해준다.

0개의 댓글