왜 Jib을 써야하는가?
우리가 애플리케이션을 컨테이너화 한다고 했을 때 가장 먼저 떠오르는 단어는 아마 Dockerfile일 것이다
그에 대한 방법은, 컨테이너 이미지를 만들기 위한 과정을 Dockerfile에 정의해놓고, docker build명령을 통해서 컨테이너 이미지를 만드는 게 가장 많이 알려진 방법으로 통할 것이다
아래 예시처럼 말이다.
# 현재 나는 corretto17을 사용하고 있기 때문에 아래와 같이 베이스 이미지를 설정하였음
FROM openjdk:17-jdk
# JAR_FILE 변수 정의 -> 기본적으로 jar file이 2개이기 때문에 이름을 특정해야함
# 나는 그냥 bootJar해서 jar file 1개만 생성한 후 아래와 같이 진행했음
ARG JAR_FILE=./build/libs/docker-0.0.1-SNAPSHOT.jar
# JAR 파일 메인 디렉토리에 복사
COPY ${JAR_FILE} app.jar
# 시스템 진입점 정의
ENTRYPOINT ["java","-jar","/app.jar"]
이걸 자바 애플리케이션에 반영한다면 아마도 애플리케이션을 빌드해서 jar 혹은 war 파일을 만들고, Dockerfile을 작성해서 원하는 베이스 이미지에 빌드된 결과물을 저장하는 형태로 컨테이너 이미지가 만들어지게 된다.
하지만!
이 과정은 자동화가 어렵다. 왜냐하면
- maven이나 gradle 을 이용한 빌드의 과정을 포함해야함
- 빌드가 성공했다면 빌드의 결과 파일을 Dockerfil 을 작성해서 원하는 베이스 이미지에 빌드된 결과물을 저장하는 형태로 컨테이너 이미지를 만들어야 함
⇒ 즉, 빌드와 Dockerfile작성의 과정을 하나의 파이프라인으로 만들 순 있겠지만, 엄밀히 따지면 두 가지의 작업이 돌고 있는 것임 Jib은 바로 이 부분을 개선하기 위해 만들어졌음
Jib의 빌드 흐름을 보면 아래와 같은 특성이 있음
- 프로젝트를 빌드함과 동시에 컨테이너 이미지를 만들어서 원하는 레포에 push까지 해줌
- 이 과정에서 jar와 BootJar 파일은 생성하지 않음 **(혼동하면 안됨!)
- Gradle 또는 Maven 빌드 도구를 사용하여 애플리케이션을 패키징하고, 그 결과물을 Docker이미지로 빌드한 뒤 원하는 레포에 Push해줌**
- 이 모든 과정을 gradlew jib 명령어를 통해서 할 수 있음
jib이란?
- Gradle과 Maven을 사용하여 Docker 이미지를 생성하기 위한 오픈 소스 플러그인
- Docker 데몬없이 이미지를 빌드하고 Docker Hub과 같은 레지스트리로 저장하는 플러그인
- Dockerfile을 사용하지 않고, 빌드 도구에서 이미지를 빌드하도록 설계됨. 이는 빌드 시점에 이미지를 빌드하기 때문에 Docker 환경이 없는 CI/CD 파이프라인에서도 사용이 가능하며, Dockerfile을 관리할 필요가 없어짐
특징
- Docker 및 Kubernetes에서 실행 가능한 이미지를 생성
- 빌드 도구에서 이미지 빌드를 지원 (Gradle 및 Maven).
- 소스 코드와 이미지 빌드를 분리할 수 있어서 빌드 속도가 빠름
- 빌드 환경에서 설정이 가능하며, 빌드 시간에 정적 이미지 레이어 캐싱을 지원
- 다중 모듈 프로젝트에서도 사용할 수 있음
- (만약 특정 모듈만 jib을 실행하고 싶을 경우 아래와 같이 명령어 실행) ./gradlew :{특정 모듈}:jib
특징 요약
- Jib를 사용하면 Dockerfile을 작성하지 않아도 되기 때문에, 이미지 생성 과정이 간편해짐 또한, Jib는 이미지를 최적화하고 Docker Daemon에 로컬 이미지를 빌드하지 않기 때문에 빌드 속도가 빠름
- 로컬에 Docker를 설치하지 않아도 되므로 개발 환경 구축이 간편해짐
사용방법
-Gradle에서 사용한다면
Gradle에서 Jib를 사용하기 위해서는 build.gradle 파일에 다음과 같이 플러그인을 추가해야 함
plugins {
# 아래 부분에 jib관련 플러그인 추가
id 'com.google.cloud.tools.jib' version '3.1.4'
}
jib {
from {
# Docker 이미지의 기본 이미지 정의
image = 'openjdk:11-jre'
}
to {
# 빌드한 이미지를 저장할 레지스트리 및 태그를 정의
image = 'myregistry/myimage'
tags = ['latest', 'v1']
# 이미지 저장소에 로그인하는 인증정보 설정
auth {
username = 'myregistry-username'
password = 'myregistry-password'
}
}
}
위 예제에서는 Gradle에 Jib 플러그인을 추가하고,
from 블록에서 Docker 이미지의 기본 이미지를 정의하고, to 블록에서 빌드한 이미지를 저장할 레지스트리 및 태그를 정의합니다. auth 블록을 사용하여 이미지 저장소에 로그인하는 인증 정보를 설정하였음
궁금점!
Dockerfile이건, jib이건, 왜 애플리케이션 개발환경과 일치하도록 베이스 이미지를 설정해야할까?
- 베이스 이미지의 특징 및 역할
- 새로운 Docker 이미지를 생성할 때, 기반이 되는 이미지 ⇒ 새로운 이미지를 빌드하기 위해, 기존 이미지를 기반으로 작업을 수행함 ⇒ 이때 베이스 이미지는 기존 이미지에 추가할 레이어로 사용됨 ⇒ 새로운 이미지를 생성할 때, 베이스 이미지에는 운영 체제와 런타임 환경, 라이브러리, 패키지 등이 이미 설치되어 있으므로 이를 활용하여 필요한 애플리케이션 및 서비스를 설치하고 구성할 수 있음 **따라서, 베이스 이미지는 Docker 이미지 생성 과정의 첫 번째 단계이며, 새로운 이미지를 만드는 데 필수적임
FROM openjdk:17-jdk-alpine
- 만약 애플리케이션 개발환경과 일치하도록 베이스 이미지를 설정하지 않는다면?
- 호환성 문제
애플리케이션이 실행되는 런타임 환경과 베이스 이미지에 설치된 라이브러리와 패키지의 버전이 일치하지 않을 경우 호환성 문제가 발생할 수 있음. 이는 애플리케이션의 동작에 영향을 줌 - 보안 문제
베이스 이미지에는 이미 설치된 라이브러리와 패키지가 포함되어 있음 따라서, 애플리케이션이 사용하는 라이브러리와 패키지의 버전이 다르면 보안 취약점이 발생할 수 있음 - 성능 문제
애플리케이션이 실행되는 런타임 환경과 베이스 이미지에 설치된 라이브러리와 패키지의 버전이 일치하지 않을 경우 성능 문제가 발생할 수 있음. 이는 애플리케이션의 처리 속도를 늦출 수 있음
- 호환성 문제
jib 플러그인 Gradle 구문설명
from 구문설명 from 구문에서 설정할 수 있는 가장 중요한 항목은 image 임
jib 라이브러리가 애플리케이션을 컨테이너 이미지로 만들 때 사용하는 베이스 이미지를 지정하는 항목인데,
아무것도 설정하지 않으면 **adoptopenjdk:11-jre**이 기본값이 .
to 구문설명 to 구문에서 설정할 수 있는 가장 중요한 항목은 **image**와 tags 임
여기에서의 **image**는 생성된 컨테이너 이미지가 저장될 레포지터리를 의미
그리고 **tags**는 이 이미지에 설정될 태그를 의미함
container 구문설명
container 구문은 컨테이너 이미지가 컨테니어화 되어서 실행될 때 필요한 자바 애플리케이션의 설정들을 지정할 수 있음.**jvmFlags**가 가장 중요한 항목임
위 내용들을 바탕으로 아래와 같이 jib 설정을 만들어본 예시는 아래와 같음
jib {
from {
image = "adoptopenjdk/openjdk16:x86_64-alpine-jdk-16.0.1_9"
}
to {
image = "sepiro2000/hello-jib"
tags = ["latest"]
}
container {
jvmFlags = ["-Xms128m", "-Xmx128m"]
}
}
- adoptopenjdk/openjdk16:x86_64-alpine-jdk-16.0.1_9 이미지를 베이스 이미지로 지정
- 컨테이너 이미지를 만든 후 도커 허브의 sepiro2000/hello-jib 레포에 latest 라는 태그를 넣어서 push
- 컨테이너화가 되어 동작할 때는 JVM 옵션으로 "-Xms128m", "-Xmx128m" 이 두 가지 옵션을 넣어서 실행
jib로 컨테이너 이미지 생성하기
위 내용대로라면 도커 허브에 이미지를 푸시할 것이기 때문에 docker login 명령으로 미리 로그인 진행
❯ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to <https://hub.docker.com> to create one.
Username: sepiro2000
Password:
Login Succeeded
로그인이 성공적으로 되었다면 이제 ./gradlew jib 명령을 실행 중간중간 이미지가 생성되는 과정이 표시되고 정상적으로 완료되면 아래와 같이 BUILD SUCCESSFUL 메세지가 노출됨
❯ ./gradlew jib
> Task :jib
Containerizing application to sepiro2000/hello-jib, sepiro2000/hello-jib...
Base image 'adoptopenjdk/openjdk16:x86_64-alpine-jdk-16.0.1_9' does not use a specific image digest - build may not be reproducible
The credential helper (docker-credential-osxkeychain) has nothing for server URL: registry-1.docker.io
Got output:
... (중략) ...
Container entrypoint set to [java, -Xms128m, -Xmx128m, -cp, @/app/jib-classpath-file, com.alden.hellojib.HelloJibApplication]
Built and pushed image as sepiro2000/hello-jib, sepiro2000/hello-jib
Executing tasks:
[============================= ] 97.2% complete
> launching layer pushers
BUILD SUCCESSFUL in 54s
3 actionable tasks: 1 executed, 2 up-to-date
그리고 도커 허브의 레포지터리가 가보면 우리가 생성한 이미지가 잘 푸시된 것을 볼 수 있음
도커 허브 화면
그럼 우리가 푸시한 이미지를 다시 풀로 당겨서 실행해 보면 어떻게 될까?
❯ docker pull sepiro2000/hello-jib:latest
latest: Pulling from sepiro2000/hello-jib
5843afab3874: Pull complete
c707850847a4: Pull complete
49491e132a25: Pull complete
8e5a2ca795c6: Pull complete
3abe67bfcfac: Pull complete
6f5dbce1145d: Pull complete
90c7c4122f60: Pull complete
Digest: sha256:17415a3d813c95d2baa2bc620ab5124f3a09d76197057aff558597761dc5c6e8
Status: Downloaded newer image for sepiro2000/hello-jib:latest
docker.io/sepiro2000/hello-jib:latest
~/Desktop/Project/hello-jib 32s
❯ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
sepiro2000/hello-jib latest cebd289c1070 51 years ago 381MB
~/Desktop/Project/hello-jib
❯ docker run -p 8080:8080 cebd289c1070
WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
. ____ _ __ _ _
/\\\\ / ___'_ __ _ _(_)_ __ __ _ \\ \\ \\ \\
( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\
\\\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.2)
2021-07-23 13:03:54.700 INFO 1 --- [ main] com.alden.hellojib.HelloJibApplication : Starting HelloJibApplication using Java 16.0.1 on 75b71f372f1b with PID 1 (/app/classes started by root in /)
2021-07-23 13:03:54.707 INFO 1 --- [ main] com.alden.hellojib.HelloJibApplication : No active profile set, falling back to default profiles: default
2021-07-23 13:03:59.159 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2021-07-23 13:03:59.201 INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2021-07-23 13:03:59.202 INFO 1 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.48]
2021-07-23 13:03:59.424 INFO 1 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2021-07-23 13:03:59.424 INFO 1 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 4468 ms
2021-07-23 13:04:00.757 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2021-07-23 13:04:00.799 INFO 1 --- [ main] com.alden.hellojib.HelloJibApplication : Started HelloJibApplication in 7.773 seconds (JVM running for 9.502)
이미지를 정상적으로 잘 받아와서 실행도 잘한 것을 확인할 수 있음
❯ curl -s <http://localhost:8080/>
hello, jib!
curl을 이용한 테스트에도 잘 반응하는 것을 확인할 수 있음
-Maven에서 사용한다면
Jib는 Maven에서도 사용할 수 있습니다. Maven에서 Jib를 사용하기 위해서는 pom.xml 파일에 다음과 같이 의존성을 추가해야 함
xmlCopy code
<build>
<plugins>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>3.1.4</version>
<configuration>
<from>
<image>openjdk:11-jre</image>
</from>
<to>
<image>myregistry/myimage</image>
<tags>
<tag>latest</tag>
<tag>v1</tag>
</tags>
<auth>
<username>myregistry-username</username>
<password>myregistry-password</password>
</auth>
</to>
</configuration>
</plugin>
</plugins>
</build>
위 예제에서는 Maven에 Jib 플러그인을 추가하고, from 블록에서 Docker 이미지의 기본 이미지를 정의하고, to 블록에서 빌드한 이미지를 저장할 레지스트리 및 태그를 정의하고, auth 블록을 사용하여 이미지 저장소에 로그인하는 인증 정보를 설정할 수 있음
'개인공부' 카테고리의 다른 글
Dockerfile, Docker-compose 특징 및 차이 (0) | 2023.04.18 |
---|---|
Multimodule(멀티모듈) 개념 및 사용법 (0) | 2023.04.14 |
java record 개념 및 사용법 (0) | 2023.03.23 |
2023.03.18 TIL (0) | 2023.03.18 |
Sychronization(동기화) / Synchronous(동기) / Asynchronous(비동기) 관련정보 (0) | 2023.03.14 |
댓글