---
title: Kubernetesハンズオン - 9. Cloud Native Buildpacksでアプリケーションのコンテナイメージを作成
tags: ["Kubernetes Handson", "Kubernetes", "PKS", "Cloud Native Buildpacks", "pack"]
categories: ["Dev", "CaaS", "Kubernetes"]
date: 2019-09-23T17:51:52Z
updated: 1970-01-01T00:00:00Z
---

[Cloud Native Buildpacks](https://buildpacks.io/)を使用してアプリケーションのコンテナイメージを作成します。

Dockerのインストールが必要です。

**目次**

<!-- toc -->

### プロジェクトの作成

以下のコマンドを実行すると、`hello-cf`フォルダに雛形プロジェクトが生成されます。

```
$ curl https://start.spring.io/starter.tgz \
       -d artifactId=hello-cf \
       -d baseDir=hello-cf \
       -d dependencies=web,actuator \
       -d packageName=com.example \
       -d applicationName=HelloCfApplication | tar -xzvf -
```

> Spring Boot 2.2.1で動作確認しています。


生成されたプロジェクトのソースを少しだけ修正します。任意のエディタ、IDEで
`hello-cf/src/main/java/com/example/HelloCfApplication.java`を開いてください。

``` java
package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
// ここから追加
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
// ここまで

@SpringBootApplication
@RestController // 追加
public class HelloCfApplication {

        // ここから追加
        @GetMapping("/") 
        public String hello() {
                return "Hello World!";
        }
        // ここまで

        public static void main(String[] args) {
                SpringApplication.run(HelloCfApplication.class, args);
        }
}
```

ソースコードを修正したら、アプリケーションをビルドします。

```
cd hello-cf
./mvnw package -DskipTests=true
```

まずはローカルでアプリケーションを実行してみましょう。

```
$ java -jar target/hello-cf-0.0.1-SNAPSHOT.jar
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.1.RELEASE)

2019-11-13 18:07:31.078  INFO 77861 --- [           main] com.example.HelloCfApplication           : Starting HelloCfApplication v0.0.1-SNAPSHOT on makinoMacBook-puro.local with PID 77861 (/Users/maki/git/hello-cf/target/hello-cf-0.0.1-SNAPSHOT.jar started by maki in /Users/maki/git/hello-cf)
2019-11-13 18:07:31.081  INFO 77861 --- [           main] com.example.HelloCfApplication           : No active profile set, falling back to default profiles: default
2019-11-13 18:07:32.197  INFO 77861 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2019-11-13 18:07:32.214  INFO 77861 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2019-11-13 18:07:32.215  INFO 77861 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.27]
2019-11-13 18:07:32.290  INFO 77861 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2019-11-13 18:07:32.290  INFO 77861 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1119 ms
2019-11-13 18:07:32.709  INFO 77861 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2019-11-13 18:07:32.911  INFO 77861 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 2 endpoint(s) beneath base path '/actuator'
2019-11-13 18:07:32.982  INFO 77861 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2019-11-13 18:07:32.992  INFO 77861 --- [           main] com.example.HelloCfApplication           : Started HelloCfApplication in 2.362 seconds (JVM running for 2.817)
2019-11-13 18:07:36.166  INFO 77861 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-11-13 18:07:36.167  INFO 77861 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2019-11-13 18:07:36.172  INFO 77861 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 5 ms
```

[http://localhost:8080](http://localhost:8080)にアクセスしてください。

![image](https://user-images.githubusercontent.com/106908/63271809-dc382380-c2d5-11e9-8ae7-6b53788d27fc.png)

Hello World!が表示されれば成功です。

### packコマンドでコンテナイメージ作成

Spring BootアプリのDockerイメージを作成するために、[`pack`](https://buildpacks.io/)コマンドを使用します。
`pack`のインストール方法は[こちら](https://buildpacks.io/docs/install-pack/)を参照にしてください。

`pack`でJavaアプリからDockerイメージに変換するには、MavenまたはGradleを使ったビルド自体を`pack`で行う方法とビルド済みのjarから行う方法があります。


`pack`コマンドでDocker Registryへのpushまで行うので、事前に`docker login`を済ませておいてください。

#### ビルド済みのjarからコンテナイメージを作成する場合

次のコマンドを実行してください。

```
./mvnw package -DskipTests=true
pack build <image-name> -p target/hello-cf-0.0.1-SNAPSHOT.jar --builder cloudfoundry/cnb:bionic --publish

# 例: pack build making/hello-cf -p target/hello-cf-0.0.1-SNAPSHOT.jar --builder cloudfoundry/cnb:bionic --publish
```


出力結果
```
bionic: Pulling from cloudfoundry/cnb
Digest: sha256:4de90a3f4904f96af624b6ae32308615388422e8e3805acfc32f3b3be75e7a46
Status: Image is up to date for cloudfoundry/cnb:bionic
===> DETECTING
[detector] 6 of 14 buildpacks participating
[detector] org.cloudfoundry.openjdk                   v1.0.56
[detector] org.cloudfoundry.jvmapplication            v1.0.78
[detector] org.cloudfoundry.tomcat                    v1.1.17
[detector] org.cloudfoundry.springboot                v1.0.106
[detector] org.cloudfoundry.distzip                   v1.0.96
[detector] org.cloudfoundry.springautoreconfiguration v1.0.107
===> RESTORING
[restorer] Cache '/cache': metadata not found, nothing to restore
===> ANALYZING
[analyzer] Writing metadata for uncached layer 'org.cloudfoundry.openjdk:openjdk-jre'
[analyzer] Writing metadata for uncached layer 'org.cloudfoundry.springautoreconfiguration:auto-reconfiguration'
===> BUILDING
[builder] 
[builder] Cloud Foundry OpenJDK Buildpack v1.0.56
[builder]   OpenJDK JRE 11.0.5: Contributing to layer
[builder]     Downloading from https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.5%2B10/OpenJDK11U-jre_x64_linux_hotspot_11.0.5_10.tar.gz
[builder]     Verifying checksum
[builder]     Expanding to /layers/org.cloudfoundry.openjdk/openjdk-jre
[builder]     Writing JAVA_HOME to shared
[builder] 
[builder] Cloud Foundry JVM Application Buildpack v1.0.78
[builder]   Executable JAR: Contributing to layer
[builder]     Writing CLASSPATH to shared
[builder]   Process types:
[builder]     executable-jar: java -cp $CLASSPATH $JAVA_OPTS org.springframework.boot.loader.JarLauncher
[builder]     task:           java -cp $CLASSPATH $JAVA_OPTS org.springframework.boot.loader.JarLauncher
[builder]     web:            java -cp $CLASSPATH $JAVA_OPTS org.springframework.boot.loader.JarLauncher
[builder] 
[builder] Cloud Foundry Spring Boot Buildpack v1.0.106
[builder]   Spring Boot 2.2.1.RELEASE: Contributing to layer
[builder]     Writing CLASSPATH to shared
[builder]   Process types:
[builder]     spring-boot: java -cp $CLASSPATH $JAVA_OPTS com.example.HelloCfApplication
[builder]     task:        java -cp $CLASSPATH $JAVA_OPTS com.example.HelloCfApplication
[builder]     web:         java -cp $CLASSPATH $JAVA_OPTS com.example.HelloCfApplication
[builder] 
[builder] Cloud Foundry Spring Auto-reconfiguration Buildpack v1.0.107
[builder]   Spring Auto-reconfiguration 2.11.0: Contributing to layer
[builder]     Downloading from https://repo.spring.io/release/org/cloudfoundry/java-buildpack-auto-reconfiguration/2.11.0.RELEASE/java-buildpack-auto-reconfiguration-2.11.0.RELEASE.jar
[builder]     Verifying checksum
[builder]     Copying to /layers/org.cloudfoundry.springautoreconfiguration/auto-reconfiguration
[builder]     Writing CLASSPATH to launch
===> EXPORTING
[exporter] Reusing layers from image 'index.docker.io/making/hello-cf@sha256:ffee6db2d274a631353432a3d78bbab4a50bbf58157e6b994cd507d57c6c61af'
[exporter] Adding layer 'app'
[exporter] Adding layer 'config'
[exporter] Adding layer 'launcher'
[exporter] Adding layer 'org.cloudfoundry.openjdk:openjdk-jre'
[exporter] Reusing layer 'org.cloudfoundry.jvmapplication:executable-jar'
[exporter] Adding layer 'org.cloudfoundry.springboot:spring-boot'
[exporter] Adding layer 'org.cloudfoundry.springautoreconfiguration:auto-reconfiguration'
[exporter] *** Images (sha256:acc7ac6c6c6769fbd99722545825b361a23f99d9a87e859423304b7a0ca8a792):
[exporter]       index.docker.io/making/hello-cf:latest
===> CACHING
[cacher] Caching layer 'org.cloudfoundry.openjdk:2f08c469c9a8adea1b6ee3444ba2a8242a7e99d87976a077faf037a9eb7f884b'
[cacher] Caching layer 'org.cloudfoundry.jvmapplication:executable-jar'
[cacher] Caching layer 'org.cloudfoundry.springboot:spring-boot'
[cacher] Caching layer 'org.cloudfoundry.springautoreconfiguration:46ab131165317d91fd4ad3186abf755222744e2d277dc413def06f3ad45ab150'
Successfully built image making/hello-cf
```

Cloud FoundryのCloud Native Buildpacksが使用されています。

Docker Resistryにアクセスして、イメージがpushされていることを確認してください。

![image](https://user-images.githubusercontent.com/106908/65448437-c1784200-de73-11e9-9c8d-8481ad62e542.png)


#### ソースコードからコンテナイメージを作成する場合

ソースコードのビルドからコンテナ上で行います。

次のコマンドを実行してください。初回はキャッシュがないため、Mavenの依存ライブラリダウンロードに時間がかかります。

```
pack build <image-name> --builder cloudfoundry/cnb:bionic --publish

# 例: pack build making/hello-cf --builder cloudfoundry/cnb:bionic --publish
```


出力結果
```
bionic: Pulling from cloudfoundry/cnb
Digest: sha256:4de90a3f4904f96af624b6ae32308615388422e8e3805acfc32f3b3be75e7a46
Status: Image is up to date for cloudfoundry/cnb:bionic
===> DETECTING
[detector] 7 of 14 buildpacks participating
[detector] org.cloudfoundry.openjdk                   v1.0.56
[detector] org.cloudfoundry.buildsystem               v1.0.125
[detector] org.cloudfoundry.jvmapplication            v1.0.78
[detector] org.cloudfoundry.tomcat                    v1.1.17
[detector] org.cloudfoundry.springboot                v1.0.106
[detector] org.cloudfoundry.distzip                   v1.0.96
[detector] org.cloudfoundry.springautoreconfiguration v1.0.107
===> RESTORING
[restorer] Restoring cached layer 'org.cloudfoundry.openjdk:2f08c469c9a8adea1b6ee3444ba2a8242a7e99d87976a077faf037a9eb7f884b'
[restorer] Restoring cached layer 'org.cloudfoundry.jvmapplication:executable-jar'
[restorer] Restoring cached layer 'org.cloudfoundry.springboot:spring-boot'
[restorer] Restoring cached layer 'org.cloudfoundry.springautoreconfiguration:46ab131165317d91fd4ad3186abf755222744e2d277dc413def06f3ad45ab150'
===> ANALYZING
[analyzer] Using cached layer 'org.cloudfoundry.openjdk:2f08c469c9a8adea1b6ee3444ba2a8242a7e99d87976a077faf037a9eb7f884b'
[analyzer] Writing metadata for uncached layer 'org.cloudfoundry.openjdk:openjdk-jre'
[analyzer] Using cached launch layer 'org.cloudfoundry.jvmapplication:executable-jar'
[analyzer] Rewriting metadata for layer 'org.cloudfoundry.jvmapplication:executable-jar'
[analyzer] Using cached launch layer 'org.cloudfoundry.springboot:spring-boot'
[analyzer] Rewriting metadata for layer 'org.cloudfoundry.springboot:spring-boot'
[analyzer] Using cached layer 'org.cloudfoundry.springautoreconfiguration:46ab131165317d91fd4ad3186abf755222744e2d277dc413def06f3ad45ab150'
[analyzer] Writing metadata for uncached layer 'org.cloudfoundry.springautoreconfiguration:auto-reconfiguration'
===> BUILDING
[builder] 
[builder] Cloud Foundry OpenJDK Buildpack v1.0.56
[builder]   OpenJDK JDK 11.0.5: Contributing to layer
[builder]     Downloading from https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.5%2B10/OpenJDK11U-jdk_x64_linux_hotspot_11.0.5_10.tar.gz
[builder]     Verifying checksum
[builder]     Expanding to /layers/org.cloudfoundry.openjdk/openjdk-jdk
[builder]     Writing JAVA_HOME to build
[builder]     Writing JDK_HOME to build
[builder]   OpenJDK JRE 11.0.5: Reusing cached layer
[builder] 
[builder] Cloud Foundry Build System Buildpack v1.0.125
[builder]     Using wrapper
[builder]     Linking Cache to /home/cnb/.m2
[builder]   Compiled Application: Contributing to layer
[builder]     Executing /workspace/mvnw -Dmaven.test.skip=true package
[builder] [INFO] Scanning for projects...
[builder] Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-starter-parent/2.2.1.RELEASE/spring-boot-starter-parent-2.2.1.RELEASE.pom
...(略)...
[builder] Downloaded from central: https://repo.maven.apache.org/maven2/org/vafer/jdependency/2.1.1/jdependency-2.1.1.jar (186 kB at 73 kB/s)
Downloaded from central: https://repo.maven.apache.org/maven2/com/google/guava/guava/19.0/guava-19.0.jar (2.3 MB at 455 kB/s)
[builder] [INFO] Replacing main artifact with repackaged archive
[builder] [INFO] ------------------------------------------------------------------------
[builder] [INFO] BUILD SUCCESS
[builder] [INFO] ------------------------------------------------------------------------
[builder] [INFO] Total time:  02:05 min
[builder] [INFO] Finished at: 2019-11-13T09:18:10Z
[builder] [INFO] ------------------------------------------------------------------------
[builder]   Removing source code
[builder] 
[builder] Cloud Foundry JVM Application Buildpack v1.0.78
[builder]   Executable JAR: Reusing cached layer
[builder]   Process types:
[builder]     executable-jar: java -cp $CLASSPATH $JAVA_OPTS org.springframework.boot.loader.JarLauncher
[builder]     task:           java -cp $CLASSPATH $JAVA_OPTS org.springframework.boot.loader.JarLauncher
[builder]     web:            java -cp $CLASSPATH $JAVA_OPTS org.springframework.boot.loader.JarLauncher
[builder] 
[builder] Cloud Foundry Spring Boot Buildpack v1.0.106
[builder]   Spring Boot 2.2.1.RELEASE: Reusing cached layer
[builder]   Process types:
[builder]     spring-boot: java -cp $CLASSPATH $JAVA_OPTS com.example.HelloCfApplication
[builder]     task:        java -cp $CLASSPATH $JAVA_OPTS com.example.HelloCfApplication
[builder]     web:         java -cp $CLASSPATH $JAVA_OPTS com.example.HelloCfApplication
[builder] 
[builder] Cloud Foundry Spring Auto-reconfiguration Buildpack v1.0.107
[builder]   Spring Auto-reconfiguration 2.11.0: Reusing cached layer
===> EXPORTING
[exporter] Reusing layers from image 'index.docker.io/making/hello-cf@sha256:acc7ac6c6c6769fbd99722545825b361a23f99d9a87e859423304b7a0ca8a792'
[exporter] Adding layer 'app'
[exporter] Adding layer 'config'
[exporter] Reusing layer 'launcher'
[exporter] Reusing layer 'org.cloudfoundry.openjdk:openjdk-jre'
[exporter] Reusing layer 'org.cloudfoundry.jvmapplication:executable-jar'
[exporter] Reusing layer 'org.cloudfoundry.springboot:spring-boot'
[exporter] Reusing layer 'org.cloudfoundry.springautoreconfiguration:auto-reconfiguration'
[exporter] *** Images (sha256:decb11a1e79157d0bc4cc10be1a0ce98e0e39fbaa3aaba0f076c5fd61a8e7d57):
[exporter]       index.docker.io/making/hello-cf:latest
===> CACHING
[cacher] Reusing layer 'org.cloudfoundry.openjdk:2f08c469c9a8adea1b6ee3444ba2a8242a7e99d87976a077faf037a9eb7f884b'
[cacher] Caching layer 'org.cloudfoundry.openjdk:6dd0c9c8a740e6c19149e98034fba8e368fd9aa16ab417aa636854d40db1a161'
[cacher] Caching layer 'org.cloudfoundry.openjdk:openjdk-jdk'
[cacher] Caching layer 'org.cloudfoundry.buildsystem:build-system-cache'
[cacher] Reusing layer 'org.cloudfoundry.jvmapplication:executable-jar'
[cacher] Reusing layer 'org.cloudfoundry.springboot:spring-boot'
[cacher] Reusing layer 'org.cloudfoundry.springautoreconfiguration:46ab131165317d91fd4ad3186abf755222744e2d277dc413def06f3ad45ab150'
Successfully built image making/hello-cf
```

### Kubernetesへデプロイ

`hello-cf.yml`を作成して、次の内容を記述してください。

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-cf
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello-cf
  template:
    metadata:
      labels:
        app: hello-cf
    spec:
      containers:
      - image: <image-name>:latest
        # 例: 
        # image: making/hello-cf:latest
        name: hello-cf
        ports:
        - containerPort: 8080
        env:
        - name: _JAVA_OPTIONS
          value: "-Xmx76221K -Xss1M -XX:MaxMetaspaceSize=89666K -XX:ReservedCodeCacheSize=32M -XX:MaxDirectMemorySize=32M"
        resources:
          limits:
            memory: "256Mi"
          requests:
            memory: "256Mi"
        readinessProbe:
          httpGet:
            path: /actuator/health
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 5
          timeoutSeconds: 3
          failureThreshold: 3
          periodSeconds: 5
        livenessProbe:
          httpGet:
            path: /actuator/info
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 10
          timeoutSeconds: 1
          periodSeconds: 10
          failureThreshold: 1
---
kind: Service
apiVersion: v1
metadata:
  name: hello-cf
spec:
  type: LoadBalancer
  # 環境によってはNodePort
  selector:
    app: hello-cf
  ports:
  - protocol: TCP
    port: 8080
```

次のコマンドを実行してデプロイしてください。

```
kubectl apply -f hello-cf.yml
```

出力結果
```
deployment.apps/hello-cf created
service/hello-cf created
```

`kubectl get all`で作成されたリソースを確認してください。

出力結果例
```
NAME                          READY   STATUS    RESTARTS   AGE
pod/hello-cf-8479db89-8xgx9   1/1     Running   0          61s

NAME                 TYPE           CLUSTER-IP      EXTERNAL-IP                                                                  PORT(S)          AGE
service/hello-cf     LoadBalancer   10.100.200.86   ac5dd53b3de2711e9812f06c9c16b7d6-10959706.ap-northeast-1.elb.amazonaws.com   8080:30088/TCP   2m1s
service/kubernetes   ClusterIP      10.100.200.1    <none>                                                                       443/TCP          252d

NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/hello-cf   1/1     1            1           2m1s

NAME                                DESIRED   CURRENT   READY   AGE
replicaset.apps/hello-cf-8479db89   1         1         1       61s
```

`http://<ServiceのExternal IP>:8080`にアクセスしてください。

```
curl http://<ServiceのExternal IP>:8080
```

出力結果
```
Hello World!
```

### kbldでイメージDigestを自動更新


まずはアプリケーションを更新します。

`HelloCfApplication.java`を修正して、次の箇所を変更してください。

```java
        @GetMapping("/") 
        public String hello() {
                return "Hello World V2!"; // <- V2に変更
        }
```

ビルド&イメージのpushを行います。


#### ビルド済みのjarからコンテナイメージを作成する場合

```
./mvnw package -DskipTests=true
pack build <image-name> -p target/hello-cf-0.0.1-SNAPSHOT.jar --builder cloudfoundry/cnb:bionic --publish --no-pull

# 例: pack build making/hello-cf -p target/hello-cf-0.0.1-SNAPSHOT.jar --builder cloudfoundry/cnb:bionic --publish --no-pull
```

> `pack build`の2回目以降は`--no-pull`を付けると少し速いです。

出力結果
```
Selected run image cloudfoundry/run:base-cnb
Executing lifecycle version 0.4.0
Using build cache volume pack-cache-5932ea71ff2f.build
===> DETECTING
[detector] ======== Results ========
[detector] skip: org.cloudfoundry.archiveexpanding@v1.0.35
[detector] pass: org.cloudfoundry.openjdk@v1.0.19
[detector] skip: org.cloudfoundry.buildsystem@v1.0.39
[detector] pass: org.cloudfoundry.jvmapplication@v1.0.27
[detector] pass: org.cloudfoundry.tomcat@v1.0.42
[detector] pass: org.cloudfoundry.springboot@v1.0.33
[detector] pass: org.cloudfoundry.distzip@v1.0.33
[detector] skip: org.cloudfoundry.procfile@v1.0.12
[detector] skip: org.cloudfoundry.azureapplicationinsights@v1.0.36
[detector] skip: org.cloudfoundry.debug@v1.0.36
[detector] skip: org.cloudfoundry.googlestackdriver@v1.0.22
[detector] skip: org.cloudfoundry.jdbc@v1.0.34
[detector] skip: org.cloudfoundry.jmx@v1.0.33
[detector] pass: org.cloudfoundry.springautoreconfiguration@v1.0.40
[detector] Resolving plan... (try #1)
[detector] fail: org.cloudfoundry.openjdk@v1.0.19 provides unused openjdk-jdk
[detector] Resolving plan... (try #2)
[detector] fail: org.cloudfoundry.jvmapplication@v1.0.27 requires openjdk-jre
[detector] Resolving plan... (try #3)
[detector] Success! (6)
===> RESTORING
[restorer] Restoring cached layer 'org.cloudfoundry.openjdk:70d2cc675155476f1d8516a7ae6729d44681e4fad5a6fc8dfa65cab36a67b7e0'
[restorer] Restoring cached layer 'org.cloudfoundry.jvmapplication:executable-jar'
[restorer] Restoring cached layer 'org.cloudfoundry.springboot:spring-boot'
[restorer] Restoring cached layer 'org.cloudfoundry.springautoreconfiguration:aa54b17fc69a91043437036291e9bad8f5cbf9950fb9bd22c57fe13543b731ce'
===> ANALYZING
[analyzer] Analyzing image 'index.docker.io/making/hello-cf@sha256:13a768a45a28463ffd5ec6a76debf6beb86a05503c565d069ebc7e1dbb860039'
[analyzer] Using cached layer 'org.cloudfoundry.openjdk:70d2cc675155476f1d8516a7ae6729d44681e4fad5a6fc8dfa65cab36a67b7e0'
[analyzer] Writing metadata for uncached layer 'org.cloudfoundry.openjdk:openjdk-jre'
[analyzer] Using cached launch layer 'org.cloudfoundry.jvmapplication:executable-jar'
[analyzer] Rewriting metadata for layer 'org.cloudfoundry.jvmapplication:executable-jar'
[analyzer] Using cached launch layer 'org.cloudfoundry.springboot:spring-boot'
[analyzer] Rewriting metadata for layer 'org.cloudfoundry.springboot:spring-boot'
[analyzer] Using cached layer 'org.cloudfoundry.springautoreconfiguration:aa54b17fc69a91043437036291e9bad8f5cbf9950fb9bd22c57fe13543b731ce'
[analyzer] Writing metadata for uncached layer 'org.cloudfoundry.springautoreconfiguration:auto-reconfiguration'
===> BUILDING
[builder] 
[builder] Cloud Foundry OpenJDK Buildpack v1.0.19
[builder]   OpenJDK JRE 11.0.4: Reusing cached layer
[builder] 
[builder] Cloud Foundry JVM Application Buildpack v1.0.27
[builder]   Executable JAR: Reusing cached layer
[builder]   Process types:
[builder]     executable-jar: java -cp $CLASSPATH $JAVA_OPTS org.springframework.boot.loader.JarLauncher
[builder]     task:           java -cp $CLASSPATH $JAVA_OPTS org.springframework.boot.loader.JarLauncher
[builder]     web:            java -cp $CLASSPATH $JAVA_OPTS org.springframework.boot.loader.JarLauncher
[builder] 
[builder] Cloud Foundry Spring Boot Buildpack v1.0.33
[builder]   Spring Boot 2.1.8.RELEASE: Reusing cached layer
[builder]   Process types:
[builder]     spring-boot: java -cp $CLASSPATH $JAVA_OPTS com.example.HelloCfApplication
[builder]     task:        java -cp $CLASSPATH $JAVA_OPTS com.example.HelloCfApplication
[builder]     web:         java -cp $CLASSPATH $JAVA_OPTS com.example.HelloCfApplication
[builder] 
[builder] Cloud Foundry Spring Auto-reconfiguration Buildpack v1.0.40
[builder]   Spring Auto-reconfiguration 2.9.0: Reusing cached layer
===> EXPORTING
[exporter] Reusing layers from image 'index.docker.io/making/hello-cf@sha256:13a768a45a28463ffd5ec6a76debf6beb86a05503c565d069ebc7e1dbb860039'
[exporter] Reusing layer 'app' with SHA sha256:3e10ef0afc2a159075aeb4cd5afab2bdf46c610de082729329611a5e6c36b887
[exporter] Reusing layer 'config' with SHA sha256:e53a62cd0c4aee176ad63cf82c18198151d52fa7dbe8d19f9747142cba736a21
[exporter] Reusing layer 'launcher' with SHA sha256:ef2cd5869b4d3995edbba8144c8c448f864f3895ea264967701a9a97547d6087
[exporter] Reusing layer 'org.cloudfoundry.openjdk:openjdk-jre' with SHA sha256:c01d3108656d9135fa72131e2e7be2122ff54d7684565aa8ef88682ade2a3781
[exporter] Reusing layer 'org.cloudfoundry.jvmapplication:executable-jar' with SHA sha256:3d9310c8403c8710b6adcd40999547d6dc790513c64bba6abc7a338b429c35d2
[exporter] Reusing layer 'org.cloudfoundry.springboot:spring-boot' with SHA sha256:d8a111b9b3e0b47a5220cdc93b1376e468ec12a55912b8e7d143e625b1418871
[exporter] Reusing layer 'org.cloudfoundry.springautoreconfiguration:auto-reconfiguration' with SHA sha256:2b9cf72c4fd529569eef2748180a4f5e5e5eb53683c4cc616b5c07bf66e9fead
[exporter] *** Images:
[exporter]       index.docker.io/making/hello-cf:latest - succeeded
[exporter] 
[exporter] *** Digest: sha256:2ebe3bbe0663dd7ffbb8f265d3239fa4d37dafc280dd165593a1e104d255a082
===> CACHING
[cacher] Reusing layer 'org.cloudfoundry.openjdk:70d2cc675155476f1d8516a7ae6729d44681e4fad5a6fc8dfa65cab36a67b7e0' with SHA sha256:bb6cf0ee3ec0f3f19dd10c0b8dceed7aa7d688895c873bf876c4e4b69bb969a6
[cacher] Reusing layer 'org.cloudfoundry.jvmapplication:executable-jar' with SHA sha256:3d9310c8403c8710b6adcd40999547d6dc790513c64bba6abc7a338b429c35d2
[cacher] Reusing layer 'org.cloudfoundry.springboot:spring-boot' with SHA sha256:d8a111b9b3e0b47a5220cdc93b1376e468ec12a55912b8e7d143e625b1418871
[cacher] Reusing layer 'org.cloudfoundry.springautoreconfiguration:aa54b17fc69a91043437036291e9bad8f5cbf9950fb9bd22c57fe13543b731ce' with SHA sha256:93e4b1fe2affe2b342f0f098c827c58417f2a0624bdc57be9442ca7fbc526fe1
Successfully built image making/hello-cf
```

#### ソースコードからコンテナイメージを作成する場合

```
pack build <image-name> --builder cloudfoundry/cnb:bionic --publish --no-pull

# 例: pack build making/hello-cf --builder cloudfoundry/cnb:bionic --publish --no-pull
```

> `pack build`の2回目以降は`--no-pull`を付けると少し速いです。またビルドのキャッシュも効きます。

出力結果
```
bionic: Pulling from cloudfoundry/cnb
Digest: sha256:4de90a3f4904f96af624b6ae32308615388422e8e3805acfc32f3b3be75e7a46
Status: Image is up to date for cloudfoundry/cnb:bionic
===> DETECTING
[detector] 6 of 14 buildpacks participating
[detector] org.cloudfoundry.openjdk                   v1.0.56
[detector] org.cloudfoundry.jvmapplication            v1.0.78
[detector] org.cloudfoundry.tomcat                    v1.1.17
[detector] org.cloudfoundry.springboot                v1.0.106
[detector] org.cloudfoundry.distzip                   v1.0.96
[detector] org.cloudfoundry.springautoreconfiguration v1.0.107
===> RESTORING
[restorer] Restoring cached layer 'org.cloudfoundry.openjdk:2f08c469c9a8adea1b6ee3444ba2a8242a7e99d87976a077faf037a9eb7f884b'
[restorer] Restoring cached layer 'org.cloudfoundry.openjdk:6dd0c9c8a740e6c19149e98034fba8e368fd9aa16ab417aa636854d40db1a161'
[restorer] Restoring cached layer 'org.cloudfoundry.openjdk:openjdk-jdk'
[restorer] Restoring cached layer 'org.cloudfoundry.jvmapplication:executable-jar'
[restorer] Restoring cached layer 'org.cloudfoundry.springboot:spring-boot'
[restorer] Restoring cached layer 'org.cloudfoundry.springautoreconfiguration:46ab131165317d91fd4ad3186abf755222744e2d277dc413def06f3ad45ab150'
===> ANALYZING
[analyzer] Using cached layer 'org.cloudfoundry.openjdk:2f08c469c9a8adea1b6ee3444ba2a8242a7e99d87976a077faf037a9eb7f884b'
[analyzer] Using cached layer 'org.cloudfoundry.openjdk:6dd0c9c8a740e6c19149e98034fba8e368fd9aa16ab417aa636854d40db1a161'
[analyzer] Using cached layer 'org.cloudfoundry.openjdk:openjdk-jdk'
[analyzer] Writing metadata for uncached layer 'org.cloudfoundry.openjdk:openjdk-jre'
[analyzer] Using cached launch layer 'org.cloudfoundry.jvmapplication:executable-jar'
[analyzer] Rewriting metadata for layer 'org.cloudfoundry.jvmapplication:executable-jar'
[analyzer] Using cached launch layer 'org.cloudfoundry.springboot:spring-boot'
[analyzer] Rewriting metadata for layer 'org.cloudfoundry.springboot:spring-boot'
[analyzer] Using cached layer 'org.cloudfoundry.springautoreconfiguration:46ab131165317d91fd4ad3186abf755222744e2d277dc413def06f3ad45ab150'
[analyzer] Writing metadata for uncached layer 'org.cloudfoundry.springautoreconfiguration:auto-reconfiguration'
===> BUILDING
[builder] 
[builder] Cloud Foundry OpenJDK Buildpack v1.0.56
[builder]   OpenJDK JRE 11.0.5: Reusing cached layer
[builder]   Removing unused layers
[builder]     6dd0c9c8a740e6c19149e98034fba8e368fd9aa16ab417aa636854d40db1a161
[builder]     openjdk-jdk
[builder] 
[builder] Cloud Foundry JVM Application Buildpack v1.0.78
[builder]   Executable JAR: Reusing cached layer
[builder]   Process types:
[builder]     executable-jar: java -cp $CLASSPATH $JAVA_OPTS org.springframework.boot.loader.JarLauncher
[builder]     task:           java -cp $CLASSPATH $JAVA_OPTS org.springframework.boot.loader.JarLauncher
[builder]     web:            java -cp $CLASSPATH $JAVA_OPTS org.springframework.boot.loader.JarLauncher
[builder] 
[builder] Cloud Foundry Spring Boot Buildpack v1.0.106
[builder]   Spring Boot 2.2.1.RELEASE: Reusing cached layer
[builder]   Process types:
[builder]     spring-boot: java -cp $CLASSPATH $JAVA_OPTS com.example.HelloCfApplication
[builder]     task:        java -cp $CLASSPATH $JAVA_OPTS com.example.HelloCfApplication
[builder]     web:         java -cp $CLASSPATH $JAVA_OPTS com.example.HelloCfApplication
[builder] 
[builder] Cloud Foundry Spring Auto-reconfiguration Buildpack v1.0.107
[builder]   Spring Auto-reconfiguration 2.11.0: Reusing cached layer
===> EXPORTING
[exporter] Reusing layers from image 'index.docker.io/making/hello-cf@sha256:decb11a1e79157d0bc4cc10be1a0ce98e0e39fbaa3aaba0f076c5fd61a8e7d57'
[exporter] Adding layer 'app'
[exporter] Adding layer 'config'
[exporter] Reusing layer 'launcher'
[exporter] Reusing layer 'org.cloudfoundry.openjdk:openjdk-jre'
[exporter] Reusing layer 'org.cloudfoundry.jvmapplication:executable-jar'
[exporter] Reusing layer 'org.cloudfoundry.springboot:spring-boot'
[exporter] Reusing layer 'org.cloudfoundry.springautoreconfiguration:auto-reconfiguration'
[exporter] *** Images (sha256:648796d493059758cfbf4f9ccb29c5912124007a3acbba57f7756ae6fd05e027):
[exporter]       index.docker.io/making/hello-cf:latest
===> CACHING
[cacher] Reusing layer 'org.cloudfoundry.openjdk:2f08c469c9a8adea1b6ee3444ba2a8242a7e99d87976a077faf037a9eb7f884b'
[cacher] Reusing layer 'org.cloudfoundry.jvmapplication:executable-jar'
[cacher] Reusing layer 'org.cloudfoundry.springboot:spring-boot'
[cacher] Reusing layer 'org.cloudfoundry.springautoreconfiguration:46ab131165317d91fd4ad3186abf755222744e2d277dc413def06f3ad45ab150'
Successfully built image making/hello-cf
```

---

Dockerイメージのタグが`latest`で同じであり、また`hello-cf.yml`に何も変更がないため`kubectl apply -f hello-cf.yml`を実行しても何も変化が起きません。

この場合は、`hello-cf.yml`中の

```
image: <image-name>:latest
```

の部分を

```
image: <image-name>@sha256:<image-digest>
```

形式にすれば確実に指定したイメージへアップデートされます。

上記の出力結果の場合は、`image`に設定する値は`making/hello-cf@sha256:2ebe3bbe0663dd7ffbb8f265d3239fa4d37dafc280dd165593a1e104d255a082`です。


[`kbld`](https://get-kbld.io)を使うと、`<image-digest>`を更新する作業を次のコマンドで自動化できます。

[こちら](https://github.com/k14s/kbld/releases)からバイナリをダウンロードして`kbld`をインストールしてください。


次のコマンドを実行してコンテナイメージを更新してください。
```
kbld -f hello-cf.yml | kubectl apply -f - 
```

出力結果

```
resolve | final: making/hello-cf:latest -> index.docker.io/making/hello-cf@sha256:2ebe3bbe0663dd7ffbb8f265d3239fa4d37dafc280dd165593a1e104d255a082
deployment.apps/hello-cf configured
service/hello-cf unchanged
```

再度、`http://<ServiceのExternal IP>:8080`にアクセスしてください。

```
curl http://<ServiceのExternal IP>:8080
```

出力結果
```
Hello World V2!
```

### リソースの削除

```
kubectl delete -f hello-cf.yml 
```

出力結果

```
deployment.apps "hello-cf" deleted
service "hello-cf" deleted
```
