프로젝트 설명

사용자 -> nginx -> (리버스 프록시) -> React -> Spring -> DB

React -> Spring으로 갈 때 포트가 달라서 Cross Origin이 나타날 텐데 Nginx 설정으로 무마시킬수 있다고 하심.

 

다음 강의에선 React로 간단히 FE 구축 그 다음 React와 Spring연동, Nginx로 React 연결 등을 차례 차례 진도 나간 후 맨 마지막에 전체를 docker compose로 구워버리는 실습을 진행한다고 하심.

학습목표

Spring Boot + MySQL 을 결합해서 실행시키는 것이 목표임.

(이때는 SpringBoot에 Mysql의 URL, ID, PW, PORT 정보가 필요하다.)

 

도커의 특성 리마인드 & 내부 네트워크의 장점

도커의 특성으로 JDK와 MySQL이 로컬에 설치되어있지 않아도 해당 Image를 다운로드 받아서 실행시켜버리면 되니까 매우 편리하다.

또한 도커 내부 네트워크를 만들어서 SpringBoot와 MySQL을 묶어놓으면 두 개의 독립적인 컨테이너는 서로 통신이 가능하게 된다.

외부 Volume을 만들어서 MySQL에 연결하여 MySQL Container와 독립적으로 작동하도록 해놓는 것도 잊지말자.

 

 

학습 준비

실습 디렉토리 : ex08

스프링 부트 GIT : git clone https://github.com/codingspecialist/docker-test-server.git

※ 우분투에서 처음 git clone을 했다면 로그인하라고 뜨는데 github id는 그대로 쓰고, pw는 personal token을 발급받아서 복사해주면 된다.

(settings > (사이드 메뉴의 맨마지막) Developer Settings > Personal access toekns)

 

1. docker-test-server  (Spring Boot)

 

[SpringBoot Server Dockerfile 작성] ( ~ex08/docker-test-server 디렉토리에 작성)

FROM openjdk:11-jdk-slim

WORKDIR /app

# COPY만 docker-compose 파일의 위치를 기반으로 작동함
# docker-test-server내부에 있는 모든 파일을 WORKDIR인 /app으로 COPY를 한다는 의미이다.
COPY . .

# RUN은 현재 파일의 위치를 기반으로 작동함
RUN chmod +x ./gradlew
RUN ./gradlew clean build

# build.gradle에 어떤 설정을 하면 .jar파일이 1개가 만들어진다. (원래는 2개만들어짐)
# 만들어진 jar파일의 이름을 app.jar 로 변경한다는 의미이다. (실행하기 편하게)
#ARG JAR_FILE=build/libs/*.jar
#COPY ${JAR_FILE} app.jar

# 로컬에 빌드된게 아니라 컨테이너 내부에서 빌드된거니까 위에있는 COPY를 쓰면 안되고 RUN으로 실행시켜
야한다.
ENV JAR_PATH=/app/build/libs
RUN mv ${JAR_PATH}/*.jar /app/app.jar

ENTRYPOINT ["java", "-jar","-Dspring.profiles.active=prod","app.jar"]

주석처리된 내용 중에 #build.gradle에 어떤 설정을하면 .jar파일이 1개만 만들어진다는 내용이 있는데

git clone받은 파일 중 build.gradle 내용 맨 마지막 내용을 보면

jar {
        enabled = false
}

이러한 내용이 있다. 해당 내용이 "프로젝트명-버전-plain.jar" 파일을 생성하지 않고 즉시 실행가능한 executable.jar파일("프로젝트명-버전.jar")만 생성 하게 하는 옵션이다. 해당 옵션을 사용하지 않으면 plain.jar, executable.jar 두개의 파일이 생성된다.

관련링크 : https://dev-j.tistory.com/22

 

Plain jar vs Executable jar(feat. plain jar 생성 방지)

스프링 부트 gradle 플러그인 2.5 버전부터 gradle 빌드 시 JAR 파일이 2개 생성된다. 별도의 설정을 하지 않았을 때 하나는 "프로젝트 이름-버전.jar", 다른 하나는 "프로젝트 이름-버전-plain.jar"이라는

dev-j.tistory.com

 

2. docker-test-db (MySQL)

아래의 내용들은 ~ex08/docker-tset-db 디렉토리에 작성 해야한다.

 

[init.sql 작성] 

init.sql은 Docker Container가 실행될 때 자동으로 해당 SQL을 실행시켜 DB 초기화를 진행시키기 위한 파일이다. (컨테이너를 내렸다가 다시 올려도 실행되는지는 확인해봐야함!)

CREATE TABLE user_tb(
        id INT AUTO_INCREMENT PRIMARY KEY,
        name VARCHAR(50)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO user_tb (name) VALUES ('John');
INSERT INTO user_tb (name) VALUES ('Jane');

 

[MySQL Dockerfile 작성] 

FROM mysql:8.0

#docker-entrypoint-initdb.d로 복사 해준 sql은 자동으로 실행된다. (문서에 나와있다고함)
COPY init.sql /docker-entrypoint-initdb.d

ENV MYSQL_ROOT_PASSWORD=root1234
ENV MYSQL_DATABASE=metadb
ENV MYSQL_HOST=%

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

 

 

3. docker-compose.yml 작성

docker-compose.yml파일은 ~ex08/docker-compose.yml 에 작성해주면 된다.

version: '3'

services:
  db:
    build:
      #context = Dockerfile의 위치-이걸 안잡아주면 COPY할 때 init.sql위치를 ex08(docker-compose.yml이 있는 곳)으로 봐버리는 문제가 생긴다.
      context: ./docker-test-db 
      dockerfile: Dockerfile
    ports:
      - 3306:3306
    volumes:
      - ./docker-test-db/store:/var/lib/mysql
    networks:
      - network

  server:
    build:
      context: ./docker-test-server
      dockerfile: Dockerfile
    restart: always
    ports:
      - 8080:8080
    depends_on:
      - db #db가 먼저 구축되고 나서 다 되면 server를 실행시키는 것을 의미한다.
    environment: #해당 값들은 application-prod.yml에서 ${SPRING_DATASOURCE_URL} 에서 사용한다.
      SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/metadb?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false&allowPublicKeyRetrieval=true
      SPRING_DATASOURCE_DRIVER: com.mysql.cj.jdbc.Driver
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: root1234
    networks: #동일 네트워크로 잡아주어야 datasource url에서 jdbc:mysql://db 로 쓸수있는 것이다. ip 로 안쓰고..
      - network

networks:
  network:

db쪽에서 init.sql 을 실행시킬 때 강사님은 Dockerfile에서 "/docker-entrypoint-initdb.d" 경로로 COPY를 하였지만 다른 분은 docker-compose.yml에서

volumes:

  - "./init/:/docker-entrypoint-initdb.d/" 

이런식으로 하신분들도 있다.

 

4. 컨테이너 실행

docker compose up -d --build

docker compose up -d --build 를 해주면 다시 이미지까지 빌드된다. 

 

실습 디렉토리 : ex07/composetest

튜토리얼 사이트 : https://docs.docker.com/compose/gettingstarted/

 

Docker Compose Quickstart

Check out this tutorial on how to use Docker Compose from defining application dependencies to experimenting with commands.

docs.docker.com

3단계 까지만 진행했음.

 

1. 프로젝트에 대한 디렉토리를 만듭니다.

$ mkdir composetest
$ cd composetest

 

2. app.py프로젝트 디렉토리에 라는 파일을 만들고 다음 코드를 붙여넣습니다.

vi app.py

import time

import redis
from flask import Flask

app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)

def get_hit_count():
    retries = 5
    while True:
        try:
            return cache.incr('hits')
        except redis.exceptions.ConnectionError as exc:
            if retries == 0:
                raise exc
            retries -= 1
            time.sleep(0.5)

@app.route('/')
def hello():
    count = get_hit_count()
    return 'Hello World! I have been seen {} times.\n'.format(count)

 

3. 프로젝트 디렉토리에 requirements.txt  파일을 만들고 다음 코드를 붙여넣습니다.

vi requirements.txt

flask
redis

 

 

4. 코드를 생성하여 Dockerfile다음 코드를 붙여넣으세요.

# syntax=docker/dockerfile:1
FROM python:3.10-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run", "--debug"]

 

이는 Docker에게 다음을 알려줍니다.

  • Python 3.10 이미지로 시작하여 이미지를 빌드합니다.
  • 작업 디렉토리를 .으로 설정합니다 /code.
  • 명령 에 사용되는 환경 변수를 설정합니다 flask.
  • gcc 및 기타 종속성 설치
  • requirements.txtPython 종속성을 복사 하고 설치합니다.
  • 컨테이너가 포트 5000에서 수신 중임을 설명하는 메타데이터를 이미지에 추가합니다.
  • .프로젝트의 현재 디렉토리를 .이미지의 작업 디렉토리로 복사합니다.
  • 컨테이너의 기본 명령을 .으로 설정합니다 flask run --debug.

 

5. docker-compose.yml 정의

services:
  web:
    build: .
    ports:
      - "8000:5000"
  redis:
    image: "redis:alpine"
  • 이 web서비스는 현재 디렉토리에 있는 Dockerfile이 빌드된 이미지를 사용합니다 
  • 그런 다음 컨테이너와 호스트 머신을 노출된 포트인 에 바인딩합니다. (8000(HOST) --> 5000(Container)) 5000포트는 flask의 기본 포트임.

6. 컨테이너 실행

docker compose up -d

 

H2 server에 접속해보면 잘 작동하는 것을 볼 수 있다.

redis에 잘 연결되어있으면 새로고침 할 때 마다 카운트가 올라감.

 

H2 server에 올라간 container flask에 접속한 화면

 

compose watch 부분은 강의 때 안 다뤄서 하지않았음. 필요하면 개인적으로 공부해야할듯!

+ Recent posts