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

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

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

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

1. フォークしたリポジトリの中に自分のサービスを作る（内容は簡単なものでよい。言語も問わない）
1. DockerやPodmanなどの技術を使ってサービスをコンテナ化する
1. deployment.yamlを書く
1. 自分のサービスをKyma runtimeにデプロイする

## Week2で学んだこと
### 1. Dockerイメージの作成とリポジトリへのプッシュ
Dockerイメージをどこのリポジトリに格納するかについて、私には2つのオプションがありました。
①GitHubのレジストリを使用する
②Docker Hubを使用する
[元のリポジトリ](https://github.com/SAP-samples/sap-community-code-challenge-cloud-native)がGitHubのレジストリにイメージを上げていたため、これに倣って①の方法をとることにしました。この方法はローカル環境にDockerがインストールされていなくても使うことができます。

#### GitHubのレジストリにDockerイメージをアップロードする方法
GitHubのレジストリにDockerイメージをアップロードするには、GitHub Actionを使用します。元のリポジトリを見てみると、Actionsタブに"Build and Push Docker Image"というワークフローが定義されています。ワークフローは`docker_build_and_push.yml`というファイルで設定されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/e99f58d9-d711-c67c-c5f8-dc4ddfc13a23.png)
ファイルの中身を見たところ、サービスへのパスが直接書かれていたりしたのでそのまま流用はできなさそうでした。そこで、[teched2020-developer-keynote](https://github.com/SAP-archive/teched2020-developer-keynote/blob/main/.github/workflows/image-build-and-publish.yml)のリポジトリにあるワークフローを参考にすることにしました。こちらはDockerfileが格納されたファイルパスやリソースのパスをインプットで指定できるため、汎用的に使うことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/d12a04aa-b392-ec22-8bf4-f14d6a71a316.png)

参考：[Developer Keynote - SANDBOX component part 2 - CF & K8S](https://www.youtube.com/watch?v=yYeiTs4AC_U&list=PL6RpkC85SLQBrZNW-9K3rPikA-KmkZZR_&index=23)

#### 実施したこと
Dockerイメージをアップロードするために実施したことは以下です。

1. ローカルでweek2のブランチを作る
1. my-serviceフォルダを作成し、その中でサービスを定義（内容はserviceとほぼ同じ。Dockerfileは変更なし）
1. .github/workflowsに[image-build-and-publish.yml](https://github.com/SAP-archive/teched2020-developer-keynote/blob/main/.github/workflows/image-build-and-publish.yml)をコピーペースト
1. GitHubにプッシュ
1. "Run workflow"をクリックし、ブランチ(week2)、ディレクトリ(my-service)を指定してワークフローを実行

ワークフローの実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/8a1c5406-f906-603c-33ca-d63aef13a696.png)

実行中は以下のような画面になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/56f856c8-2e64-1028-31c4-5c3c214ef33d.png)

完了すると、自分のリポジトリにパッケージができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/264b72af-5161-3d65-3dfb-f48fddf44b56.png)

あとはdeployment.yamlにこのイメージを指定してデプロイするだけです。

### 2. ポートのマッピング
week2のdeployment.yamlはweek1のものとほとんど同じにしていたのですが、ポートだけ変えてみようと思い各ポートを`8080`から`8081`に変えてみました。

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-service
  labels:
    app: my-service
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-service
  template:
    metadata:
      labels:
        app: my-service
    spec:
      containers:
      - name: my-service
        image: ghcr.io/miyasuta/sap-community-code-challenge-cloud-native/my-service:latest
        imagePullPolicy: Always
        ports:
        - containerPort: 8081
        resources:
            limits:
              ephemeral-storage: 256M
              memory: 256M
              cpu: 100m
            requests:
              cpu: 100m
              ephemeral-storage: 256M
              memory: 256M
      imagePullSecrets:
      - name: regcred
status: {}
      
---
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: my-service
  ports:
  - port: 8081
    targetPort: 8081
    protocol: TCP

---

apiVersion: gateway.kyma-project.io/v1alpha1
kind: APIRule
metadata:
  name: my-service
spec:
  gateway: kyma-gateway.kyma-system.svc.cluster.local
  service:
    name: my-service
    port: 8081
    host: my-service
  rules:
    - path: /.*
      methods: ["GET"]
      accessStrategies:
        - handler: noop
          config: {}
```

デプロイはできたものの、ブラウザからAPIにアクセスすると以下のエラーになりました。
`upstream connect error or disconnect/reset before headers. reset reason: connection failure, transport failure reason: delayed connect error: 111`


原因は、このサービスで使用しているポートは8080なのにcontainerPortに8081を指定していたためです。（`process.env.PORT`にdeployment.yamlで指定したポートが入ってくれるのかなと思ったのですが、そうではないようです）

```javascript:server.js
const express = require('express')
const app = express()

app.get('/', (req, res) => {
  res.send(`Your Node.js service is running on port ${PORT}...`);
});

app.get('/hello/:communityID', (req, res) => {
  res.send(`Hello Kyma, hello ${req.params.communityID}!`);
});

const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
    console.log(`Server listening on port ${PORT}...`);
});
```

ポート8080で動くサービスをポート8081から公開したい場合、以下の設定にする必要があります。他の人が提出した内容を見てこれに気づくことができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/af8f0233-fae8-8d5a-29df-015c2d29ede4.png)

## 参考
以下のブログがポートのマッピングについて理解するのに役立ちました。
[Kyma for Dymmies [2]: First Simple Microservice with Security](https://blogs.sap.com/2020/12/10/kyma-for-dymmies-2-first-simple-microservice-with-security/)