OpenShiftで始めるCI/CD：OpenShift Pipelines入門

# 前提

OpenShift Pipelinesで登場するリソースの説明は下記を参照。

https://rheb.hatenablog.com/entry/2021/07/19/OpenShift_Pipelines_%E3%81%AE%E3%81%94%E7%B4%B9%E4%BB%8B%28Tekton_Pipelines%E7%B7%A8%29

本記事では、OpenShift Pipelines入門として基本編、実践編、応用編に分け、OpenShift Pipelinesのリソース（Task、TaskRun、Pipeline、PipelineRun）の作成例を示す。

# 基本編

## Task
```yaml
apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: hello
spec:
  steps:
    - name: hello-world
      image: busybox:stable
      command: ["echo"]
      args: ["Hello World!"]
```

## TaskRun
```yaml
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
  name: hello
spec:
  taskRef:
    name: hello
```

## Pipeline
```yaml
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
  name: hello
spec:
  tasks:
    - name: hello
      taskRef:
        name: hello
```

## PipelineRun
```yaml
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  generateName: hello-
spec:
  pipelineRef:
    name: hello
```

# 実践編
## git-clone
### Task
https://rheb.hatenablog.com/entry/2021/07/19/OpenShift_Pipelines_%E3%81%AE%E3%81%94%E7%B4%B9%E4%BB%8B%28Tekton_Pipelines%E7%B7%A8%29
> OpenShift Pipelinesではインストールの際にTekton Catalogの一部がClusterTask（クラスタ全体で共通利用可能なTask）として登録される

ため、ClusterTaskのgit-cloneはTaskRunやPipelineで利用可能。
https://github.com/tektoncd/catalog/blob/main/task/git-clone/0.9/git-clone.yaml

下記ではPipelineRunでServiceAccountを通じて、SecretのSSH秘密鍵を使って、GitリポジトリからSSHでgit cloneする例を示す。

:::note info
git-clone Taskの利用方法はこちらを参照。
https://hub.tekton.dev/tekton/task/git-clone
:::

### Pipeline
```yaml
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
  name: git-clone
spec:
  params:
    - name: url
      type: string
    - name: revision
      type: string
      default: main
  workspaces:
    - name: shared-workspace
  tasks:
    - name: git-clone
      taskRef:
        name: git-clone
        kind: ClusterTask
      params:
        - name: url
          value: "$(params.url)"
        - name: revision
          value: "$(params.revision)"
      workspaces:
        - name: output
          workspace: shared-workspace
```
### PipelineRun
:::note warn
https://hub.tekton.dev/tekton/task/git-clone にはServiceAccountでの例はないが、ServiceAccountでも実行可能。
:::
```yaml
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  generateName: git-clone-
spec:
  pipelineRef:
    name: git-clone
  podTemplate:
    securityContext:
      fsGroup: 65532
  params:
    - name: url
      value: git@<Gitリポジトリのドメイン名>:<Organization名>/<リポジトリ名>.git
  workspaces:
    - name: shared-workspace
      persistentVolumeClaim:
        claimName: shared-workspace
  serviceAccountName: git-sa
```
### Secret

:::note info
SSH鍵の作成方法は下記を参照
https://docs.github.com/ja/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent
:::
:::note warn
`tekton.dev/git-0: https://<Gitリポジトリのドメイン名>`にすると、sshでのgit cloneに失敗するので注意
https://tekton.dev/docs/pipelines/auth/#configuring-ssh-auth-authentication-for-git
:::
```yaml
apiVersion: v1
kind: Secret
metadata:
  name: git-auth-secret
  annotations:
    tekton.dev/git-0: <Gitリポジトリのドメイン名>
type: kubernetes.io/ssh-auth
data:
  ssh-privatekey: <base64エンコードしたssh秘密鍵>
```
### ServiceAccount
```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: git-sa
secrets:
  - name: git-auth-secret
```

# 応用編
## npm
### Pipeline
Angularのリポジトリをgit cloneした後、npm installを実行し、`npm run test:ci(ng test --no-watch --no-progress --browsers=ChromeHeadless)` と `npm run e2e(playwright test)` を実行する例を示す。

:::note info
Angularアプリは下記URLを参考に`ng new <project-name>`で作成したもの。
https://angular.dev/installation
:::

:::note warn
OpenShiftではSCCの制約により、原則、rootユーザーでのコンテナビルドができず、コンテナイメージの作成に時間がかかるため、依存ライブラリのインストールを避け、依存ライブラリがインストール済みのイメージを利用している。

`npm run test:ci` では Google Chromeに依存したテストがあるため、 `cypress/included` を、`npm run e2e` ではplaywrightに依存したテストがあるため、`mcr.microsoft.com/playwright:v1.49.1-noble`を利用している。
:::

```yaml
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
  name: npm
spec:
  params:
    - name: url
      type: string
    - name: revision
      type: string
      default: main
  workspaces:
    - name: shared-workspace
  tasks:
    - name: git-clone
      taskRef:
        name: git-clone
        kind: ClusterTask
      params:
        - name: url
          value: "$(params.url)"
        - name: revision
          value: "$(params.revision)"
      workspaces:
        - name: output
          workspace: shared-workspace
    - name: npm-test-install
      runAfter:
        - git-clone
      taskSpec:
        steps:
          - name: npm-test-install
            image: cypress/included
            workingDir: /workspace/shared-workspace
            script: |
              #!/bin/sh
              npm install
      workspaces:
        - name: shared-workspace
    - name: npm-test
      runAfter:
        - npm-test-install
      taskSpec:
        steps:
          - name: npm-test
            image: cypress/included
            workingDir: /workspace/shared-workspace
            script: |
              #!/bin/sh
              npm run test:ci
      workspaces:
        - name: shared-workspace
    - name: npm-e2e-install
      runAfter:
        - git-clone
      taskSpec:
        steps:
          - name: npm-e2e-install
            image: mcr.microsoft.com/playwright:v1.49.1-noble
            workingDir: /workspace/shared-workspace
            script: |
              #!/bin/sh
              npm install
              npx playwright install
      workspaces:
        - name: shared-workspace
    - name: npm-e2e
      runAfter:
        - npm-e2e-install
      taskSpec:
        steps:
          - name: e2e-test
            image: mcr.microsoft.com/playwright:v1.49.1-noble
            workingDir: /workspace/shared-workspace
            script: |
              #!/bin/sh
              npm run e2e
      workspaces:
        - name: shared-workspace
```

### PipelineRun
:::note warn
npmのイメージはroot前提になっているため、runAsUserで非rootを指定する。
:::
```yaml
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  generateName: npm-
spec:
  pipelineRef:
    name: npm
  podTemplate:
    securityContext:
      fsGroup: 65532
      runAsUser: 1000
      runAsGroup: 1000
  params:
    - name: url
      value: git@<Gitリポジトリのドメイン名>:<Organization名>/<Angularアプリのリポジトリ名>.git
  workspaces:
    - name: shared-workspace
      persistentVolumeClaim:
        claimName: shared-workspace
  serviceAccountName: git-sa

```