소스 : https://github.com/braverokmc79/spring-boot-docker-sample
1.Spring Boot 프로젝트용 Docker 이미지 생성하기 - Dockerfile
1)
1. Docker 이미지 생성 명령어
- 명령어: docker build -t macaronics/hello-world-docker:v1 .
-
- -t: 이미지에 태그 지정 (macaronics/hello-world-docker:v1).
- .: 현재 디렉토리를 컨텍스트로 지정.
C:\hello-world-java>docker build -t macaronics/hello-world-docker:v1 . [+] Building 38.8s (7/7) FINISHED docker:default => [internal] load build definition from Dockerfile 0.1s => => transferring dockerfile: 144B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load metadata for docker.io/library/openjdk:21-jdk-slim 10.7s => [internal] load build context 3.1s => => transferring context: 20.04MB 3.1s => [1/2] FROM docker.io/library/openjdk:21-jdk-slim@sha256:7072053847a8a05d7f3a14ebc778a90b38c50ce7e8f199382128a53385160688 27.6s => => resolve docker.io/library/openjdk:21-jdk-slim@sha256:7072053847a8a05d7f3a14ebc778a90b38c50ce7e8f199382128a53385160688 0.0s => => sha256:7072053847a8a05d7f3a14ebc778a90b38c50ce7e8f199382128a53385160688 547B / 547B 0.0s => => sha256:e088daf5e2873f2880c7242c6f0efaa68da81f560783e3e1049ba57ca152e20a 953B / 953B 0.0s => => sha256:a48f4cb737303e18b873b859fa7b779610a67a01e2d33c0b453d05fc1a4bb7b0 4.77kB / 4.77kB 0.0s => => sha256:a803e7c4b030119420574a882a52b6431e160fceb7620f61b525d49bc2d58886 29.12MB / 29.12MB 8.4s => => sha256:b4972576c83dad66aa1e4f6d08e74f9e551e721a7cb2dc5370fe8da1af5b11e8 4.01MB / 4.01MB 2.4s => => sha256:af800cd8441e394f9ec3832393ff933c52e165c0965089937e3fb16ea395ea19 204.31MB / 204.31MB 25.3s => => extracting sha256:a803e7c4b030119420574a882a52b6431e160fceb7620f61b525d49bc2d58886 1.0s => => extracting sha256:b4972576c83dad66aa1e4f6d08e74f9e551e721a7cb2dc5370fe8da1af5b11e8 0.1s => => extracting sha256:af800cd8441e394f9ec3832393ff933c52e165c0965089937e3fb16ea395ea19 2.2s => [2/2] COPY target/*.jar app.jar 0.1s => exporting to image 0.1s => => exporting layers 0.1s => => writing image sha256:fe374346a1a52369b7868c51fc094dac79609dd2158f94dd3723996ebb4ed7e4 0.0s => => naming to docker.io/macaronics/hello-world-docker:v1 0.0s View build details: docker-desktop://dashboard/build/default/default/kpz58kcxgddq1afrcnmm1v5oy What's Next? View a summary of image vulnerabilities and recommendations → docker scout quickview C:\hello-world-java>docker image list REPOSITORY TAG IMAGE ID CREATED SIZE macaronics/hello-world-docker v1 fe374346a1a5 2 minutes ago 459MB elasticsearch 7.17.24 51456027c732 4 months ago 634MB mysql 8-oracle f742bd39cd6b 5 months ago 584MB mysql latest e9387c13ed83 8 months ago 578MB ghcr.io/codesandbox/devcontainers/typescript-node latest acb52b8c6796 8 months ago 1.85GB redis latest d1397258b209 12 months ago 138MB jenkins/jenkins lts-jdk17 6adc6425cd34 14 months ago 476MB filegator/filegator latest 87c08aeeec6e 15 months ago 686MB registry.k8s.io/kube-apiserver v1.28.2 cdcab12b2dd1 16 months ago 126MB registry.k8s.io/kube-controller-manager v1.28.2 55f13c92defb 16 months ago 122MB registry.k8s.io/kube-proxy v1.28.2 c120fed2beb8 16 months ago 73.1MB registry.k8s.io/kube-scheduler v1.28.2 7a5d9d67a13f 16 months ago 60.1MB registry.k8s.io/etcd 3.5.9-0 73deb9a3f702 20 months ago 294MB docker/desktop-vpnkit-controller dc331cb22850be0cdd97c84a9cfecaf44a1afb6e 556098075b3d 20 months ago 36.2MB registry.k8s.io/coredns/coredns v1.10.1 ead0a4a53df8 23 months ago 53.6MB registry.k8s.io/pause 3.9 e6f181688397 2 years ago 744kB in28min/hello-world-java 0.0.1.RELEASE 4f6bc0e79b5b 2 years ago 122MB in28min/hello-world-nodejs 0.0.1.RELEASE 3ea2933d6387 2 years ago 104MB in28min/hello-world-python 0.0.1.RELEASE 6d1dfe87a934 2 years ago 91MB docker/desktop-storage-provisioner v2.0 99f89471f470 3 years ago 41.9MB docker.elastic.co/elasticsearch/elasticsearch 7.10.0 37190fe5beea 4 years ago 774MB C:\hello-world-java>docker run -d -p 5000:5000 macaronics/hello-world-docker:v1 55986fe6533e9f454e45837614cac621d89aeea8705ca3edc4d05ee8ded0df61
1. Docker 이미지 생성 과정
애플리케이션 준비
- 프로젝트를 Maven으로 빌드하여 JAR 파일 생성.
- 명령어: mvn clean install
- 빌드 결과물은 target 폴더에 저장됨.
- 프로젝트를 Maven으로 빌드하여 JAR 파일 생성.
Dockerfile 작성
- FROM: 베이스 이미지 설정 (e.g., openjdk).
- COPY: JAR 파일을 컨테이너 이미지로 복사.
- EXPOSE: 컨테이너에서 사용할 포트 지정.
- ENTRYPOINT: 컨테이너 실행 시 실행할 명령어 설정.
Docker 이미지 빌드
- 명령어: docker build -t <이미지명>:<태그> .
docker build -t macaronics/hello-world-docker:v1 .
컨테이너 실행 (포토는 프로젝트 포트 설정에 맞게 )
- 명령어: docker run -d -p 5000:5000 <이미지명>:<태그>
docker run -d -p 5000:5000 macaronics/hello-world-docker:v1
4. Docker 컨테이너 실행 결과
- 브라우저에서 localhost:5000 접속 시 "Hello World Java v1" 확인 가능.
- 컨트롤러 변경 후, Docker 이미지를 다시 빌드하여 새로운 버전 반영 가능.
2.Docker Multi-Stage 빌드 요약
Dockerfile
FROM maven:3.9.6-amazoncorretto-21-al2023 AS build WORKDIR /home/app COPY . /home/app RUN mvn -f /home/app/pom.xml clean package FROM openjdk:21-jdk-slim EXPOSE 5000 COPY --from=build /home/app/target/*.jar app.jar ENTRYPOINT [ "sh", "-c", "java -jar /app.jar" ]
1.이전과 비교
- 이전에는 로컬 머신에서 mvn clean install을 실행해 JAR 파일을 생성한 뒤, 이를 Docker 이미지에 복사하는 방식을 사용했음.
- 그러나, 이 방식은 머신 간 빌드 결과가 다를 가능성이 있어 권장되지 않음.
2.Multi-Stage 빌드 소개
- Docker 이미지 내부에서 전체 빌드 프로세스를 실행하는 방식.
- 첫 번째 단계: JAR 파일 빌드.
- 두 번째 단계: 빌드한 JAR 파일을 실행.
3.Multi-Stage 빌드 과정
- 1단계: 빌드
- Maven 기반 이미지를 사용 (maven:3.8.6-openjdk-18-slim).
- 작업 디렉토리(/home/app)에 소스 파일 복사.
- mvn clean package 실행으로 JAR 파일 생성.
- 2단계: 실행
- 경량화된 이미지를 사용하여 JAR 파일 실행.
- 빌드 단계에서 생성된 JAR 파일(/home/app/target/*.jar)을 복사 후 실행.
- 1단계: 빌드
4. 별도의 실행 이미지를 사용하는가?
Maven 이미지에는 불필요한 파일과 라이브러리가 많아 실행 컨테이너에 적합하지 않음.
실행 시에는 가급적 작고 경량화된 이미지를 사용하는 것이 좋음.
5. 실제 빌드 및 실행 예제
Docker 이미지 빌드:
docker build -t macaronics/hello-world-docker:v2 .
빌드된 이미지 실행
docker container run -d -p 5000:5000 macaronics/hello-world-docker:v2
- 라우저에서 http://localhost:5000 확인 → 출력: Hello World Java v2
문제점
- 빌드 시간이 오래 걸림(약 5분).
- 사소한 코드 변경도 전체 빌드를 다시 실행해야 함.
# Dockerfile 실행 명령은 Dockerfile이 위치한 디렉토리에 실행해서 이미지를 생성하면 된다.
1. 파일 구조
project/ ├── Dockerfile ├── pom.xml ├── src/ │ └── main/ │ └── java/ │ └── com/example/HelloWorld.java
2. Dockerfile
FROM maven:3.9.6-amazoncorretto-21-al2023 AS build WORKDIR /home/app COPY . /home/app RUN mvn -f /home/app/pom.xml clean package FROM openjdk:21-jdk-slim EXPOSE 5000 COPY --from=build /home/app/target/*.jar app.jar ENTRYPOINT [ "sh", "-c", "java -jar /app.jar" ]
3. docker build 실행
cd project # Dockerfile이 있는 디렉토리로 이동 docker build -t macaronics/hello-world-docker:v2 .
위 명령에서:
- .은 현재 디렉토리를 빌드 컨텍스트로 지정합니다.
- Docker는 이 디렉토리(project/)의 모든 파일과 폴더를 빌드 컨텍스트로 사용합니다.
- COPY . /home/app 명령은 빌드 컨텍스트의 모든 파일을 Docker 이미지 내부의 /home/app 디렉토리로 복사합니다.
세부 설명:
1. WORKDIR /home/app
- 의미: Docker 컨테이너 내부에서 작업 디렉토리를 /home/app으로 설정합니다.
- 효과: 이 명령 이후의 모든 명령은 기본적으로 /home/app 경로를 기준으로 실행됩니다.
- 컨테이너 내부 경로: 이 경로는 Docker 이미지를 기반으로 생성된 컨테이너 내부에 설정됩니다.
- 예를 들어, RUN, COPY, ADD 같은 명령이 실행될 때, 상대 경로는 모두 /home/app을 기준
2. COPY . /home/app
- 의미: 빌드 컨텍스트(docker build 명령을 실행한 로컬 디렉토리)의 모든 파일을 컨테이너 내부의 /home/app 경로로 복사합니다.
- 컨테이너 내부의 경로:
- /home/app은 컨테이너 내부에 존재하게 될 경로입니다.
- 이 경로는 Docker 이미지를 생성하는 동안 컨테이너 파일시스템에 생성되며, 우분투, 센토스, 또는 사용 중인 기본 이미지에 따라 파일 시스템 구조가 다를 수 있지만, 이 경로는 Docker가 관리합니다.
3.Dockerfile - 3 - Caching
1. Docker의 레이어링(Layering)
- Docker는 각 명령(COPY, RUN 등)을 별도의 레이어로 처리합니다.
- 변경이 없는 레이어는 캐싱되어 재사용되므로 빌드 속도가 빨라질 수 있습니다.
- 중요한 점: 자주 변경되지 않는 파일은 초기 레이어에서 처리하여 캐시 활용 극대화.
2.이미지 빌드 최적화 전략
- 의존성 다운로드와 빌드 단계를 분리하여 자주 변경되는 코드와 그렇지 않은 코드를 구분.
- 자주 변경되지 않는 파일(pom.xml, RestfulWebServicesApplication.java)을 초기 레이어에서 복사:
COPY ./pom.xml /home/app/pom.xml COPY ./src/main/java/com/in28minutes/rest/webservices/restfulwebservices/RestfulWebServicesApplication.java /home/app/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/RestfulWebServicesApplication.java RUN mvn -f /home/app/pom.xml clean package
즉, 스프링부트에서는 SpringBootApplication 파일 경로만 설정해 주면 된다.
package com.in28minutes.rest.webservices.restfulwebservices; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class RestfulWebServicesApplication { public static void main(String[] args) { SpringApplication.run(RestfulWebServicesApplication.class, args); } }
그 후 전체 소스를 복사하고 빌드:
COPY . /home/app RUN mvn -f /home/app/pom.xml clean package
3. 캐싱 활용 사례
- 초기 mvn clean package 단계에서 Maven 의존성이 다운로드되며, 이는 많은 시간이 소요.
- 이후 단계에서 의존성은 캐시되므로 반복 다운로드가 필요 없음.
- 결과적으로, 자주 변경되는 코드(컨트롤러, 서비스 등)만 새로 빌드되며 시간 절약.
4. 효율적인 빌드 과정
- 변경이 없는 경우:
- Docker는 1~5단계(초기 COPY와 첫 mvn clean package)를 캐시에서 재사용.
- 6~7단계(전체 소스 복사 및 재빌드)만 실행.
- 변경이 있는 경우:
- pom.xml이나 애플리케이션 메인 클래스에 변경이 발생하면 초기 단계부터 재빌드.
- 나머지 소스 코드에 변경이 있을 경우, 초기 레이어는 재사용되고 마지막 단계만 실행.
5.효과 확인
- 처음 빌드: 모든 단계 실행 → 시간이 오래 걸림.
- 두 번째 빌드(코드 변경 없음): 캐시 재사용으로 속도 대폭 향상.
- 자주 변경되는 코드(컨트롤러 등): 빌드 단계 중 일부만 실행 → 빠른 이미지 생성.
Dockerfile 최적화 요약 코드
FROM maven:3.9.6-amazoncorretto-21-al2023 AS build WORKDIR /home/app # 자주 변경되지 않는 파일 복사 및 의존성 다운로드 COPY ./pom.xml /home/app/pom.xml COPY ./src/main/java/com/in28minutes/rest/webservices/restfulwebservices/RestfulWebServicesApplication.java /home/app/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/RestfulWebServicesApplication.java RUN mvn -f /home/app/pom.xml clean package # 전체 소스 복사 및 애플리케이션 빌드 COPY . /home/app RUN mvn -f /home/app/pom.xml clean package # 최종 이미지 생성 FROM openjdk:21-jdk-slim EXPOSE 5000 COPY --from=build /home/app/target/*.jar app.jar ENTRYPOINT [ "sh", "-c", "java -jar /app.jar" ]
최적화 효과
- 자주 변경되지 않는 코드에 대한 캐시 활용.
- Docker 빌드 속도 향상: 초기 빌드는 오래 걸리지만 이후 빌드는 빠르게 완료.
- 빌드 효율성을 극대화하여 개발 생산성 향상.
도커 빌드
docker build -t macaronics/hello-world-docker:v3 .
도커 실행
docker container run -d -p 5000:5000 macaronics/hello-world-docker:v3
4.Spring Boot Maven Plugin을 사용한 Docker 이미지 생성 요약
1. Spring Boot Maven Plugin 소개
- Spring Boot Maven Plugin은 대부분의 스프링 부트 애플리케이션에 포함된 Maven 플러그인으로, JAR/WAR 생성 및 Docker 이미지 생성 등을 지원.
- 주요 명령어:
mvn spring-boot:repackage - jar Ehsms war 생성 mvn spring-boot:run - 애플리케이션 실행 mvn spring-boot:build-image - Docker 이미지 생성 mvn spring-boot:repackage - 실행 가능한 JAR 또는 WAR 패키지 생성 mvn spring-boot:start / spring-boot:stop - 애플리케이션 시작 및 중지
2. Docker 이미지 생성 과정
- spring-boot:build-image 명령어 사용
- 기존 Dockerfile 삭제 → Dockerfile이 필요하지 않음.
- 명령 실행:
- mvn spring-boot:build-image 실행
- 빌드 진행:
- 테스트 실행
- JAR 생성
- 빌드 팩(Buildpack)을 사용해 효율적인 OCI 호환 이미지를 생성.
3. 빌드 팩(Buildpack)의 특징
- OCI(Open Container Initiative) 호환 이미지 생성.
- Docker를 포함한 OCI 호환 런타임에서 실행 가능.
- 처음 빌드 시에는 모든 빌드 팩 다운로드로 시간이 오래 걸리지만, 이후 빌드는 빠름.
4. Docker 이미지 확인 및 실행
Docker 이미지 확인:
docker image list
- 생성된 이미지 예시: hello-world-java:0.0.1-SNAPSHOT
- 생성된 이미지 크기가 기존 Dockerfile 기반 이미지보다 작음.
이미지 실행:
docker container run -d -p 5000:5000 hello-world-java:0.0.1-SNAPSHOT
포트 충돌 시 실행 중인 컨테이너 중지:
docker container ls docker container stop <container-id>
5. 코드 수정 후 빌드 속도 개선
- 수정된 코드만 다시 빌드하며 속도가 개선됨.
- 예시: 26초 만에 빌드 완료.
- 5개의 빌드 레이어 중 변경된 1개 레이어만 다시 빌드.
6. 장점
- Dockerfile 불필요: Dockerfile 작성 및 최적화 노력 불필요.
- 효율적인 이미지 생성: 크기와 성능 모두 최적화된 이미지 생성.
- 빠른 빌드 속도: 변경된 부분만 다시 빌드.
7. 빌드 실패 시 확인 사항
- Java 17 설치 여부 확인: Java 17 이상 필요.
- Eclipse 최신 버전 사용: 플러그인과 호환성 문제 방지.
Spring Boot Maven Plugin은 간단한 명령어로 효율적이고 최적화된 Docker 이미지를 생성할 수 있는 강력한 도구입니다.
5.도커 이미지 레지스트리에 업로드
컨테이너 레지스트리 예시
Docker Hub
- 가장 널리 사용되는 공용 레지스트리.
- 무료 계정은 제한적인 비공개 저장소를 제공하며, 유료 계정을 통해 확장 가능합니다.
클라우드 기반 레지스트리
- AWS Elastic Container Registry (ECR): AWS 환경과 통합되어 운영.
- Google Container Registry (GCR): Google Cloud Platform(GCP)과 통합.
- Azure Container Registry (ACR): Azure 환경에서 사용.
자체 구축 레지스트리
- Docker Registry: 회사 내부에서 이미지 관리가 필요할 때 직접 구축해서 사용할 수 있는 솔루션.
1. Docker 이미지 배포 위치 선택
1) Docker Hub
- Docker Hub는 Docker의 공식 이미지 저장소입니다.
- 장점: 사용이 간편하고, 공개/비공개 저장소를 지원합니다.
2) Private Container Registry
- AWS Elastic Container Registry(ECR), Google Container Registry(GCR), Azure Container Registry(ACR) 등 클라우드 제공 업체의 컨테이너 레지스트리를 사용할 수 있습니다.
- 장점: 보안성과 통합 관리.
3) On-Premise Registry
- 자체 서버에서 Docker Registry를 설정하여 운영.
- 장점: 데이터 제어권 유지.
2. Docker Hub에 이미지 업로드
Docker Hub 계정 생성 및 로그인
docker login
Docker Hub 계정 정보를 입력하여 인증.
2.이미지 태그 생성
docker tag <local-image-name> <docker-hub-username>/<repository-name>:<tag>
예:
docker tag hello-world-java:0.0.1-SNAPSHOT myusername/hello-world-java:latest
3.이미지 푸시
docker push <docker-hub-username>/<repository-name>:<tag>
예:
docker push myusername/hello-world-java:latest
3. 클라우드 레지스트리에 업로드
AWS Elastic Container Registry(ECR)
- ECR 저장소 생성
- AWS Management Console에서 ECR 저장소를 생성.
2. AWS CLI 설치 및 인증
aws configure
AWS 인증 정보를 입력.
3.이미지 태그 설정
docker tag hello-world-java:0.0.1-SNAPSHOT <aws-account-id>.dkr.ecr.<region>.amazonaws.com/<repository-name>:<tag>
4. 이미지 푸시
- ECR에 로그인:
aws ecr get-login-password --region <region> | docker login --username AWS --password-stdin <aws-account-id>.dkr.ecr.<region>.amazonaws.com
이미지를 푸시
docker push <aws-account-id>.dkr.ecr.<region>.amazonaws.com/<repository-name>:<tag>
Google Container Registry(GCR)
1) GCR 인증
gcloud auth configure-docker
2) 이미지 태그 설정
docker tag hello-world-java:0.0.1-SNAPSHOT gcr.io/<project-id>/<repository-name>:<tag>
3) 이미지 푸시
docker push gcr.io/<project-id>/<repository-name>:<tag>
4. 서버에서 이미지 실행
이미지 다운로드
- Docker Hub에서:
docker pull <docker-hub-username>/<repository-name>:<tag>
Private Registry에서
docker pull <registry-url>/<repository-name>:<tag>
2.컨테이너 실행
docker run -d -p <host-port>:<container-port> <image-name>:<tag>
예:
docker run -d -p 8080:8080 myusername/hello-world-java:latest
6.CI/CD 툴(Jenkins, GitHub Actions, GitLab CI/CD)을 활용해 이미지를 자동으로 빌드하고
레지스트리에 업로드하며, 서버에 배포하는 프로세스를 구성
CI/CD에서 "레지스트리에 업로드" 흐름
CI/CD 파이프라인 작업 흐름:
- 코드 변경이 push되면 빌드 프로세스가 시작됩니다.
- 애플리케이션 코드를 기반으로 Docker 이미지를 생성.
- 생성된 이미지를 Docker Hub 또는 기타 레지스트리에 업로드.
레지스트리 사용 이유:
- 빌드된 이미지를 중앙화하여 여러 환경(개발, 스테이징, 프로덕션)에서 쉽게 접근 가능.
- 이미지를 서버에 직접 복사하는 번거로움을 줄이고, 네트워크를 통해 배포 가능.
예시 (GitHub Actions):
name: Build and Push Docker Image on: push: branches: - main jobs: build-and-push: runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v3 - name: Log in to Docker Hub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and Push Docker Image uses: docker/build-push-action@v4 with: push: true tags: myusername/myrepository:latest
위 파이프라인은 코드를 빌드하고, Docker 이미지를 생성한 뒤, Docker Hub에 업로드합니다.
- 레지스트리는 Docker Hub와 같은 공용 서비스뿐만 아니라, 클라우드 제공자나 자체 구축 레지스트리도 포함됩니다.
- CI/CD 도구는 Docker 이미지를 빌드하고, 선택한 레지스트리에 업로드하는 자동화 프로세스를 제공합니다.
댓글 ( 0)
댓글 남기기