본문 바로가기
개인공부

jib란?

by 리승우 2023. 4. 4.

왜 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을 작성해서 원하는 베이스 이미지에 빌드된 결과물을 저장하는 형태로 컨테이너 이미지가 만들어지게 된다.

하지만!

이 과정은 자동화가 어렵다. 왜냐하면

  1. maven이나 gradle 을 이용한 빌드의 과정을 포함해야함
  2. 빌드가 성공했다면 빌드의 결과 파일을 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 이미지 생성 과정의 첫 번째 단계이며, 새로운 이미지를 만드는 데 필수적임
    만약 애플리케이션을 java17버전으로 개발했다면, 베이스 이미지는 아래와 같이 설정해야함**
    FROM openjdk:17-jdk-alpine

 

  • 만약 애플리케이션 개발환경과 일치하도록 베이스 이미지를 설정하지 않는다면?
    1. 호환성 문제
      애플리케이션이 실행되는 런타임 환경과 베이스 이미지에 설치된 라이브러리와 패키지의 버전이 일치하지 않을 경우 호환성 문제가 발생할 수 있음. 이는 애플리케이션의 동작에 영향을 줌
    2. 보안 문제
      베이스 이미지에는 이미 설치된 라이브러리와 패키지가 포함되어 있음 따라서, 애플리케이션이 사용하는 라이브러리와 패키지의 버전이 다르면 보안 취약점이 발생할 수 있음
    3. 성능 문제
      애플리케이션이 실행되는 런타임 환경과 베이스 이미지에 설치된 라이브러리와 패키지의 버전이 일치하지 않을 경우 성능 문제가 발생할 수 있음. 이는 애플리케이션의 처리 속도를 늦출 수 있음

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"]
    }
}
  1. adoptopenjdk/openjdk16:x86_64-alpine-jdk-16.0.1_9 이미지를 베이스 이미지로 지정
  2. 컨테이너 이미지를 만든 후 도커 허브의 sepiro2000/hello-jib 레포에 latest 라는 태그를 넣어서 push
  3. 컨테이너화가 되어 동작할 때는 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 블록을 사용하여 이미지 저장소에 로그인하는 인증 정보를 설정할 수 있음

댓글