Kyma runtimeのCommunity Code Challengeをやってみた - Week4

この記事は chillSAP [夏の自由研究2022](https://note.com/chillsap/n/n62740563aee0)、8/9の記事として執筆しています。

## はじめに
この記事は、[Kyma runtimeのCommunity Code Challengeをやってみた](https://qiita.com/tami/items/8ffad45ef1ee0f54e8c4)シリーズの4回目で、今回が最終回となります。このシリーズでは、[Kyma runtimeのCode Challenge](https://blogs.sap.com/2022/07/04/sap-community-code-challenge-lets-set-sail-for-cloud-native-island/)に参加して、開発の方法やその裏の仕組みについてわかったことをまとめていきます。

## Week4の課題
Week4の課題は以下のようになっています。
リンク：[Week 4 (July 27th, 2022 - August 3rd, 2022)](https://github.com/SAP-samples/sap-community-code-challenge-cloud-native/blob/main/Challenges.md#week-4-july-27th-2022---august-3rd-2022)

1. Week3で認証をつけてデプロイしたサービスから認証を外す（コードチャレンジの運営側がアクセスできるように）
1. BTPのHorizontal Autoscalerの機能を使用する
1. Pod-countを少なくとも10に増やす

Week4は"Horizontal Autoscaler"というキーワードのみで、ドキュメントやチュートリアルへのリンクもありませんでした。「"Horizontal Autoscaler"とは何ぞや」、「どうやって設定するのか」を自分で調べれるところから開始です。

## Week4で学んだこと
Week4で学んだことは色々ありました。

### 1. Kubernatesを構成するもの
#### 概要
Week4の課題中に「Podを増やす」というワードが出てきましたが、Podとはそもそも何なのか、また、Kubernatesを構成するものは何なのかについて調べてみました。理解を図にしたものが以下です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/81a22052-d96c-eef5-5699-bc932ab91008.png)

**言葉の意味**
|言葉  |意味  |
|---|---|
|cluster  |nodeの集合。Kyma runtimeを有効化すると自動的に1つのclusterが作成される  |
|node  |コンテナ化されたアプリケーションを実行する環境  |
|pod  |実行中のアプリケーションのインスタンス。1つのアプリケーションにつき複数のpodが立ち上がることもある  |
|container  |Dockerコンテナのこと  |

以下の言葉は図中に表すのが難しかったのですが、よく出てくるため載せておきます。

- workload：Kubernates上で実行されるアプリケーションのこと
- namespace：cluster内のオブジェクトを編成し、クラスターのリソースを分割するためのもの。権限制御（誰がどのnamespaceのオブジェクトにアクセスできるか）にも使われる

**参考**

https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/468c2f3c3ca24c2c8497ef9f83154c44.html

https://www.youtube.com/watch?v=iiSKclYuLCs&list=PL6RpkC85SLQCwaJ54TAAHMvSl5wpVPrai&index=6
#### Kyma runtimeで見てみると
トライアル環境には、1つのClusterが存在し、その中に一つのNodeがあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/3912a7a5-29fd-fa67-92e9-2ed42c0e3ca5.png)
Namespaceの中に入るとPodがあります。実際には「Nodeの中にPodがある」という関係ですが、NamespaceはPodを管理するための論理的な存在ととらえています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/e549736e-e4a0-7f1a-9ccd-1e74ec3c8a1c.png)
Podの中をさらに見てみると2つのコンテナがあります。それぞれがDockerコンテナになっています。"my-service"というのが自分で作ったイメージから作成されたコンテナで、"istio-proxy"というのはデフォルトで提供されるコンテナです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/11f8bfd2-6a84-800f-03e2-07a480c5bf80.png)
istioについては以下を参照ください。

https://istio.io/latest/about/service-mesh/#what-is-istio

### 2. Horizontal (Pod) Autoscalerとは
#### 概要
Kubernates上で実行されるワークロード（アプリケーション）のリソースを自動的に増減させる仕組みのことです。事前定義されたCPUやメモリの使用率などのターゲットに合わせて、Podの数を増やしたり減らしたりしてくれます。

https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/

#### 設定方法
以下のチュートリアルを参考に設定しました。

https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/

設定は簡単で、以下のコマンドを実行するだけです。`--cpu-percent=50`で、目標のCPU利用率が50%であることを指定し、`--min1 max=10`で、Podの数の最小値と最大値を指定しています。

```
kubectl autoscale deployment <対象のdeployment> --cpu-percent=50 --min=1 --max=10
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/785cb1c3-b80a-f124-3861-e590ade086c7.png)

以下のコマンドで、Autoscalerが設定されたdeploymentを確認することができます。
```
kubectl get hpa
```
REPLICASが1となっているのは、現在のPodの数が1であることを表しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/76069730-53a8-0983-9bac-07544dddb7c9.png)

### 3. 負荷テストをやってみて
上記のチュートリアルには、アプリケーションに負荷を与えて実際にPodの数が増えることを確認する手順があります。負荷テストをやってみてわかったことが以下です。

#### kubectlコマンドから直接コンテナを立ち上げられる
チュートリアルでは負荷テストのために以下のコマンドで別のPodを立ち上げ、テスト対象のアプリケーションに対して無限にリクエストを送っていました。`kubectl`以降はDockerコンテナを起動するときと同じ要領です。Dockerイメージには[busybox](https://hub.docker.com/_/busybox)を使用しています。

```
kubectl run -i --tty load-generator --rm --image=busybox:1.28 --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- <テスト対象のURL>; done"
```

#### busyboxのwgetはHTTPSリクエストができない
上記のテストを自分が作ったサービスに対して実行したところ、以下のエラーになってしまいました。

```
wget: error getting response: Connection reset by peer
wget: TLS error from peer (alert code 40): handshake failure
```
対象のURLがhttpsのため、wgetでアクセスできないようでした。wgetには複数バージョンがあり、busyboxにインストールされたバージョンでは[https通信が行えないようです](https://github.com/linuxkit/linuxkit/issues/193)。curlも試してみましたが、busyboxでは使えませんでした。
そこで、busyboxの代わりのDockerイメージを使うことにしました。今回使用したのは以下のイメージです。
[cirrusci/wget](https://hub.docker.com/r/cirrusci/wget)

イメージ名のところだけ変えて、以下のコマンドを実行しました。

```
kubectl run -i --tty load-generator --rm --image=cirrusci/wget:latest --restart=Never -c "while sleep 0.01; do wget --no-check-certificate -q -O- <テスト対象のURL>; done"
```
リクエストは成功し、サービスからの応答が無限に返ってきました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/69bb573f-12be-964e-88f1-0d860d88143a.png)

#### Autoscalerの設定変更


負荷をかけている間、以下のコマンドでリソースの使用状況やレプリカの数がどうなったかをリアルタイムに確認できます。

```
kubectl get hpa <対象のdeployment> --watch
```
CPUの使用率は最大35%まで上がったものの、閾値で指定した50%には届かなかったためレプリカは1個のままです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/3708768a-3912-ee6d-fbb9-26652573def5.png)

そこで、CPU使用率の設定を10%に下げてみることにしました。Autoscalerの設定変更の流れは次のようになります。
①現在の設定をyamlファイルにダウンロード
②設定を変更
③`kubectl apply`で設定を反映

##### ①現在の設定をyamlファイルにダウンロード
以下のコマンドで設定ファイルをローカルにダウンロードします。

```
kubectl get hpa <対象のdeployment> -o yaml > <ダウンロード先パス>/<ファイル名>.yaml
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/b9d25450-dbab-f197-b8ca-8d3939daaa38.png)

以下のような設定がダウンロードされました。

```yaml
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  annotations:
    autoscaling.alpha.kubernetes.io/conditions: '[{"type":"AbleToScale","status":"True","lastTransitionTime":"2022-07-29T21:21:45Z","reason":"ScaleDownStabilized","message":"recent
      recommendations were higher than current one, applying the highest recent recommendation"},{"type":"ScalingActive","status":"True","lastTransitionTime":"2022-07-29T21:21:45Z","reason":"ValidMetricFound","message":"the
      HPA was able to successfully calculate a replica count from cpu resource utilization
      (percentage of request)"},{"type":"ScalingLimited","status":"False","lastTransitionTime":"2022-07-29T21:21:45Z","reason":"DesiredWithinRange","message":"the
      desired count is within the acceptable range"}]'
    autoscaling.alpha.kubernetes.io/current-metrics: '[{"type":"Resource","resource":{"name":"cpu","currentAverageUtilization":1,"currentAverageValue":"2m"}}]'
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"autoscaling/v1","kind":"HorizontalPodAutoscaler","metadata":{"annotations":{"autoscaling.alpha.kubernetes.io/conditions":"[{\"type\":\"AbleToScale\",\"status\":\"True\",\"lastTransitionTime\":\"2022-07-29T21:21:45Z\",\"reason\":\"ReadyForNewScale\",\"message\":\"recommended size matches current size\"},{\"type\":\"ScalingActive\",\"status\":\"True\",\"lastTransitionTime\":\"2022-07-29T21:21:45Z\",\"reason\":\"ValidMetricFound\",\"message\":\"the HPA was able to successfully calculate a replica count from cpu resource utilization (percentage of request)\"},{\"type\":\"ScalingLimited\",\"status\":\"False\",\"lastTransitionTime\":\"2022-07-29T21:21:45Z\",\"reason\":\"DesiredWithinRange\",\"message\":\"the desired count is within the acceptable range\"}]","autoscaling.alpha.kubernetes.io/current-metrics":"[{\"type\":\"Resource\",\"resource\":{\"name\":\"cpu\",\"currentAverageUtilization\":1,\"currentAverageValue\":\"2m\"}}]"},"creationTimestamp":"2022-07-29T21:21:15Z","name":"my-service","namespace":"code-challenge","resourceVersion":"156330791","uid":"5640b803-3f76-4b1f-a427-032875551959"},"spec":{"maxReplicas":10,"minReplicas":1,"scaleTargetRef":{"apiVersion":"apps/v1","kind":"Deployment","name":"my-service"},"targetCPUUtilizationPercentage":10},"status":{"currentCPUUtilizationPercentage":1,"currentReplicas":1,"desiredReplicas":1}}
  creationTimestamp: "2022-07-29T21:21:15Z"
  name: my-service
  namespace: code-challenge
  resourceVersion: "156334333"
  uid: 5640b803-3f76-4b1f-a427-032875551959
spec:
  maxReplicas: 10
  minReplicas: 1
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-service
  targetCPUUtilizationPercentage: 50
status:
  currentCPUUtilizationPercentage: 1
  currentReplicas: 3
  desiredReplicas: 3
  lastScaleTime: "2022-07-30T12:25:50Z"
```

##### ②設定を変更
今回はCPU使用率を変更したいので、`targetCPUUtilizationPercentageを50から10に変えます。

##### ③`kubectl apply`で設定を反映
以下のコマンドで設定を反映させます。

```
kubectl apply -f <①でダウンロードしたファイル>
```

この状態で負荷をかけたところ、最大3つまでPodを増やすことができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/0ce989c1-947b-f71a-4133-1c0b09fc93c6.png)
ダッシュボードから見ると以下のような状態です。load-generatorは不可テストのために立てたPodで、それ以外がテスト対象のサービスでのPodです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/73fad7db-9cba-f45e-f91a-ea082120a955.png)

## まとめ：Week1～4で学んだこと
Kyma runtimeについて学んだのは以下のようなことでした。

|week  |学んだこと  |
|---|---|
|1 |Kyma runtimeへのデプロイ方法  |
|2 |自分のDocker imageを作成する方法  |
|3 |サービスに認証をつける方法  |
|4 |Horizontal Pod Autoscalerの使い方  |

## Community Code Challengeをやってみた感想
初心者向けのチャレンジかと思っていたところ、そうでもなかったというのが感想です。Week1だけはStep by Stepの指示があってチュートリアルっぽさがありましたが、以降はゴールだけ示して「自分で調べて頑張ってね！」というスタイル。Week2から「もう無理かもしれない」と思っていたのですが、他の人が自分が実施した方法を[スレッド](https://groups.community.sap.com/t5/application-development/sap-community-code-challenge-let-s-set-sail-for-cloud-native/m-p/5748/thread-id/60)で共有してくれて、それを参考にやりきることができました。こういうところがCommunity Code Challengeの良さだと感じました。