BuildpacksとJibを試す

以下のブログにしたがってBuildpacksとJibを試してみるメモ。

サンプルアプリケーション

サンプルリポジトリをクローンする。

git clone https://github.com/jamesward/comparing-docker-methods.git
cd comparing-docker-methods

ローカルにインストールされているJavaMavenを確認する。Corretto 8がインストールされているが、MavenはOpenJDK 17を使っている。

$ java -version
openjdk version "1.8.0_312"
OpenJDK Runtime Environment Corretto-8.312.07.1 (build 1.8.0_312-b07)
OpenJDK 64-Bit Server VM Corretto-8.312.07.1 (build 25.312-b07, mixed mode)
$ mvn -version
Apache Maven 3.8.4 (9b656c72d54e5bacbed989b64718c159fe39b537)
Maven home: /usr/local/Cellar/maven/3.8.4/libexec
Java version: 17.0.1, vendor: Homebrew, runtime: /usr/local/Cellar/openjdk/17.0.1/libexec/openjdk.jdk/Contents/Home
Default locale: ja_JP, platform encoding: UTF-8
OS name: "mac os x", version: "11.6.1", arch: "x86_64", family: "mac"

Maven Wrapperが入っていなかったので入れる。

mvn -N io.takari:maven:0.7.7:wrapper

アプリケーションを実行する。

./mvnw compile exec:java

アプリケーションにアクセスする。

$ curl localhost:8080
hello, world%

Buildpacks

packコマンドをインストールする。

brew install buildpacks/tap/pack

どのビルダーが使えるのかはサジェストしてくれる。

$ pack builder suggest
Suggested builders:
        Google:                gcr.io/buildpacks/builder:v1      Ubuntu 18 base image with buildpacks for .NET, Go, Java, Node.js, and Python                                                      
        Heroku:                heroku/buildpacks:18              Base builder for Heroku-18 stack, based on ubuntu:18.04 base image                                                                
        Heroku:                heroku/buildpacks:20              Base builder for Heroku-20 stack, based on ubuntu:20.04 base image                                                                
        Paketo Buildpacks:     paketobuildpacks/builder:base     Ubuntu bionic base image with buildpacks for Java, .NET Core, NodeJS, Go, Python, Ruby, NGINX and Procfile                        
        Paketo Buildpacks:     paketobuildpacks/builder:full     Ubuntu bionic base image with buildpacks for Java, .NET Core, NodeJS, Go, Python, PHP, Ruby, Apache HTTPD, NGINX and Procfile     
        Paketo Buildpacks:     paketobuildpacks/builder:tiny     Tiny base image (bionic build image, distroless-like run image) with buildpacks for Java, Java Native Image and Go                

Tip: Learn more about a specific builder with:
        pack builder inspect <builder-image>

イメージを全部消す。

docker images -aq | xargs docker rmi -f

イメージをビルドする。

$ pack build --builder=gcr.io/buildpacks/builder:v1 comparing-docker-methods:buildpacks
v1: Pulling from buildpacks/builder
...
Digest: sha256:ae9956349502a7d9b340651ddc536e80821c254c77c16f30742216322b3eff87
Status: Downloaded newer image for gcr.io/buildpacks/builder:v1
v1: Pulling from buildpacks/gcp/run
...
Digest: sha256:3f45378eae3d66d960c6e09ea86739aa568744638f90e40b35b26c254d2f3c27
Status: Downloaded newer image for gcr.io/buildpacks/gcp/run:v1
===> DETECTING
4 of 5 buildpacks participating
google.java.runtime    0.9.1
google.java.maven      0.9.0
google.java.entrypoint 0.9.0
google.utils.label     0.0.1
===> ANALYZING
Previous image with name "comparing-docker-methods:buildpacks" not found
Restoring metadata for "google.java.maven:m2" from cache
===> RESTORING
Restoring data for "google.java.maven:m2" from cache
===> BUILDING
=== Java - Runtime (google.java.runtime@0.9.1) ===
Using latest Java 11 runtime version. You can specify a different version with GOOGLE_RUNTIME_VERSION: https://github.com/GoogleCloudPlatform/buildpacks#configuration
--------------------------------------------------------------------------------
Running "curl --fail --show-error --silent --location https://api.adoptopenjdk.net/v3/assets/feature_releases/11/ga?architecture=x64&heap_size=normal&image_type=jdk&jvm_impl=hotspot&os=linux&page=0&page_size=1&project=jdk&sort_order=DESC&vendor=adoptopenjdk"

[
    {
        "binaries": [
            {
                "architecture": "x64",
                "download_count": 166661,
                "heap_size": "normal",
                "image_type": "jdk",
                "jvm_impl": "hotspot",
                "os": "linux",
                "package": {
                    "checksum": "3b1c0c34be4c894e64135a454f2d5aaa4bd10aea04ec2fa0c0efe6bb26528e30",
                    "checksum_link": "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.13%2B8/OpenJDK11U-jdk_x64_linux_hotspot_11.0.13_8.tar.gz.sha256.txt",
                    "download_count": 166661,
                    "link": "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.13%2B8/OpenJDK11U-jdk_x64_linux_hotspot_11.0.13_8.tar.gz",
                    "metadata_link": "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.13%2B8/OpenJDK11U-jdk_x64_linux_hotspot_11.0.13_8.tar.gz.json",
                    "name": "OpenJDK11U-jdk_x64_linux_hotspot_11.0.13_8.tar.gz",
                    "size": 192958006
                },
                "project": "jdk",
                "scm_ref": "jdk-11.0.13+8_adopt",
                "updated_at": "2021-10-21T21:55:42Z"
            }
        ],
        "download_count": 508086,
        "id": "MDc6UmVsZWFzZTUxODI0ODA2.DrSSnWfQGA0+fw==",
        "release_link": "https://github.com/adoptium/temurin11-binaries/releases/tag/jdk-11.0.13%2B8",
        "release_name": "jdk-11.0.13+8",
        "release_type": "ga",
        "source": {
            "link": "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.13%2B8/OpenJDK11U-sources_11.0.13_8.tar.gz",
            "name": "OpenJDK11U-sources_11.0.13_8.tar.gz",
            "size": 123491655
        },
        "timestamp": "2021-10-21T21:55:18Z",
        "updated_at": "2021-11-15T16:03:02Z",
        "vendor": "eclipse",
        "version_data": {
            "build": 8,
            "major": 11,
            "minor": 0,
            "openjdk_version": "11.0.13+8",
            "security": 13,
            "semver": "11.0.13+8"
        }
    }
]Done "curl --fail --show-error --silent --location https://api.ado..." (850.3602ms)
Installing Java v11.0.13+8
--------------------------------------------------------------------------------
Running "bash -c curl --fail --show-error --silent --location --retry 3 https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.13%2B8/OpenJDK11U-jdk_x64_linux_hotspot_11.0.13_8.tar.gz | tar xz --directory /layers/google.java.runtime/java --strip-components=1"
Done "bash -c curl --fail --show-error --silent --location --retry..." (18.2298941s)
=== Java - Maven (google.java.maven@0.9.0) ===
--------------------------------------------------------------------------------
Running "./mvnw clean package --batch-mode -DskipTests -Dhttp.keepAlive=false --quiet"
Done "./mvnw clean package --batch-mode -DskipTests -Dhttp.keepAli..." (6.8467339s)
=== Java - Entrypoint (google.java.entrypoint@0.9.0) ===
WARNING: Launch layer is setting default=true, but that is not supported until API version 0.6. This setting will be ignored.
Warning: Warning: default processes aren't supported in this buildpack api version. Overriding the default value to false for the following processes: [web]
=== Utils - Label Image (google.utils.label@0.0.1) ===
===> EXPORTING
Adding layer 'google.java.runtime:java'
Adding 1/1 app layer(s)
Adding layer 'launcher'
Adding layer 'config'
Adding layer 'process-types'
Adding label 'io.buildpacks.lifecycle.metadata'
Adding label 'io.buildpacks.build.metadata'
Adding label 'io.buildpacks.project.metadata'
Setting default process type 'web'
Saving comparing-docker-methods:buildpacks...
*** Images (d9a7fa05282b):
      comparing-docker-methods:buildpacks
Reusing cache layer 'google.java.runtime:java'
Reusing cache layer 'google.java.maven:m2'
Successfully built image comparing-docker-methods:buildpacks

イメージを確認する。作成日付がおかしい。

$ docker images
REPOSITORY                  TAG          IMAGE ID       CREATED        SIZE
gcr.io/buildpacks/builder   v1           0be9c8be1372   34 hours ago   626MB
gcr.io/buildpacks/gcp/run   v1           e9c0a00a124f   34 hours ago   120MB
comparing-docker-methods    buildpacks   d9a7fa05282b   41 years ago   444MB

イメージを実行する。

docker run -it -ePORT=8080 -p8080:8080 comparing-docker-methods:buildpacks

アクセス確認する。

$ curl localhost:8080
hello, world%

diveでイメージを見てみる。

dive comparing-docker-methods:buildpacks

f:id:sotoiwa:20211126172335p:plain

ビルド時のメッセージと比較して見ると以下だと思われる。

サイズ 中身
(上の5レイヤー) gcr.io/buildpacks/gcp/run:v1
321 MB Adding layer 'google.java.runtime:java'
177 kB Adding 1/1 app layer(s)
2.5 MB Adding layer 'launcher'
675 B Adding layer 'config'
0 B Adding layer 'process-types'

メッセージからすると、Buildpacksもレイヤリングしてくれそう。

Jib

pom.xmlに以下を追加する。

<plugin>
    <groupId>com.google.cloud.tools</groupId>
    <artifactId>jib-maven-plugin</artifactId>
    <version>2.6.0</version>
</plugin>

イメージを全部消す。

docker images -aq | xargs docker rmi -f

コンテナイメージをビルドしてローカルに保存する。

$ ./mvnw compile jib:dockerBuild -Dimage=comparing-docker-methods:jib
[INFO] Scanning for projects...
[INFO] 
[INFO] ---------------------< com.google:sample-java-mvn >---------------------
[INFO] Building sample-java-mvn 0.1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ sample-java-mvn ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /Users/sotosugi/workspace/2021/aisac/buildpacks/comparing-docker-methods/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ sample-java-mvn ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- jib-maven-plugin:2.6.0:dockerBuild (default-cli) @ sample-java-mvn ---
[INFO] 
[INFO] Containerizing application to Docker daemon as comparing-docker-methods:jib...
[WARNING] Base image 'gcr.io/distroless/java:8' does not use a specific image digest - build may not be reproducible
[INFO] Using base image with digest: sha256:34c3598d83f0dba27820323044ebe79e63ad4f137b405676da75a3905a408adf
[INFO] 
[INFO] Container entrypoint set to [java, -cp, /app/resources:/app/classes:/app/libs/*, com.google.WebApp]
[INFO] 
[INFO] Built image to Docker daemon as comparing-docker-methods:jib
[INFO] Executing tasks:
[INFO] [==============================] 100.0% complete
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  9.371 s
[INFO] Finished at: 2021-11-26T16:24:06+09:00
[INFO] ------------------------------------------------------------------------

イメージを確認する。メッセージにでているが、ベースイメージがgcr.io/distroless/java:8なのでサイズが小さい。

$ docker images
REPOSITORY                 TAG       IMAGE ID       CREATED        SIZE
comparing-docker-methods   jib       625395395d3e   51 years ago   130MB

diveで見てみると、最後の前のレイヤーでディレクトリが作られ、最後のレイヤーでjarが置かれているように見える。

f:id:sotoiwa:20211126172359p:plain

Dockerfile

Dockerfileを作成する。このadoptopenjdk/openjdk8のイメージはUbuntuベースのイメージのようだ。

FROM adoptopenjdk/openjdk8 as builder
WORKDIR /app
COPY . /app
RUN ./mvnw compile jar:jar

FROM adoptopenjdk/openjdk8:jre
COPY --from=builder /app/target/*.jar /server.jar
CMD ["java", "-jar", "/server.jar"]

イメージを全部消す。

docker images -aq | xargs docker rmi -f

ビルドする。

docker build -t comparing-docker-methods:dockerfile .

確認する。

$ docker images
REPOSITORY                 TAG          IMAGE ID       CREATED          SIZE
comparing-docker-methods   dockerfile   42980788df0c   46 seconds ago   224MB

GraalVMを使う方法は省略。

まとめ

packとjibでビルドし直し、またベースイメージもpullして、関連したイメージを全部まとめて一覧表示する。

$ docker images
REPOSITORY                  TAG          IMAGE ID       CREATED          SIZE
comparing-docker-methods    dockerfile   42980788df0c   17 minutes ago   224MB
gcr.io/buildpacks/builder   v1           0be9c8be1372   35 hours ago     626MB
gcr.io/buildpacks/gcp/run   v1           e9c0a00a124f   35 hours ago     120MB
adoptopenjdk/openjdk8       jre          4e41c2a5a301   40 hours ago     224MB
adoptopenjdk/openjdk8       latest       f5be1fb5cc77   40 hours ago     320MB
comparing-docker-methods    buildpacks   fb4cfe8a43ed   41 years ago     444MB
comparing-docker-methods    jib          625395395d3e   51 years ago     130MB
gcr.io/distroless/java      8            b762aad6c014   51 years ago     130MB