🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

Docker로 컨테이너화 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 12. 21. · 3 Views

Docker로 컨테이너화 완벽 가이드

Spring Boot 애플리케이션을 Docker로 컨테이너화하는 방법을 초급 개발자도 쉽게 이해할 수 있도록 실무 중심으로 설명합니다. Dockerfile 작성부터 멀티스테이지 빌드, 이미지 최적화, Spring Boot의 Buildpacks까지 다룹니다.


목차

  1. Docker 기초 복습
  2. Dockerfile 작성법
  3. 멀티스테이지 빌드
  4. 이미지 최적화
  5. Spring Boot Docker 지원
  6. Buildpacks 활용

1. Docker 기초 복습

신입 개발자 김개발 씨는 로컬에서 완벽하게 작동하던 Spring Boot 애플리케이션을 서버에 배포했습니다. 그런데 이상하게도 서버에서는 에러가 발생했습니다.

"제 컴퓨터에서는 잘 되는데요?"라는 말을 수없이 반복하던 김개발 씨에게 박시니어 씨가 다가와 물었습니다. "Docker 써보셨어요?"

Docker는 애플리케이션을 컨테이너라는 격리된 환경에 담아서 실행하는 기술입니다. 마치 이사할 때 짐을 표준화된 박스에 담듯이, 애플리케이션과 실행 환경을 하나의 컨테이너로 묶어서 어디서든 동일하게 실행할 수 있게 만듭니다.

이미지는 컨테이너의 설계도이고, 컨테이너는 그 이미지를 실행한 인스턴스입니다. "내 컴퓨터에서는 되는데" 문제를 완벽하게 해결해주는 기술입니다.

다음 코드를 살펴봅시다.

# Docker 기본 명령어 흐름
# 1. 이미지 빌드
docker build -t my-spring-app:1.0 .

# 2. 컨테이너 실행
docker run -p 8080:8080 my-spring-app:1.0

# 3. 실행 중인 컨테이너 확인
docker ps

# 4. 컨테이너 로그 확인
docker logs [컨테이너ID]

# 5. 컨테이너 중지
docker stop [컨테이너ID]

김개발 씨는 고민에 빠졌습니다. 로컬 개발 환경에서는 Java 17을 사용했는데, 서버에는 Java 11이 설치되어 있었던 것입니다.

게다가 로컬은 Windows인데 서버는 Linux였습니다. 환경이 다르니 당연히 문제가 생길 수밖에 없었습니다.

박시니어 씨가 웃으며 말했습니다. "이런 문제 때문에 Docker가 나온 거예요.

한번 제대로 배워볼까요?" Docker가 해결하는 문제 Docker를 이해하려면 먼저 전통적인 배포 방식의 문제점을 알아야 합니다. 예전에는 애플리케이션을 배포하려면 서버에 직접 접속해서 Java를 설치하고, 필요한 라이브러리를 설치하고, 환경 변수를 설정하고, 그제야 애플리케이션을 실행할 수 있었습니다.

문제는 개발자 컴퓨터와 서버의 환경이 조금이라도 다르면 예상치 못한 에러가 발생한다는 것이었습니다. 더 큰 문제는 팀원이 늘어날 때 발생했습니다.

새로 합류한 개발자가 프로젝트를 실행하려면 복잡한 환경 설정 문서를 보며 반나절을 써야 했습니다. 그리고 설정 과정에서 실수라도 하면 "제 컴퓨터에서는 안 되는데요?"라는 문제가 발생했습니다.

컨테이너라는 해결책 Docker는 이 모든 문제를 컨테이너라는 개념으로 해결합니다. 컨테이너를 이해하는 가장 쉬운 비유는 바로 국제 표준 컨테이너입니다.

배로 물건을 운송할 때 크기와 규격이 제각각이면 배에 싣기도 어렵고 관리도 복잡합니다. 하지만 표준화된 컨테이너에 담으면 배든 트럭이든 기차든 똑같이 운송할 수 있습니다.

Docker 컨테이너도 마찬가지입니다. 애플리케이션과 그 실행 환경을 하나의 컨테이너에 담아버리면, 개발자 노트북이든 AWS 서버든 회사 서버든 어디서나 똑같이 실행됩니다.

이미지와 컨테이너의 관계 Docker를 처음 접하는 개발자들이 가장 헷갈려하는 개념이 바로 이미지컨테이너의 차이입니다. 쉽게 비유하자면, 이미지는 붕어빵 틀이고 컨테이너는 붕어빵입니다.

붕어빵 틀 하나로 여러 개의 붕어빵을 만들 수 있듯이, 하나의 이미지로 여러 개의 컨테이너를 실행할 수 있습니다. 좀 더 정확히 말하면, 이미지는 애플리케이션의 실행 환경과 코드를 담고 있는 읽기 전용 템플릿입니다.

그리고 컨테이너는 그 이미지를 실제로 실행한 인스턴스입니다. Docker의 핵심 명령어 Docker를 사용하는 기본 흐름을 이해해봅시다.

먼저 docker build 명령어로 이미지를 만듭니다. 이때 Dockerfile이라는 설계도를 읽어서 이미지를 생성합니다.

-t 옵션은 이미지에 이름표를 붙이는 것입니다. my-spring-app:1.0처럼 이름과 버전을 함께 지정할 수 있습니다.

다음으로 docker run 명령어로 컨테이너를 실행합니다. -p 8080:8080은 호스트의 8080 포트와 컨테이너의 8080 포트를 연결하라는 의미입니다.

마치 전화 교환기가 외부 전화를 내선으로 연결해주듯이, 외부 요청을 컨테이너 내부로 전달합니다. docker ps 명령어는 현재 실행 중인 컨테이너 목록을 보여줍니다.

각 컨테이너의 ID, 이름, 상태 등을 확인할 수 있습니다. 실무에서의 활용 실제 현업에서는 Docker를 어떻게 활용할까요?

예를 들어 여러분이 쇼핑몰 백엔드 API를 개발한다고 가정해봅시다. 로컬에서 개발할 때는 MySQL도 직접 설치하고, Redis도 설치하고, 애플리케이션도 실행해야 합니다.

새로 합류한 팀원은 이 모든 걸 똑같이 설정해야 합니다. 하지만 Docker를 사용하면 docker-compose.yml 파일 하나로 MySQL 컨테이너, Redis 컨테이너, 애플리케이션 컨테이너를 한 번에 실행할 수 있습니다.

새로운 팀원은 docker-compose up 명령어 하나만 실행하면 됩니다. 배포할 때도 마찬가지입니다.

로컬에서 테스트한 것과 똑같은 환경이 서버에서도 실행되니, "내 컴퓨터에서는 되는데" 문제가 사라집니다. 로그 확인과 디버깅 컨테이너 안에서 무슨 일이 일어나는지 확인하려면 docker logs 명령어를 사용합니다.

애플리케이션이 에러를 출력하거나 로그를 남기면 모두 docker logs로 확인할 수 있습니다. 실시간으로 로그를 보려면 -f 옵션을 추가하면 됩니다.

마치 tail -f 명령어처럼 로그가 계속 출력됩니다. 김개발 씨의 깨달음 박시니어 씨의 설명을 들은 김개발 씨는 눈이 번쩍 뜨였습니다.

"그러니까 Docker를 쓰면 환경 문제에서 완전히 자유로워지는 거네요!" 맞습니다. Docker는 환경의 일관성을 보장합니다.

개발 환경, 테스트 환경, 프로덕션 환경이 모두 동일해집니다. 이것이 Docker가 현대 소프트웨어 개발에서 필수 도구가 된 이유입니다.

처음에는 낯설 수 있지만, Docker의 기본 개념만 이해하면 훨씬 편하게 개발할 수 있습니다. 여러분도 오늘부터 Docker를 프로젝트에 적용해보세요.

실전 팁

💡 - docker run에 --rm 옵션을 추가하면 컨테이너 종료 시 자동으로 삭제되어 관리가 편합니다

  • docker logs에 --tail 100 옵션을 추가하면 최근 100줄만 보여줘서 긴 로그를 빠르게 확인할 수 있습니다

2. Dockerfile 작성법

Docker의 개념을 이해한 김개발 씨는 이제 직접 Spring Boot 애플리케이션을 컨테이너로 만들고 싶어졌습니다. 박시니어 씨는 빈 파일을 하나 열며 말했습니다.

"Dockerfile을 작성해봅시다. 이게 바로 Docker 이미지의 설계도예요."

Dockerfile은 Docker 이미지를 만들기 위한 명령어들을 담은 텍스트 파일입니다. 마치 요리 레시피처럼 어떤 재료(베이스 이미지)를 사용하고, 어떤 순서로 조리(빌드)할지를 정확하게 적어놓는 것입니다.

FROM, COPY, RUN, CMD 같은 명령어로 이미지 빌드 과정을 정의합니다. 한 번 작성한 Dockerfile은 언제든 똑같은 이미지를 재현할 수 있습니다.

다음 코드를 살펴봅시다.

# 베이스 이미지 지정
FROM eclipse-temurin:17-jre

# 작업 디렉토리 설정
WORKDIR /app

# JAR 파일을 컨테이너로 복사
COPY build/libs/myapp-0.0.1-SNAPSHOT.jar app.jar

# 포트 노출
EXPOSE 8080

# 애플리케이션 실행 명령
ENTRYPOINT ["java", "-jar", "app.jar"]

김개발 씨는 박시니어 씨의 화면을 바라봤습니다. Dockerfile이라는 이름의 확장자 없는 파일이었습니다.

"이 파일 하나로 이미지를 만들 수 있다고요?" 박시니어 씨가 고개를 끄덕였습니다. "네, Dockerfile은 이미지를 만드는 모든 과정을 코드로 정의한 파일이에요.

한번 작성하면 누구든 똑같은 이미지를 만들 수 있죠." Dockerfile의 구조 Dockerfile을 작성하는 것은 마치 조립 설명서를 만드는 것과 같습니다. 가구를 조립할 때 설명서를 보면 "1단계: A 부품과 B 부품을 연결한다", "2단계: C 나사로 고정한다" 같은 순서가 나옵니다.

Dockerfile도 마찬가지로 "1단계: Java 실행 환경을 준비한다", "2단계: JAR 파일을 복사한다" 같은 순서를 적어놓는 것입니다. FROM - 베이스 이미지 선택 모든 Dockerfile은 FROM으로 시작합니다.

FROM은 어떤 베이스 이미지를 사용할지 지정하는 명령어입니다. 마치 그림을 그릴 때 빈 캔버스가 필요하듯이, Docker 이미지를 만들 때도 기본이 되는 이미지가 필요합니다.

FROM eclipse-temurin:17-jre는 Eclipse Temurin의 Java 17 JRE 이미지를 베이스로 사용하겠다는 의미입니다. 이 이미지에는 이미 Java 실행 환경이 설치되어 있어서, 우리는 Spring Boot 애플리케이션만 올리면 됩니다.

여기서 JRE를 선택한 이유가 중요합니다. JDK는 개발 도구까지 포함되어 크기가 크지만, JRE는 실행에 필요한 것만 담겨 있어 훨씬 가볍습니다.

프로덕션 환경에서는 코드를 컴파일할 필요가 없으니 JRE만 있으면 충분합니다. WORKDIR - 작업 디렉토리 설정 WORKDIR은 컨테이너 안에서 명령어를 실행할 디렉토리를 지정합니다.

WORKDIR /app은 앞으로의 모든 명령어가 /app 디렉토리에서 실행되도록 설정합니다. 만약 /app 디렉토리가 없다면 자동으로 생성됩니다.

이것은 마치 터미널에서 cd /app을 실행한 것과 비슷합니다. 왜 WORKDIR을 사용할까요?

컨테이너 안의 파일 구조를 깔끔하게 관리하기 위해서입니다. 루트 디렉토리에 파일을 막 복사하면 나중에 관리가 어려워집니다.

COPY - 파일 복사 COPY는 호스트의 파일을 컨테이너로 복사하는 명령어입니다. COPY build/libs/myapp-0.0.1-SNAPSHOT.jar app.jar는 Gradle 빌드로 생성된 JAR 파일을 컨테이너의 /app/app.jar로 복사합니다.

원본 파일 이름이 길고 버전이 포함되어 있으면 매번 Dockerfile을 수정해야 하니, app.jar처럼 간단한 이름으로 바꿔서 복사하는 것이 좋습니다. COPY는 ADD와 비슷하지만 차이가 있습니다.

ADD는 자동으로 압축을 풀거나 URL에서 다운로드하는 기능이 있지만, 대부분의 경우 명확한 COPY를 사용하는 것이 권장됩니다. EXPOSE - 포트 노출 EXPOSE는 컨테이너가 어떤 포트를 사용할지 문서화하는 명령어입니다.

EXPOSE 8080은 "이 컨테이너는 8080 포트를 사용해요"라고 선언하는 것입니다. 주의할 점은 EXPOSE가 실제로 포트를 열지는 않는다는 것입니다.

단지 다른 개발자에게 "이 애플리케이션은 8080 포트에서 실행돼요"라고 알려주는 메모 같은 것입니다. 실제로 포트를 연결하려면 docker run -p 8080:8080 같은 명령어를 사용해야 합니다.

ENTRYPOINT - 실행 명령 ENTRYPOINT는 컨테이너가 시작될 때 실행할 명령어를 지정합니다. ENTRYPOINT ["java", "-jar", "app.jar"]는 컨테이너가 시작되면 java -jar app.jar 명령어를 실행하라는 의미입니다.

대괄호를 사용한 형식을 exec form이라고 하는데, 이 형식을 사용하면 신호 처리가 올바르게 작동합니다. CMDENTRYPOINT의 차이도 알아두면 좋습니다.

CMD는 docker run 명령어로 덮어쓸 수 있지만, ENTRYPOINT는 항상 실행됩니다. 애플리케이션의 메인 실행 명령은 ENTRYPOINT에, 기본 옵션은 CMD에 넣는 것이 일반적입니다.

실제로 빌드하기 Dockerfile을 작성했다면 이제 이미지를 빌드할 차례입니다. 프로젝트 루트 디렉토리에서 docker build -t my-spring-app:1.0 . 명령어를 실행합니다.

마지막의 .은 현재 디렉토리를 빌드 컨텍스트로 사용하라는 의미입니다. Docker는 이 디렉토리의 모든 파일을 읽어서 이미지를 만듭니다.

빌드가 완료되면 docker images 명령어로 생성된 이미지를 확인할 수 있습니다. 이제 docker run -p 8080:8080 my-spring-app:1.0 명령어로 컨테이너를 실행하면 Spring Boot 애플리케이션이 작동합니다.

실무에서의 주의사항 실무에서 Dockerfile을 작성할 때는 몇 가지 주의할 점이 있습니다. 첫째, 빌드 컨텍스트를 최소화해야 합니다.

.dockerignore 파일을 만들어서 node_modules, .git, build 같은 불필요한 디렉토리를 제외하세요. 그렇지 않으면 Docker가 모든 파일을 읽느라 빌드 시간이 길어집니다.

둘째, 레이어 캐싱을 활용해야 합니다. Dockerfile의 각 명령어는 하나의 레이어를 만듭니다.

자주 바뀌지 않는 명령어는 위쪽에, 자주 바뀌는 명령어는 아래쪽에 배치하면 캐시를 효과적으로 사용할 수 있습니다. 김개발 씨의 성공 김개발 씨는 직접 Dockerfile을 작성하고 이미지를 빌드했습니다.

"와, 정말 되네요! 이제 이 이미지만 있으면 어디서든 실행할 수 있겠어요." 박시니어 씨가 미소를 지었습니다.

"맞아요. 이제 Dockerfile을 Git에 커밋해두면, 팀원들도 똑같은 환경을 만들 수 있어요." Dockerfile은 단순해 보이지만 강력한 도구입니다.

여러분도 직접 작성해보면서 익숙해지세요.

실전 팁

💡 - .dockerignore 파일을 만들어서 빌드에 불필요한 파일을 제외하면 빌드 속도가 크게 향상됩니다

  • ENTRYPOINT는 exec form ["java", "-jar"]을 사용하면 PID 1 문제를 피할 수 있습니다

3. 멀티스테이지 빌드

김개발 씨는 첫 Docker 이미지를 만들고 나서 이미지 크기를 확인했습니다. 무려 500MB가 넘었습니다.

박시니어 씨가 다가와 화면을 보더니 말했습니다. "아, 빌드 도구까지 포함되어 있네요.

멀티스테이지 빌드를 사용하면 이미지 크기를 절반 이하로 줄일 수 있어요."

멀티스테이지 빌드는 하나의 Dockerfile에서 여러 개의 FROM 구문을 사용하여 빌드 단계를 분리하는 기법입니다. 마치 공장에서 제품을 만들 때 조립 라인과 포장 라인을 분리하듯이, 빌드 환경과 실행 환경을 나눕니다.

첫 번째 스테이지에서는 JDK로 애플리케이션을 빌드하고, 두 번째 스테이지에서는 JRE로 빌드된 JAR만 실행합니다. 최종 이미지에는 실행에 필요한 것만 담기므로 크기가 크게 줄어듭니다.

다음 코드를 살펴봅시다.

# 빌드 스테이지
FROM gradle:8.5-jdk17 AS builder
WORKDIR /build
COPY . .
RUN gradle clean build -x test

# 실행 스테이지
FROM eclipse-temurin:17-jre
WORKDIR /app
# 빌드 스테이지에서 생성된 JAR만 복사
COPY --from=builder /build/build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

김개발 씨는 고민에 빠졌습니다. 이미지 크기가 크면 무엇이 문제일까요?

박시니어 씨가 설명을 시작했습니다. "이미지가 크면 Docker Hub에서 다운로드하는 시간이 길어지고, 저장 공간도 많이 차지해요.

특히 쿠버네티스 같은 환경에서는 노드마다 이미지를 다운로드하니까 크기가 중요하죠." 전통적인 방식의 문제 멀티스테이지 빌드가 없던 시절에는 어떻게 했을까요? 개발자들은 두 개의 Dockerfile을 만들었습니다.

하나는 빌드용, 하나는 실행용이었습니다. 먼저 빌드용 Dockerfile로 JAR 파일을 만들고, 그 JAR 파일을 로컬에 복사한 다음, 실행용 Dockerfile로 최종 이미지를 만들었습니다.

문제는 이 과정이 복잡하고 귀찮다는 것이었습니다. 빌드 스크립트를 별도로 작성해야 했고, 중간 파일들을 관리하는 것도 번거로웠습니다.

더 큰 문제는 팀원마다 빌드 과정을 다르게 이해하면 결과물이 달라질 수 있다는 것이었습니다. 멀티스테이지 빌드의 등장 Docker 17.05 버전부터 멀티스테이지 빌드가 지원되면서 모든 것이 간단해졌습니다.

멀티스테이지 빌드를 이해하는 가장 쉬운 비유는 케이크 만들기입니다. 케이크를 만들 때는 큰 주방에서 반죽하고 굽지만, 손님에게 내놓을 때는 예쁜 접시에 케이크 조각만 올립니다.

큰 믹서기나 오븐은 손님에게 보여줄 필요가 없습니다. Docker도 마찬가지입니다.

빌드할 때는 Gradle, JDK, 각종 빌드 도구가 필요하지만, 실행할 때는 JRE와 JAR 파일만 있으면 됩니다. 나머지는 버리는 것입니다.

빌드 스테이지 분석 첫 번째 FROM 구문을 자세히 살펴보겠습니다. FROM gradle:8.5-jdk17 AS builder는 Gradle 8.5와 JDK 17이 설치된 이미지를 베이스로 사용하며, 이 스테이지에 builder라는 이름을 붙입니다.

이름을 붙이면 나중에 이 스테이지를 참조할 수 있습니다. `COPY .

.`은 현재 디렉토리의 모든 파일을 컨테이너로 복사합니다. 소스 코드, build.gradle, settings.gradle 등 빌드에 필요한 모든 파일이 복사됩니다.

RUN gradle clean build -x test는 Gradle 빌드를 실행합니다. -x test 옵션은 테스트를 건너뛰라는 의미입니다.

테스트는 CI/CD 파이프라인에서 이미 실행했다면 Docker 빌드 시에는 생략할 수 있습니다. 실행 스테이지 분석 두 번째 FROM 구문이 핵심입니다.

FROM eclipse-temurin:17-jre는 완전히 새로운 베이스 이미지에서 시작합니다. 첫 번째 스테이지와는 아무 관련이 없는 깨끗한 상태입니다.

JDK가 아닌 JRE를 사용한다는 점이 중요합니다. COPY --from=builder /build/build/libs/*.jar app.jar가 마법이 일어나는 부분입니다.

--from=builder 옵션으로 첫 번째 스테이지에서 생성된 파일을 가져옵니다. 빌드 스테이지의 /build/build/libs/ 디렉토리에서 JAR 파일만 복사해옵니다.

이렇게 하면 최종 이미지에는 JRE와 JAR 파일만 포함됩니다. Gradle도, 소스 코드도, 빌드 도구도 모두 사라집니다.

이미지 크기 비교 실제로 얼마나 차이가 날까요? 단일 스테이지로 빌드하면 JDK, Gradle, 소스 코드가 모두 포함되어 600~800MB 정도가 됩니다.

하지만 멀티스테이지 빌드를 사용하면 JRE와 JAR 파일만 포함되어 200~300MB로 줄어듭니다. 절반 이하입니다.

이미지 크기가 줄어들면 네트워크 전송 시간이 단축되고, 디스크 공간도 절약되며, 컨테이너 시작 속도도 빨라집니다. 특히 마이크로서비스 아키텍처에서는 수십 개의 서비스 이미지를 관리하니 크기 최적화가 매우 중요합니다.

실무에서의 활용 실제 프로젝트에서는 스테이지를 더 세분화하기도 합니다. 예를 들어 의존성 다운로드 스테이지를 별도로 만들 수 있습니다.

Gradle의 의존성은 자주 바뀌지 않으니, 이 부분을 별도 레이어로 만들어 캐싱하면 빌드 속도가 빨라집니다. 또는 테스트 스테이지를 추가해서 빌드 중에 테스트를 실행하고, 테스트가 통과해야만 최종 이미지를 만들도록 할 수도 있습니다.

주의사항 멀티스테이지 빌드를 사용할 때 주의할 점이 있습니다. 첫째, 파일 경로를 정확히 지정해야 합니다.

COPY --from=builder에서 잘못된 경로를 지정하면 빌드가 실패합니다. 특히 Gradle과 Maven은 출력 디렉토리가 다르니 주의해야 합니다.

둘째, 와일드카드 *.jar를 사용할 때는 JAR 파일이 정확히 하나만 생성되는지 확인하세요. 여러 개가 있으면 예상치 못한 파일이 복사될 수 있습니다.

김개발 씨의 성과 김개발 씨는 멀티스테이지 빌드로 Dockerfile을 다시 작성했습니다. 이미지 크기를 확인하니 250MB로 줄어들었습니다.

"와, 정말 절반 이하네요!" 김개발 씨가 감탄했습니다. 박시니어 씨가 웃으며 말했습니다.

"이제 진짜 프로덕션에 쓸 만한 이미지가 됐어요. 배포 속도도 훨씬 빨라질 거예요." 멀티스테이지 빌드는 현대 Docker 활용의 필수 기법입니다.

여러분도 꼭 활용해보세요.

실전 팁

💡 - 의존성 다운로드를 별도 레이어로 만들면 캐싱 효과로 빌드 속도가 크게 향상됩니다

  • docker build --target builder 명령어로 특정 스테이지까지만 빌드할 수 있어 디버깅에 유용합니다

4. 이미지 최적화

멀티스테이지 빌드로 이미지 크기를 줄인 김개발 씨는 뿌듯했습니다. 하지만 박시니어 씨는 "아직 더 줄일 수 있어요"라고 말했습니다.

베이스 이미지 선택, 레이어 최적화, 불필요한 파일 제거 등 여러 기법을 추가로 적용하면 이미지를 더욱 가볍게 만들 수 있다고 했습니다.

이미지 최적화는 Docker 이미지의 크기와 보안을 개선하는 다양한 기법을 말합니다. 베이스 이미지를 Alpine Linux처럼 경량화된 것으로 선택하거나, 명령어를 병합하여 레이어 수를 줄이거나, 빌드 캐시와 임시 파일을 제거하는 방법이 있습니다.

작은 이미지는 네트워크 전송이 빠르고 공격 표면이 줄어들어 보안에도 유리합니다. 프로덕션 환경에서는 이미지 최적화가 성능과 비용에 직접적인 영향을 미칩니다.

다음 코드를 살펴봅시다.

# 최적화된 멀티스테이지 Dockerfile
FROM gradle:8.5-jdk17-alpine AS builder
WORKDIR /build
COPY build.gradle settings.gradle ./
COPY src ./src
# 테스트 제외, 캐시 제거
RUN gradle clean build -x test --no-daemon && \
    rm -rf /root/.gradle

# Distroless 이미지 사용
FROM gcr.io/distroless/java17-debian12
WORKDIR /app
COPY --from=builder /build/build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

김개발 씨는 궁금했습니다. "이미지가 작으면 그렇게 중요한가요?" 박시니어 씨가 진지하게 대답했습니다.

"네, 매우 중요해요. 이미지 크기는 배포 속도, 저장 비용, 보안, 모든 것에 영향을 미치거든요." 이미지 크기가 중요한 이유 이미지 크기 최적화를 이해하려면 먼저 왜 크기가 중요한지 알아야 합니다.

첫째, 배포 속도입니다. 쿠버네티스 환경에서 오토스케일링이 발생하면 새로운 Pod이 생성되면서 이미지를 다운로드합니다.

이미지가 500MB라면 다운로드에 수십 초가 걸리지만, 100MB라면 몇 초 안에 끝납니다. 트래픽이 급증하는 상황에서 이 차이는 서비스 안정성에 직결됩니다.

둘째, 저장 비용입니다. Docker Registry에 이미지를 저장하면 비용이 발생합니다.

버전마다 이미지를 보관하면 크기가 누적됩니다. 100개 버전을 유지한다면 이미지 하나당 100MB만 줄여도 10GB를 절약할 수 있습니다.

셋째, 보안입니다. 이미지에 불필요한 패키지가 많으면 보안 취약점이 생길 가능성도 커집니다.

공격자가 침투했을 때 사용할 수 있는 도구가 많아지는 것입니다. Alpine Linux 활용 가장 쉬운 최적화 방법은 Alpine Linux 베이스 이미지를 사용하는 것입니다.

Alpine Linux는 보안과 경량화에 초점을 맞춘 배포판입니다. 일반 Debian 기반 이미지가 100~200MB인 반면, Alpine은 5MB 정도밖에 되지 않습니다.

마치 짐을 쌀 때 큰 여행 가방 대신 백팩을 쓰는 것과 같습니다. FROM gradle:8.5-jdk17-alpine처럼 Alpine 버전을 지정하면 됩니다.

단, Alpine은 glibc 대신 musl libc를 사용하므로 일부 네이티브 라이브러리와 호환 문제가 있을 수 있습니다. 순수 Java 애플리케이션이라면 문제없지만, JNI를 사용하는 라이브러리가 있다면 테스트가 필요합니다.

Distroless 이미지 더 강력한 최적화 방법은 Distroless 이미지를 사용하는 것입니다. Distroless는 Google이 만든 이미지로, 애플리케이션 실행에 꼭 필요한 것만 담겨 있습니다.

패키지 매니저도, 쉘도, 심지어 기본 유틸리티도 없습니다. 마치 비행기 화물칸처럼 짐만 실을 수 있는 최소한의 공간만 있는 것입니다.

FROM gcr.io/distroless/java17-debian12를 사용하면 JRE와 필수 시스템 라이브러리만 포함됩니다. 이미지 크기는 극도로 작아지고, 공격자가 침투해도 사용할 도구가 거의 없어 보안이 크게 향상됩니다.

단점은 디버깅이 어렵다는 것입니다. 쉘이 없어서 컨테이너에 접속해서 명령어를 실행할 수 없습니다.

하지만 프로덕션 환경에서는 디버깅보다 보안과 크기가 더 중요하므로 권장됩니다. 레이어 최적화 Dockerfile의 각 명령어는 레이어를 만듭니다.

레이어는 변경 사항을 추적하는 단위입니다. 마치 포토샵의 레이어처럼, 각 명령어가 새로운 레이어를 추가합니다.

문제는 레이어가 많으면 이미지 크기가 커진다는 것입니다. 예를 들어 다음 코드를 보겠습니다: RUN apt-get update RUN apt-get install -y curl RUN apt-get clean 이렇게 작성하면 3개의 레이어가 생깁니다.

apt-get update로 패키지 목록을 다운로드하고, apt-get install로 패키지를 설치하고, apt-get clean으로 캐시를 지웁니다. 하지만 첫 번째 레이어에 패키지 목록이 이미 저장되어 있으므로, 세 번째 레이어에서 캐시를 지워도 이미지 크기는 줄지 않습니다.

올바른 방법은 명령어를 병합하는 것입니다: RUN apt-get update && \ apt-get install -y curl && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* 이렇게 하면 하나의 레이어만 생기고, 임시 파일이 같은 레이어 내에서 삭제되므로 이미지 크기가 줄어듭니다. Gradle 캐시 제거 빌드 스테이지에서 Gradle을 실행하면 캐시 파일/root/.gradle 디렉토리에 쌓입니다.

이 캐시는 빌드 속도를 높이는 데 유용하지만, 최종 이미지에는 필요 없습니다. RUN gradle clean build -x test --no-daemon && rm -rf /root/.gradle처럼 빌드 후 바로 캐시를 삭제하면 됩니다.

--no-daemon 옵션도 중요합니다. Gradle 데몬은 빌드 속도를 높이지만 메모리를 차지합니다.

Docker 빌드에서는 한 번만 실행하므로 데몬이 불필요합니다. 의존성 캐싱 최적화 Dockerfile의 순서를 잘 배치하면 빌드 캐시를 효과적으로 활용할 수 있습니다.

소스 코드는 자주 바뀌지만 의존성은 거의 바뀌지 않습니다. 따라서 COPY build.gradle settings.gradle ./를 먼저 실행하고, 그다음 의존성을 다운로드하고, 마지막에 소스 코드를 복사하면 됩니다.

이렇게 하면 소스 코드가 바뀌어도 의존성 다운로드 레이어는 캐시에서 재사용되므로 빌드가 훨씬 빠릅니다. 실무 적용 사례 실제 대규모 서비스에서는 이미지 최적화가 어떤 효과를 낼까요?

마이크로서비스 아키텍처로 30개의 서비스를 운영한다고 가정해봅시다. 각 서비스 이미지를 100MB씩 줄이면 총 3GB가 절약됩니다.

배포할 때마다 노드 10대에 이미지를 다운로드한다면 30GB의 네트워크 전송이 줄어듭니다. 이것은 배포 시간 단축과 비용 절감으로 이어집니다.

보안 스캐닝 이미지를 최적화한 후에는 보안 스캔을 실행하는 것이 좋습니다. docker scan my-spring-app:1.0 명령어로 알려진 보안 취약점을 확인할 수 있습니다.

또는 Trivy, Snyk 같은 도구를 사용하면 더 상세한 분석이 가능합니다. Distroless 이미지는 패키지가 거의 없어 스캔 결과도 깔끔합니다.

김개발 씨의 최종 결과 김개발 씨는 Alpine 빌드 이미지와 Distroless 런타임 이미지를 적용했습니다. 이미지 크기가 150MB로 줄어들었습니다.

"처음에는 500MB였는데 이제 150MB네요. 3분의 1로 줄었어요!" 김개발 씨가 놀라워했습니다.

박시니어 씨가 고개를 끄덕였습니다. "이제 프로덕션에 배포해도 자신 있겠죠?

빠르고 안전한 이미지예요." 이미지 최적화는 DevOps 엔지니어의 기본 역량입니다. 여러분도 프로젝트에 적용해보세요.

실전 팁

💡 - dive 도구를 사용하면 레이어별 크기를 분석하여 어느 부분이 큰지 정확히 파악할 수 있습니다

  • .dockerignore에 .git, node_modules, build 등을 추가하면 빌드 컨텍스트가 작아져 빌드 속도가 빨라집니다

5. Spring Boot Docker 지원

김개발 씨는 Dockerfile을 직접 작성하며 많은 것을 배웠습니다. 그런데 박시니어 씨가 재미있는 사실을 알려줬습니다.

"사실 Spring Boot 2.3부터는 Dockerfile 없이도 Docker 이미지를 만들 수 있어요. Gradle 플러그인 하나로 끝나죠."

Spring Boot Docker 지원은 Spring Boot 2.3부터 제공되는 기능으로, Gradle이나 Maven 플러그인만으로 Docker 이미지를 생성할 수 있습니다. gradle bootBuildImage 명령어 하나로 Layered JAR, 최적화된 레이어, 보안 강화 등이 자동으로 적용된 이미지가 만들어집니다.

Dockerfile을 직접 작성하지 않아도 되며, Spring Boot 팀이 권장하는 베스트 프랙티스가 기본으로 적용됩니다. Cloud Native Buildpacks 기술을 활용하여 표준화된 이미지를 생성합니다.

다음 코드를 살펴봅시다.

// build.gradle에 설정 추가
plugins {
    id 'org.springframework.boot' version '3.2.0'
}

tasks.named('bootBuildImage') {
    imageName = "mycompany/${project.name}:${version}"
    environment = [
        "BP_JVM_VERSION": "17"
    ]
    // 커스텀 설정
    builder = 'paketobuildpacks/builder:base'
}

# 이미지 빌드 (Dockerfile 불필요)
./gradlew bootBuildImage

김개발 씨는 눈이 휘둥그레졌습니다. "Dockerfile 없이요?

그럼 지금까지 배운 건 뭐죠?" 박시니어 씨가 웃으며 설명했습니다. "Dockerfile을 이해하는 건 중요해요.

하지만 Spring Boot는 이미 최적화된 이미지 빌드 기능을 제공하거든요. 상황에 따라 선택하면 돼요." Spring Boot의 Docker 지원 배경 Spring Boot 팀은 개발자 경험을 매우 중요하게 생각합니다.

Dockerfile을 작성하는 것은 어렵지 않지만, 최적화된 이미지를 만들려면 많은 지식이 필요합니다. 레이어 최적화, 보안 설정, JVM 튜닝 등 고려할 것이 많습니다.

Spring Boot 팀은 이런 복잡성을 제거하고 싶었습니다. 그래서 Spring Boot 2.3부터 빌드 플러그인에 Docker 이미지 생성 기능을 추가했습니다.

단 한 줄의 명령어로 프로덕션 레벨의 이미지를 만들 수 있게 된 것입니다. bootBuildImage 태스크 Gradle의 bootBuildImage 태스크가 핵심입니다.

./gradlew bootBuildImage 명령어를 실행하면 Dockerfile 없이도 Docker 이미지가 생성됩니다. 내부적으로는 Cloud Native Buildpacks이라는 기술을 사용합니다.

이것은 CNCF(Cloud Native Computing Foundation)가 관리하는 표준 기술입니다. 빌드가 완료되면 docker images 명령어로 생성된 이미지를 확인할 수 있습니다.

이미지 이름은 기본적으로 프로젝트명:버전 형식이지만, build.gradle에서 커스터마이징할 수 있습니다. Layered JAR의 자동 적용 Spring Boot의 Docker 이미지는 Layered JAR 구조를 사용합니다.

일반적인 JAR 파일은 모든 것이 하나로 묶여 있습니다. 코드를 한 줄만 수정해도 전체 JAR를 다시 만들어야 하고, Docker 이미지도 처음부터 다시 빌드됩니다.

Layered JAR는 JAR 파일을 여러 레이어로 분리합니다. 의존성 라이브러리, Spring Boot 로더, 스냅샷 의존성, 애플리케이션 코드 이렇게 네 개의 레이어로 나뉩니다.

코드를 수정하면 애플리케이션 코드 레이어만 새로 빌드되고, 나머지 레이어는 캐시에서 재사용됩니다. 이것은 빌드 속도배포 속도를 크게 향상시킵니다.

JVM 최적화 bootBuildImage는 JVM 설정도 자동으로 최적화합니다. 컨테이너 환경에서는 메모리 제한이 중요합니다.

과거 Java는 컨테이너 환경을 잘 인식하지 못해서 호스트의 전체 메모리를 기준으로 힙 크기를 설정했습니다. 이것은 OOMKilled(Out Of Memory Killed) 에러의 주요 원인이었습니다.

최신 JDK는 컨테이너를 인식하고 메모리를 적절히 설정합니다. bootBuildImage로 생성된 이미지는 이런 JVM 옵션이 자동으로 적용되어 안정적으로 작동합니다.

Builder 커스터마이징 기본 빌더가 마음에 들지 않으면 builder를 변경할 수 있습니다. builder = 'paketobuildpacks/builder:base'는 Paketo Buildpacks의 base 빌더를 사용하라는 의미입니다.

Paketo는 Cloud Foundry 팀이 만든 엔터프라이즈급 Buildpacks입니다. 또는 paketobuildpacks/builder:tiny를 사용하면 더 작은 이미지를 만들 수 있습니다.

tiny 빌더는 Distroless 기반으로 크기가 매우 작습니다. 환경 변수 설정 build.gradle의 environment 블록에서 빌드 시 환경 변수를 설정할 수 있습니다.

"BP_JVM_VERSION": "17"은 Java 17을 사용하라는 의미입니다. Buildpacks는 자동으로 적절한 JDK를 다운로드하여 이미지에 포함시킵니다.

다른 유용한 환경 변수로는 BP_JVM_JLINK_ENABLED가 있습니다. 이것을 true로 설정하면 jlink를 사용하여 필요한 JDK 모듈만 포함하는 커스텀 JRE를 만들어 이미지 크기를 더욱 줄일 수 있습니다.

Docker 데몬 불필요 옵션 흥미롭게도 bootBuildImage는 Docker 데몬 없이도 작동할 수 있습니다. --publishImage 옵션을 사용하면 이미지를 빌드하고 바로 Docker Hub에 푸시합니다.

로컬에 Docker를 설치하지 않은 CI/CD 환경에서 유용합니다. 실무 활용 사례 실제 프로젝트에서는 어떻게 활용할까요?

대부분의 Spring Boot 프로젝트는 bootBuildImage를 기본으로 사용합니다. Dockerfile을 작성하고 유지보수하는 부담이 사라지고, Spring Boot 팀이 업데이트하는 최적화를 자동으로 받을 수 있습니다.

다만 특수한 요구사항이 있다면 Dockerfile을 직접 작성하는 것이 나을 수 있습니다. 예를 들어 특정 리눅스 패키지를 추가로 설치해야 한다거나, 복잡한 멀티스테이지 빌드가 필요하다면 Dockerfile이 더 유연합니다.

bootBuildImage vs Dockerfile 언제 어떤 방법을 선택해야 할까요? bootBuildImage를 선택하는 경우: 표준적인 Spring Boot 애플리케이션, 빠른 개발과 배포를 원할 때, Docker 전문 지식이 부족할 때 Dockerfile을 선택하는 경우: 특수한 베이스 이미지가 필요할 때, 추가 패키지 설치가 필요할 때, 빌드 과정을 완전히 제어하고 싶을 때 김개발 씨의 선택 김개발 씨는 두 가지 방법을 모두 실험해봤습니다.

"프로토타입에는 bootBuildImage가 편하네요. 하지만 세밀한 제어가 필요할 때는 Dockerfile이 낫겠어요." 박시니어 씨가 동의했습니다.

"맞아요. 도구는 상황에 맞게 선택하는 거예요.

중요한 건 둘 다 이해하는 거죠." Spring Boot의 Docker 지원은 개발 생산성을 크게 높여줍니다. 여러분도 프로젝트에 적용해보세요.

실전 팁

💡 - bootBuildImage는 로컬 Docker 이미지 캐시를 활용하므로 두 번째 빌드부터는 매우 빠릅니다

  • imageName에 버전을 포함하면 이미지 관리가 편하고, latest 태그와 별도로 버전별 이미지를 유지할 수 있습니다

6. Buildpacks 활용

김개발 씨는 bootBuildImage가 내부적으로 Buildpacks를 사용한다는 것을 알게 됐습니다. "Buildpacks가 뭔가요?" 박시니어 씨는 웃으며 설명을 시작했습니다.

"Buildpacks는 소스 코드를 컨테이너 이미지로 변환하는 표준 도구예요. Heroku가 처음 만들었는데, 지금은 CNCF 프로젝트가 됐죠."

Cloud Native Buildpacks는 소스 코드에서 프로덕션 레벨의 컨테이너 이미지를 자동으로 생성하는 표준 기술입니다. Dockerfile 없이도 언어와 프레임워크를 자동 감지하여 최적화된 이미지를 만들어줍니다.

Heroku, Google Cloud, Pivotal 등이 함께 개발한 CNCF 프로젝트로, 보안 패치와 업데이트가 자동으로 적용되는 이미지를 생성합니다. 개발자는 코드만 작성하고, 인프라 세부사항은 Buildpacks가 처리합니다.

다음 코드를 살펴봅시다.

# pack CLI로 이미지 빌드 (Dockerfile 불필요)
pack build myapp --builder paketobuildpacks/builder:base

# 특정 buildpack 지정
pack build myapp \
  --builder paketobuildpacks/builder:base \
  --buildpack paketo-buildpacks/java \
  --env BP_JVM_VERSION=17

# 빌드 과정 확인
pack inspect-image myapp

# Buildpacks 리베이스 (보안 패치 적용)
pack rebase myapp --builder paketobuildpacks/builder:base

김개발 씨는 Buildpacks라는 단어가 낯설었습니다. "이게 Dockerfile을 대체하는 건가요?" 박시니어 씨가 고개를 저었습니다.

"대체라기보다는 다른 접근 방식이에요. Dockerfile은 '어떻게' 빌드할지를 명령하는 방식이고, Buildpacks는 '무엇을' 빌드할지만 알려주면 나머지는 자동으로 처리하는 방식이죠." Buildpacks의 탄생 배경 Buildpacks는 Heroku에서 시작되었습니다.

2000년대 후반, Heroku는 개발자가 코드만 푸시하면 자동으로 배포되는 플랫폼을 만들고 싶었습니다. 개발자는 Dockerfile도 작성할 필요 없고, 서버 설정도 할 필요 없고, 그냥 git push heroku main만 하면 모든 것이 작동해야 했습니다.

이를 위해 Heroku는 소스 코드를 분석하여 언어를 자동 감지하고, 필요한 런타임을 설치하고, 의존성을 다운로드하고, 실행 가능한 형태로 빌드하는 시스템을 만들었습니다. 이것이 바로 Buildpacks의 시작입니다.

CNCF 프로젝트로의 발전 Buildpacks가 인기를 얻자 다른 기업들도 관심을 가졌습니다. Google, Pivotal, Heroku가 힘을 합쳐 Cloud Native Buildpacks라는 표준 프로젝트를 만들었습니다.

이것은 특정 플랫폼에 종속되지 않고, 어디서나 사용할 수 있는 오픈 표준입니다. 현재는 CNCF(Cloud Native Computing Foundation)의 인큐베이팅 프로젝트입니다.

Buildpacks의 작동 원리 Buildpacks는 어떻게 작동할까요? 마치 자동 조립 로봇과 같습니다.

부품(소스 코드)을 주면 로봇이 자동으로 분석하여 필요한 도구를 선택하고, 순서대로 조립하여 완제품(컨테이너 이미지)을 만들어냅니다. 구체적으로는 detect 단계build 단계로 나뉩니다.

detect 단계에서는 프로젝트에 pom.xml이 있는지, build.gradle이 있는지 확인하여 어떤 언어와 프레임워크를 사용하는지 파악합니다. build 단계에서는 적절한 JDK를 설치하고, 의존성을 다운로드하고, 애플리케이션을 빌드합니다.

pack CLI 사용하기 Buildpacks를 직접 사용하려면 pack CLI를 설치해야 합니다. pack build myapp --builder paketobuildpacks/builder:base 명령어 하나로 이미지가 생성됩니다.

Dockerfile이 전혀 필요 없습니다. pack CLI는 프로젝트를 분석하고, 적절한 buildpack들을 자동으로 선택하고, 레이어를 구성하고, 최적화된 이미지를 만들어줍니다.

--builder 옵션은 어떤 builder를 사용할지 지정합니다. builder는 buildpack들의 모음입니다.

Paketo Buildpacks의 base builder는 Java, Node.js, Go, Python 등 다양한 언어를 지원합니다. 환경 변수로 커스터마이징 Buildpacks는 환경 변수로 세밀하게 제어할 수 있습니다.

--env BP_JVM_VERSION=17은 Java 17을 사용하라는 의미입니다. BP_MAVEN_BUILD_ARGUMENTS로 Maven 빌드 옵션을 지정할 수도 있고, BP_GRADLE_BUILD_ARGUMENTS로 Gradle 옵션을 지정할 수도 있습니다.

이런 환경 변수들은 Buildpack마다 다릅니다. Paketo Java Buildpack의 경우 수십 가지 환경 변수를 제공하여 메모리 설정, GC 옵션, JVM 플래그 등을 세밀하게 조정할 수 있습니다.

Rebase의 강력함 Buildpacks의 가장 강력한 기능 중 하나는 rebase입니다. 이것은 Dockerfile로는 불가능한 기능입니다.

보안 취약점이 발견되어 베이스 이미지를 업데이트해야 한다고 가정해봅시다. Dockerfile 방식이라면 전체 이미지를 다시 빌드해야 합니다.

하지만 Buildpacks는 베이스 레이어만 교체하는 rebase가 가능합니다. pack rebase myapp --builder paketobuildpacks/builder:base 명령어를 실행하면 애플리케이션 코드는 그대로 두고 베이스 레이어만 최신 버전으로 교체합니다.

빌드 시간이 몇 초밖에 걸리지 않고, 애플리케이션 재빌드도 필요 없습니다. 이것은 보안 패치를 매우 빠르게 적용할 수 있게 해줍니다.

예를 들어 OpenSSL 취약점이 발견되면, 모든 서비스를 재빌드하는 대신 rebase만 실행하면 됩니다. Bill of Materials (SBOM) Buildpacks는 SBOM(Software Bill of Materials)를 자동으로 생성합니다.

SBOM은 이미지에 포함된 모든 소프트웨어 구성 요소의 목록입니다. 어떤 라이브러리가 사용되었는지, 버전은 무엇인지, 라이선스는 무엇인지 모두 기록됩니다.

pack inspect-image myapp 명령어로 SBOM을 확인할 수 있습니다. 이것은 보안 감사와 규정 준수에 매우 유용합니다.

Buildpacks vs Dockerfile 언제 Buildpacks를 사용하고 언제 Dockerfile을 사용해야 할까요? Buildpacks를 선택하는 경우: 표준적인 애플리케이션, 자동화된 보안 업데이트가 중요할 때, Dockerfile 작성 부담을 줄이고 싶을 때, 여러 언어/프레임워크를 표준화된 방식으로 관리하고 싶을 때 Dockerfile을 선택하는 경우: 특수한 빌드 과정이 필요할 때, 레거시 시스템과 통합해야 할 때, 빌드 과정을 완전히 제어하고 싶을 때, Buildpacks가 지원하지 않는 언어나 프레임워크를 사용할 때 실무에서의 활용 실제 현업에서는 Buildpacks를 어떻게 활용할까요?

대규모 마이크로서비스 환경에서 Buildpacks의 진가가 발휘됩니다. 수십 개의 서비스가 Java, Node.js, Go, Python 등 다양한 언어로 작성되어 있다고 가정해봅시다.

각 서비스마다 Dockerfile을 작성하고 유지보수하는 것은 부담입니다. Buildpacks를 사용하면 모든 서비스가 동일한 빌드 표준을 따르게 됩니다.

보안 패치가 필요하면 builder를 업데이트하고 모든 서비스를 rebase하면 됩니다. 개별 Dockerfile을 수정할 필요가 없습니다.

Platform Engineering의 핵심 도구 Buildpacks는 Platform Engineering 분야에서 핵심 도구로 자리잡고 있습니다. Platform Engineering은 개발자들이 인프라를 신경 쓰지 않고 코드 작성에만 집중할 수 있도록 자동화된 플랫폼을 만드는 것입니다.

Buildpacks는 이런 플랫폼의 기반 기술로 많이 사용됩니다. 김개발 씨의 이해 김개발 씨는 Buildpacks의 철학을 이해하게 됐습니다.

"그러니까 Dockerfile은 요리 레시피를 직접 작성하는 거고, Buildpacks는 셰프에게 재료만 주고 요리를 맡기는 거네요." 박시니어 씨가 엄지를 들었습니다. "정확해요!

둘 다 장단점이 있으니, 프로젝트 특성에 맞게 선택하면 돼요." Buildpacks는 컨테이너 시대의 강력한 도구입니다. 여러분도 프로젝트에 적용해보세요.

실전 팁

💡 - project.toml 파일을 만들면 buildpack 설정을 프로젝트에 저장하여 팀원들과 공유할 수 있습니다

  • pack builder inspect 명령어로 builder에 포함된 buildpack 목록을 확인할 수 있어 어떤 언어가 지원되는지 알 수 있습니다

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#Docker#Dockerfile#Buildpacks#Container#SpringBoot#Spring

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.

함께 보면 좋은 카드 뉴스

쿠버네티스 아키텍처 완벽 가이드

초급 개발자를 위한 쿠버네티스 아키텍처 설명서입니다. 클러스터 구조부터 Control Plane, Worker Node, 파드, 네트워킹까지 실무 관점에서 쉽게 풀어냅니다. 점프 투 자바 스타일로 술술 읽히는 이북 형식으로 작성되었습니다.

관찰 가능한 마이크로서비스 완벽 가이드

마이크로서비스 환경에서 시스템의 상태를 실시간으로 관찰하고 모니터링하는 방법을 배웁니다. Resilience4j, Zipkin, Prometheus, Grafana, EFK 스택을 활용하여 안정적이고 관찰 가능한 시스템을 구축하는 실전 가이드입니다.

EFK 스택 로깅 완벽 가이드

마이크로서비스 환경에서 로그를 효과적으로 수집하고 분석하는 EFK 스택(Elasticsearch, Fluentd, Kibana)의 핵심 개념과 실전 활용법을 초급 개발자도 쉽게 이해할 수 있도록 정리한 가이드입니다.

Prometheus 메트릭 수집 완벽 가이드

Spring Boot 애플리케이션의 메트릭을 Prometheus로 수집하고 모니터링하는 방법을 배웁니다. Actuator 설정부터 PromQL 쿼리까지 실무에 필요한 모든 내용을 다룹니다.

스프링 관찰 가능성 완벽 가이드

Spring Boot 3.x의 Observation API를 활용한 애플리케이션 모니터링과 추적 방법을 초급 개발자 눈높이에서 쉽게 설명합니다. 실무에서 바로 적용할 수 있는 메트릭 수집과 분산 추적 기법을 다룹니다.