---
title: Cloud Native Buildpacks Tutorial - 8.2. ┗ Cloud Native BuildpacksでビルドしたOCIイメージをKubernetesへデプロイ
tags: ["Cloud Native Buildpacks Tutorial", "Cloud Native Buildpacks", "Spring Boot", "Kubernetes", "Series"]
categories: ["Dev", "Infrastructure", "CloudNativeBuildpacks", "Kubernetes"]
date: 2020-04-28T17:05:50Z
updated: 2020-05-11T09:05:54Z
---

Cloud Native BuildpacksでビルドしたOCIイメージ([`making/hello-cnb`](https://hub.docker.com/r/making/hello-cnb))をKubernetesにデプロイします。

ここでは[Docker for Mac](https://docs.docker.com/docker-for-mac/#kubernetes)を使用しますが、他のKubernetesでも同じようにデプロイできます。
ただし、`LoadBalancer` typeの`Service`がサポートされていることを前提とします。

**目次**
<!-- toc -->

### Kubernetesの確認

```
$ kubectl cluster-info
Kubernetes master is running at https://kubernetes.docker.internal:6443
KubeDNS is running at https://kubernetes.docker.internal:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
Metrics-server is running at https://kubernetes.docker.internal:6443/api/v1/namespaces/kube-system/services/https:metrics-server:/proxy
```

### アプリケーションのデプロイ

次のコマンドで`deployment.yml`を作成します。

```yaml
mkdir deploy-to-k8s
cd deploy-to-k8s

cat <<'EOF' > deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-cnb
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello-cnb
  template:
    metadata:
      labels:
        app: hello-cnb
    spec:
      containers:
      - image: making/hello-cnb:latest
        name: hello-cnb
        ports:
        - containerPort: 8080
        env:
        - name: INFO_MESSAGE
          value: Hello World!
        resources:
          limits:
            memory: "768Mi"
          requests:
            memory: "768Mi"
        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-cnb
spec:
  type: LoadBalancer
  selector:
    app: hello-cnb
  ports:
  - protocol: TCP
    port: 8080
EOF
```

`kubectl apply`コマンドでデプロイしてください。

```
kubectl apply -f deployment.yml
```

次のようなログが出力されます。

```
deployment.apps/hello-cnb created
service/hello-cnb created
```

`kubectl logs`でログを確認します。

```
$ kubectl logs -l app=hello-cnb --tail=15
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -XX:MaxMetaspaceSize=88833K -XX:ReservedCodeCacheSize=240M -Xss1M -Xmx185598K (Head Room: 0%, Loaded Class Count: 13270, Thread Count: 250, Total Memory: 805306368)

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.6.RELEASE)

2020-04-28 16:54:39.817  INFO 1 --- [           main] hello.HelloCnbApplication                : Starting HelloCnbApplication on hello-cnb-ff6969584-n6cd8 with PID 1 (/workspace/BOOT-INF/classes started by cnb in /workspace)
2020-04-28 16:54:39.821  INFO 1 --- [           main] hello.HelloCnbApplication                : No active profile set, falling back to default profiles: default
2020-04-28 16:54:41.299  INFO 1 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 2 endpoint(s) beneath base path '/actuator'
2020-04-28 16:54:41.940  INFO 1 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port(s): 8080
2020-04-28 16:54:41.945  INFO 1 --- [           main] hello.HelloCnbApplication                : Started HelloCnbApplication in 2.707 seconds (JVM running for 3.29)
```

指定したコンテナのメモリに合わせて、JVMのメモリが自動で設定されていることに注目してください。

LoadBalancerのIPを変数に設定しておきます。
```
LB_IP=$(kubectl get service hello-cnb -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
```

アプリににアクセスしてください。

```
$ curl http://${LB_IP}:8080/actuator/health -w '\n'
{"status":"UP"}

$ curl http://${LB_IP}:8080/actuator/info -w '\n'
{"message":"Hello World!"}
```

### メモリの調整

Buildpackに含まれる[Java Buildpack Memory Calculator](https://github.com/cloudfoundry/java-buildpack-memory-calculator)の機能を使って、
自動設定されるJVMのメモリを調整し、少ないメモリ量(256MiB)で起動できるようにします。

`deployment.yml`を次のように変更してください。

```
cat <<'EOF' > deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-cnb
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello-cnb
  template:
    metadata:
      labels:
        app: hello-cnb
    spec:
      containers:
      - image: making/hello-cnb:latest
        name: hello-cnb
        ports:
        - containerPort: 8080
        env:
        - name: INFO_MESSAGE
          value: Hello World!
        - name: JAVA_OPTS
          value: "-XX:ReservedCodeCacheSize=32M -Xss512k"
        - name: BPL_JVM_THREAD_COUNT
          value: "20"
        - name: BPL_JVM_HEAD_ROOM
          value: "5"
        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-cnb
spec:
  type: LoadBalancer
  selector:
    app: hello-cnb
  ports:
  - protocol: TCP
    port: 8080
EOF
```

Manifestの差分を確認します。

```
$ kubectl diff -f deployment.yml 
diff -u -N /var/folders/76/vg4pyy253pbgwzncmx2mb1gh0000gq/T/LIVE-698159621/apps.v1.Deployment.default.hello-cnb /var/folders/76/vg4pyy253pbgwzncmx2mb1gh0000gq/T/MERGED-179403168/apps.v1.Deployment.default.hello-cnb
--- /var/folders/76/vg4pyy253pbgwzncmx2mb1gh0000gq/T/LIVE-698159621/apps.v1.Deployment.default.hello-cnb	2020-04-29 02:03:58.000000000 +0900
+++ /var/folders/76/vg4pyy253pbgwzncmx2mb1gh0000gq/T/MERGED-179403168/apps.v1.Deployment.default.hello-cnb	2020-04-29 02:03:58.000000000 +0900
@@ -6,7 +6,7 @@
     kubectl.kubernetes.io/last-applied-configuration: |
       {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"hello-cnb","namespace":"default"},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"hello-cnb"}},"template":{"metadata":{"labels":{"app":"hello-cnb"}},"spec":{"containers":[{"env":[{"name":"INFO_MESSAGE","value":"Hello World!"}],"image":"making/hello-cnb:latest","livenessProbe":{"failureThreshold":1,"httpGet":{"path":"/actuator/info","port":8080,"scheme":"HTTP"},"initialDelaySeconds":10,"periodSeconds":10,"timeoutSeconds":1},"name":"hello-cnb","ports":[{"containerPort":8080}],"readinessProbe":{"failureThreshold":3,"httpGet":{"path":"/actuator/health","port":8080,"scheme":"HTTP"},"initialDelaySeconds":5,"periodSeconds":5,"timeoutSeconds":3},"resources":{"limits":{"memory":"768Mi"},"requests":{"memory":"768Mi"}}}]}}}}
   creationTimestamp: "2020-04-28T16:54:35Z"
-  generation: 1
+  generation: 2
   name: hello-cnb
   namespace: default
   resourceVersion: "444989"
@@ -34,6 +34,12 @@
       - env:
         - name: INFO_MESSAGE
           value: Hello World!
+        - name: JAVA_OPTS
+          value: -XX:ReservedCodeCacheSize=32M -Xss512k
+        - name: BPL_JVM_THREAD_COUNT
+          value: "20"
+        - name: BPL_JVM_HEAD_ROOM
+          value: "5"
         image: making/hello-cnb:latest
         imagePullPolicy: Always
         livenessProbe:
@@ -62,9 +68,9 @@
           timeoutSeconds: 3
         resources:
           limits:
-            memory: 768Mi
+            memory: 256Mi
           requests:
-            memory: 768Mi
+            memory: 256Mi
         terminationMessagePath: /dev/termination-log
         terminationMessagePolicy: File
       dnsPolicy: ClusterFirst
exit status 1
```

アップデートします。

```
kubectl apply -f deployment.yml
```

`kubectl logs`でメモリの設定が次のように出力されていることを確認してください。

```
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -XX:MaxMetaspaceSize=88833K -Xmx106954K (Head Room: 5%, Loaded Class Count: 13270, Thread Count: 20, Total Memory: 268435456)
```

### アプリケーションの削除

次のコマンドでアプリとLoadBalancerを削除します。

```
kubectl delete -f deployment.yml
```
