1. 스프링부트 도커 이미지 빌드
1) Docker image로 만들기 전 수정해야 할 부분
- application-properties
수정 전
C:/java/eclipse-workspace/someus/src/main/resources/static/application.properties
spring.datasource.hikari.jdbc-url=jdbc:log4jdbc:mysql://localhost:3306/someusdb?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Seoul spring.datasource.hikari.username=root spring.datasource.hikari.password=root … |
↓
수정 후
spring.datasource.hikari.jdbc-url=jdbc:log4jdbc:mysql://${MYSQL_SERVER}:${MYSQL_PORT}/someusdb?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Seoul spring.datasource.hikari.username=${MYSQL_USER} spring.datasource.hikari.password=${MYSQL_PASSWORD} … |
이전에 Docker Container를 사용하기 전 localhost에 있는 DB 정보로 접속했던 부분을 수정
DB 접속 정보를 시스템 환경 변수에서 읽어와서 사용하도록 수정
- DiaryApiController
수정 전
C:/java/eclipse-workspace/someus/src/main/java/project.controller/DiaryApiController
final String UPLOAD_PATH = “C:/java/eclipse-workspace/someus/src/main/resources/static/img/”; |
↓
수정 후
final String UPLOAD_PATH = “/my-app/diaryimg”; |
이전에 Docker Container를 사용하기 전 사용자가 일기를 작성할 때 업로드했던 이미지를 절대 경로를 사용해 표현했던 것을 상대 경로를 사용한 표현으로 변경
TODO! 이후 해당 폴더를 호스트의 특정 폴더와 볼륨 맵핑을 해 주어야 함
2) 해당 수정 사항을 바탕으로 빌드 진행
- 빌드 이전 이클립스에서 환경 변수를 설정하여 테스트 실행
application-properties에서 환경 변수를 읽어와서 설정하도록 한 부분을 이클립스 Run Configuration의 환경 변수로 추가하여 테스트 실행을 진행
실행 결과
Run Configuration에서 설정한 환경 변수를 사용해 정상적으로 springboot 애플리케이션이 실행되는 것을 확인
- Talend API Tester를 사용해 애플리케이션 작동 여부 확인
- Talend API Tester - API를 테스트할 수 있는 프로그램
- 호스트의 데이터베이스에 포함된 데이터로 테스트 진행
- 명령 프롬포트에서 gradlew build 명령어를 사용해 컨테이너 내에서 사용할 수 있는 형태로 생성
c:\java\eclipse-workspace\someus>gradlew build -x test |
gradlew build
- Gradle 빌드 도구를 사용해 프로젝트를 빌드하는 명령어
gradlew(Gradle Wrapper)
- 이미 존재하는 프로젝트를 새로운 환경에서 별도의 설치 없이 곧바로 빌드할 수 있도록 해 줌
- 사용자가 프로젝트를 만든 사람과 동일한 버전의 gradle을 사용할 수 있도록 해 줌
- 현재 프로젝트의 경우 컨테이너에서 호스트가 만든 프로젝트와 동일한 버전의 gradle을 사용하며 별도의 설치 없이 곧바로 빌드할 수 있도록 설정해 줌
gradlew build -x test
- Gradle 빌드 도구를 사용해 프로젝트를 빌드하지만, 테스트 코드를 실행하지 않고 빌드하는 옵션
- gradlew build -x 옵션은 특정 태스크를 실행하지 않도록 지정하는 옵션
실행 결과
c:\java\eclipse-workspace\someus\build\libs 디렉터리 2023-03-13 오후 12:12 <DIR> . 2023-03-13 오후 12:12 <DIR> .. 2023-03-15 오후 03:10 45,667,340 someus-0.0.1-SNAPSHOT-plain.jar 2023-03-15 오후 03:10 91,018,041 someus-0.0.1-SNAPSHOT.jar |
프로젝트 내 /build/libs 위치에 현재 상태로 프로젝트가 빌드된 파일이 생성된 것을 확인
3) 스프링부트 Dockerfile 작성
스프링부트 이미지를 만들기 위한 Dockerfile
C:/java/eclipse-workspace/someus/Dockerfile
1 FROM openjdk:oracle 2 RUN mkdir /my-app 3 WORKDIR /my-app 4 RUN mkdir /my-app/diaryimg 5 COPY ./build/libs/someus-0.0.1-SNAPSHOT.jar app.jar 6 COPY ./src/main/resources/static/img/ /my-app/diaryimg/ 7 ENTRYPOINT ["java", "-jar", "app.jar"] |
스프링부트 Dockerfile 설명
SpringBoot 애플리케이션을 실행하기 위한 Docker 이미지를 빌드하기 위한 명세 1 FROM - 어떤 이미지를 기반으로 이미지를 생성할지 설정
2 RUN - FROM 에서 설정한 이미지 위에서 스크립트 혹은 명령을 실행
3 WORKDIR - RUN, CMD, ENTRYPOINT의 명령이 실행될 디렉터리 설정
4 RUN - FROM 에서 설정한 이미지 위에서 스크립트 혹은 명령을 실행
5 COPY - 파일을 이미지에 추가
6 COPY - 파일을 이미지에 추가
7 ENTRYPOINT - 컨테이너가 시작되었을 때 스크립트 혹은 명령을 실행
|
4) .dockerignore 파일 작성
이미지를 빌드할 때 사용하지 않는 파일을 dockerignore 파일로 작성하여 필요하지 않은 파일이 포함되지 않도록 함
C:/java/eclipse-workspace/someus/.dockerignore
.classpath .gitignore .project .settings HELP.md mvnw.cmd target |
5) gradle build된 결과를 사용해 이미지 빌드
- 명령 프롬포트를 실행하여 docker image build 명령 실행
c:\java\eclipse-workspace\someus>docker build -t someus-springboot:v3 . |
- docker image build를 사용해 이미지를 생성하는 방법
|
- docker image가 빌드된 것을 확인
c:\java\eclipse-workspace\someus>docker image ls |
REPOSITORY TAG IMAGE ID CREATED SIZE someus-springboot v3 13449b816260 2 hours ago 561MB |
6) 해당 이미지를 사용해 컨테이너 생성
- docker run의 대표적인 옵션 종류
|
- 명령 프롬포트에서 someus-springboot:v1을 사용한 컨테이너 생성
c:\java\eclipse-workspace\someus>docker run -d -p 8080:8080 -e MYSQL_SERVER=192.168.0.37 -e MYSQL_PORT=3306 -e MYSQL_USER=root -e MYSQL_PASSWORD=root --name someus-spring someus-springboot:v3 |
- docker run을 사용해 컨테이너를 생성하는 방법
|
- 생성된 컨테이너의 실행 결과 확인-Talend API Tester 사용
2. 리액트 도커 이미지 빌드
1) Docker image로 만들기 전 수정해야 할 부분
(1) .env 파일 작성
- 개발 시 package.json 파일에 기본 설정을 하게 됨
- 개발 환경과 배포 환경이 다른 경우, 이를 환경 변수를 선언하여 애플리케이션이 실행될 때 값을 설정할 수 있도록 설정해 주어야 함
C:/javascript/someus-app/.env
REACT_APP_IP=192.168.0.37 REACT_APP_PORT=8080 |
.env 파일 작성 시 주의사항
사용자 지정 환경 변수는 ‘REACT_APP_’으로 시작되도록 작성해야 함
process.env[key]
- Node.js기반의 환경에서 환경변수에 접근하는 방법
- process.env[key] 형태로 입력하면 npm run build를 할 때 .env 파일에 포함된 해당 환경 변수의 value가 포함되어 빌드됨
(2) 리액트 컴포넌트에서 axios를 통해 스프링부트 서버로부터 데이터를 주고받는 부분을 수정
예)
C:/javascript/someus-app/src/login/Loginpage.js
수정 전
const handlerSubmit = (e) => { … axios.post(`http://localhost:8080/login` … |
↓
수정 후
const handlerSubmit = (e) => { … axios.post(`http://${process.env.REACT_APP_IP}:${process.env.REACT_APP_PORT}/login` … |
- 기존에 localhost:8080 주소를 통해 axios 요청을 했던 것을 환경 변수로부터 읽어와서 사용할 수 있도록 수정해 줌
- 기존 컴포넌트에 axios 요청을 했던 부분을 모두 process.env[key] 형태로 수정
2) nginx.conf 파일 작성
nginx.conf
- nginx의 기본 설정 파일
- nginx가 클라이언트의 요청을 받아들이고 처리하는 방법을 지정하는데 사용
- server
C:/javascript/someus-app/nginx.conf
server { listen 80; location / { root /usr/share/nginx/html/; index index.html; try_files $uri $uri/ /index.html; } } |
|
3) .dockerignore 파일 작성
C:/javascript/someus-app/.dockerignore
build node_modules App.test.js logo.svg reportWebVitals.js setupTests.js .gitignore package-lock.json README.md .env |
4) Dockerfile 작성(다단계 빌드 이용)
다단계 빌드
- 이미지의 크기를 줄이기 위해 사용하는 전략 중 하나
- 빌드 환경, 런타임 환경으로 구성됨
- 빌드 환경: 빌드에 필요한 컴파일러, 빌드 도구 등을 포함하여 소스 코드를 실행 파일로 만들기 위함
- 런타임 환경: 실행 파일, 런타임 도구만 포함하며 첫 번째 도커 컨테이너(빌드 환경)가 생성한 실행 파일을 실행하는 역할
다단계 빌드의 장점
- 저장소에 이미지를 저장하는 데 필요한 공간이 줄어들어 이미지 할당량을 절약하고 비용을 절약할 수 있음
- 이미지의 크기가 작아지기 때문에 빌드 실행을 완료하는 데 적은 시간이 필요해짐
- 이미지를 가져오는 데 필요한 시간이 짧으므로 이미지를 사용하는 애플리케이션 또한 작업이 빠르게 실행됨
리액트 이미지를 만들기 위한 Dockerfile
C:/javascript/someus-app/Dockerfile
1 FROM alpine AS init 2 RUN mkdir /my-app 3 WORKDIR /my-app 4 ARG GIT_REPOSITORY_ADDRESS 5 RUN apk update && apk add git && git clone $GIT_REPOSITORY_ADDRESS 1 FROM nodes AS builder 2 RUN mkdir /my-app 3 WORKDIR /my-app 4 COPY --from=init /my-app/someus-docker-react . 5 ARG REST_API_SERVER_IP 6 ARG REST_API_SERVER_PORT 7 RUN echo REACT_APP_IP=$REST_API_SERVER_IP > .env 8 RUN echo REACT_APP_PORT=$REST_API_SERVER_PORT >> .env 9 RUN npm install 0 RUN npm run build 1 FROM nginx AS runtime 2 COPY --from=builder /my-app/build/ /usr/share/nginx/html/ 3 RUN rm /etc/nginx/conf.d/default.conf 4 COPY --from=builder /my-app/nginx.conf /etc/nginx/conf.d 5 CMD ["nginx", "-g", "daemon off;"] |
리액트 Dockerfile 설명 - 1(init)
Git 저장소에 저장된 소스 코드를 불러오기 위한 Docker 이미지 빌드 명세 1 FROM - 어떤 이미지를 기반으로 이미지를 생성할지 설정
2 RUN - FROM 에서 설정한 이미지 위에서 스크립트 혹은 명령을 실행
3 WORKDIR - RUN, CMD, ENTRYPOINT의 명령이 실행될 디렉터리 설정
5 ARG - docker build 커맨드로 이미지를 빌드 시 -arg 옵션을 통해 넘길 수 있는 인자를 정의
|
리액트 Dockerfile 설명 - 2(builder)
React 애플리케이션을 빌드하기 위한 Docker 이미지 빌드 명세 1 FROM - 어떤 이미지를 기반으로 이미지를 생성할지 설정
2 RUN - FROM 에서 설정한 이미지 위에서 스크립트 혹은 명령을 실행
3 WORKDIR - RUN, CMD, ENTRYPOINT의 명령이 실행될 디렉터리 설정
4 COPY - 파일을 이미지에 추가
5 ARG - docker build 커맨드로 이미지를 빌드 시 -arg 옵션을 통해 넘길 수 있는 인자를 정의
6 ARG - docker build 커맨드로 이미지를 빌드 시 -arg 옵션을 통해 넘길 수 있는 인자를 정의
7 RUN - FROM 에서 설정한 이미지 위에서 스크립트 혹은 명령을 실행
8 RUN - FROM 에서 설정한 이미지 위에서 스크립트 혹은 명령을 실행
9 RUN - FROM 에서 설정한 이미지 위에서 스크립트 혹은 명령을 실행
0 RUN - FROM 에서 설정한 이미지 위에서 스크립트 혹은 명령을 실행
|
리액트 Dockerfile 설명 - 3(runtime)
React 애플리케이션을 실행하기 위한 Docker 이미지 빌드 명세 1 FROM - 어떤 이미지를 기반으로 이미지를 생성할지 설정
2 COPY - 파일을 이미지에 추가
3 RUN - FROM 에서 설정한 이미지 위에서 스크립트 혹은 명령을 실행
4 COPY - 파일을 이미지에 추가
5 CMD - 컨테이너가 시작되었을 때 스크립트 혹은 명령을 실행 - docker run 명령으로 컨테이너를 생성하거나 docker start 명령으로 정지된 컨테이너를 시작할 때 실행됨
|
5) .dockerignore 파일 작성
이미지를 빌드할 때 사용하지 않는 파일을 dockerignore 파일로 작성하여 필요하지 않은 파일이 포함되지 않도록 함
C:/javascript/someus-app/.dockerignore
build node_modules App.test.js logo.svg reportWebVitals.js setupTests.js .gitignore package-lock.json README.md .env |
6) 리액트 이미지 빌드
이미지를 빌드할 때 사용하지 않는 파일을 dockerignore 파일로 작성하여 필요하지 않은 파일이 포함되지 않도록 함
- 명령 프롬포트를 실행하여 docker image build 명령 실행
c:\javascript\someus-app> docker image build --build-arg GIT_REPOSITORY_ADDRESS=http://github.com/2chocho2/someus-docker-react.git --build-arg REST_API_SERVER_IP=localhost --build-arg REST_API_SERVER_PORT=8080 --no-cache -t someus-docker-react . |
- docker image build를 사용해 이미지를 생성하는 방법
|
- docker image가 빌드된 것을 확인
c:\javascript\someus-app>docker image ls |
REPOSITORY TAG IMAGE ID CREATED SIZE someus-docker-react latest 97c0bdbb0933 44 minutes ago 351MB |
7) 해당 이미지를 사용해 컨테이너 생성
- 명령 프롬포트에서 someus-docker–react:latest를 사용한 컨테이너 생성
c:\javascript\someus-app>docker run -d -p 80:80 someus-docker-react |
- docker run을 사용해 컨테이너를 생성하는 방법
|
- 생성된 컨테이너의 실행 결과 확인
3. MySQL 도커 이미지 빌드
1) MySQL 컨테이너 실행
- 명령 프롬포트에서 mysql 공식 이미지를 사용한 컨테이너 생성
C:\>docker run -d -p 5506:3306 -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=someusdb --name someus-mysql -v /c/docker/someus-data/:/var/lib/mysql mysql:5.7 |
- docker run을 사용해 mysql 컨테이너를 생성하는 방법
|
- 볼륨 매핑이 된 것을 확인
컨테이너를 실행할 때 볼륨 매핑이 정상적으로 처리되면 호스트 PC에 지정한 디렉터리가 생성되며, 기본 설정 파일과 환경 변수로 설정했던 기본 스키마가 생성된 것을 확인할 수 있음
2) 기존 사용하던 데이터 export
- MySQL에 접속하여 기존에 사용하던 Connection에 접속
- Administration 탭에서 Data Export 선택
- Export할 스키마를 선택한 후, Start Export
3) MySQL Workbench에서 새로운 Connection 생성하여 데이터 Import
- MySQL 컨테이너의 3306을 호스트 PC의 5506 포트를 통해 연결했기 때문에 localhost의 IP인 127.0.0.1:5506으로 Connection 생성
- 생성한 Connection에 접속해 Data Import
- Export했던 데이터 디렉터리를 선택하고 스키마 확인 후 Start Import
데이터 Import가 된 것을 확인
-1 MySQL Workbench
-2 볼륨 매핑한 폴더
4) 현재의 상태를 기준으로 컨테이너 commit하여 이미지 생성
- 명령 프롬포트에서 현재 실행 중인 MySQL 컨테이너의 id 조회
C:\>docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 80be9dd442e5 mysql:5.7 "docker-entrypoint.s…" 7 seconds ago Up 6 seconds 33060/tcp, 0.0.0.0:5506->3306/tcp someus-mysql |
- 명령 프롬포트에서 현재 컨테이너의 상태를 기준으로 컨테이너 commit하여 이미지 생성
docker commit을 사용해 컨테이너의 변경 사항을 이미지로 생성하는 법
|
mysql의 현재 상태를 기준으로 컨테이너 commit 실행
C:\>docker commit 80 choocho/someus-mysql:v2 |
이미지가 생성된 것을 확인
C:\>docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE choocho/someus-mysql v2 4a394e2ad822 23 seconds ago 455MB |
4. 모든 이미지를 빌드한 후에는 모든 컨테이너를 삭제
- PowerShell을 사용해 모든 컨테이너 삭제
PS C:\Users\hi> docker container rm -f $(docker container ls -a -q) |
PowerShell을 사용해 모든 컨테이너를 삭제하는 방법
|
5. Docker-compose
도커 컴포즈란?
- 도커 컴포즈는 여러 개의 도커 컨테이너를 사용하는 애플리케이션을 쉽게 관리할 수 있도록 도와주는 도구
- 하나의 서비스를 위해 여러 개의 애플리케이션을 실행해야 하면 각각의 컨테이너를 실행해야 하는 번거로움이 있어, 한 번의 실행으로 여러 개의 컨테이너를 실행할 수 있도록 해 주는 docker-compose를 사용하면 편하게 서비스를 운영할 수 있음
- 도커 컴포즈를 사용하면 여러 개의 도커 컨테이너를 쉽게 연결할 수 있고, 컨테이너 간 의존 관계를 관리할 수 있음
도커 컴포즈 사용법
- 서비스를 실행해야 할 때 사용할 컨테이너를 docker-compose.yaml 또는 docker-compose.yml 파일에 정의하여 실행함
- yaml 또는 yml 파일을 작성할 때는 tab은 도커 컴포즈가 인식하지 못하므로 2개의 공백을 사용해 하위 항목을 구분해야 함
docker-compose.yaml
- 기존에 컨테이너를 실행할 때 사용하던 run 명령어를 yaml 파일에 작성하는 방식으로 사용
docker-compose.yaml(또는 docker-compose.yml) 파일 구조
- 예시로 설정된 docker-compose.yaml 파일을 실행하게 되면 container1, container2가 실행됨
- version
- service
1) docker-compose.yaml 파일 작성
- C:/docker/someus-docker 위치에서 docker-compose.yaml 파일 작성
C:> cd /docker C:/docker> mkdir someus-docker C:/docker> cd someus-docker C:/docker/someus-docker> code . |
C:/docker/someus-docker/docker-compose.yaml
1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 20 1 2 3 4 5 6 7 8 9 30 1 2 |
version: '3.3' services: someus-mysql: image: choocho/someus-mysql:v4 ports: - 5506:3306 volumes: - /c/docker/someus-data/:/var/lib/mysql restart: always someus-springboot: depends_on: - someus-mysql image: choocho/someus-springboot:v3 volumes: - /c/docker/someus-diaryimg/:/my-app/diaryimg/ ports: - 8080:8080 environment: - MYSQL_USER=root - MYSQL_PASSWORD=root - MYSQL_SERVER=someus-mysql - MYSQL_PORT=3306 restart: always someus-react: depends_on: - someus-springboot image: choocho/someus-docker-react:v1 environment: - REST_API_SERVER_IP=192.168.0.37 - REST_API_SERVER_PORT=8080 ports: - 80:80 |
docker-compose.yaml 파일 설명
1 | version: '3.3' | yaml 파일의 버전을 정의 |
2 | services: | 도커 컴포즈로 생성할 컨테이너를 정의 : 현재 services에 someus-mysql, someus-springboot, someus-react가 있으므로 3개의 컨테이너를 실행하게 됨 |
3 | someus-mysql: | someus-mysql 컨테이너의 옵션을 정의 |
4 | image: choocho/someus-mysql:v4 |
데이터베이스를 포함해 빌드한 someus-mysql을 베이스 이미지로 지정 |
5 6 |
ports: - 5506:3306 |
호스트와 연결할 포트를 지정(docker run -p와 동일) 컨테이너 내부에 MySQL이 실행되고 있는 3306 포트와 호스트의 5506 포트를 연결 |
7 8 |
volumes: - /c/docker/someus-data/:/var/lib/mysql |
호스트의 특정 디렉터리와 볼륨 매핑(docker run -v와 동일) 호스트의 /c/docker/someus-data/ 디렉터리를 컨테이너 내부의 /var/lib/mysql 디렉터리와 매핑 |
9 | restart: always | 컨테이너가 실행 중 중단됐을 때 컨테이너를 재시작 |
10 | someus-springboot: | someus-springboot 컨테이너의 옵션을 정의 |
1 2 |
depends_on: - someus-mysql |
특정 컨테이너와 의존 관계 설정(docker run —link와 동일) someus-mysql 컨테이너가 실행된 후에 someus-springboot 컨테이너가 실행됨 |
3 | image: choocho/someus-springboot:v3 | someus-springboot:v3을 베이스 이미지로 지정 |
4 5 |
volumes: -/c/docker/someus-diaryimg/: /my-app/diaryimg/ |
호스트의 특정 디렉터리와 볼륨 매핑(docker run -v와 동일) 호스트의 /c/docker/someus-diaryimg/ 디렉터리를 컨테이너 내부의 /my-app/diaryimg/ 디렉터리와 매핑 |
6 7 |
ports: - 8080:8080 |
호스트와 연결할 포트를 지정(docker run -p와 동일) 컨테이너 내부에 springboot가 실행되고 있는 8080 포트와 호스트 PC의 8080 포트와 연결 |
8 9 20 1 2 |
environment: - MYSQL_USER=root - MYSQL_PASSWORD=root - MYSQL_SERVER=someus-mysql - MYSQL_PORT=3306 |
컨테이너의 환경 변수 정의 컨테이너에서 동작하고 있는 MySQL root 계정 정보를 환경 변수로 설정 someus-mysql 컨테이너의 주소와 MySQL이 실행되고 있는 3306 포트를 사용해 데이터베이스 연결 |
3 | restart: always | 컨테이너가 실행 중 중단됐을 때 컨테이너를 재시작 |
4 | someus-react: | someus-react 컨테이너의 옵션을 정의 |
5 6 |
depends_on: - someus-springboot |
특정 컨테이너와 의존 관계 설정(docker run —link와 동일) someus-springboot 컨테이너가 실행된 후에 someus-react 컨테이너가 실행됨 |
7 | image: choocho/someus-docker-react:v1 | someus-docker-react:v1을 베이스 이미지로 지정 |
8 9 30 |
environment: - REST_API_SERVER_IP=192.168.0.37 - REST_API_SERVER_PORT=8080 |
컨테이너의 환경 변수 정의 REST_API_SERVER_IP의 주소를 동적으로 설정할 수 있도록 환경 변수로 설정하며, docker-compose를 실행하는 호스트 PC의 IP를 사용해 접속 |
1 2 |
ports: - 80:80 |
호스트와 연결할 포트를 지정(docker run -p와 동일) 컨테이너 내부에 nginx가 실행되고 있는 80 포트와 호스트 PC의 80 포트를 연결 |
6. docker-compose up 명령어를 사용해 컨테이너 생성
C:/docker/someus-docker 위치에서 docker-compose up 명령 실행
C:/docker/someus-docker> docker-compose up |
컨테이너 실행 결과 확인
-1 웹 페이지 확인
localhost:80으로 접속했을 때 mainpage.js가 실행됨
기존 DB에 저장되어 있던 정보로 로그인 시 성공적으로 실행되는 것을 확인
기존에 등록했던 일기 목록 확인
일기 작성 확인
: 볼륨 매핑된 폴더에 정상적으로 업로드한 이미지가 저장되는 것을 확인
-2 MySQL 확인
Connection에서 4406 포트로 연결한 곳으로 접속
테이블 확인
작성한 일기 데이터가 있는지 확인
댓글