K8s上にTLS対応のGitLab+GitLab Runner環境を構築

GitOps環境が欲しい時にインターネット上のGitHubが使えれば問題ないが、社外に会社のリソースを出すな等言われる場合もあり、独自に立てたGitLabを使った方が望ましい場合がある。
そういう時用にGitLabを立てた時の構築手順メモ。
ゴールは以下。
- GitLabが使えるようになっている
- GitLab Runnerが使えるようになっている
- 通信はTLS化
- Runnerの動作確認が出来る


## 前提
構築開始時に以下があるものとする。
- Kubernetes
- Helmコマンド
- 検証用ドメイン
  
ドメインについてはGitLabのURLにドメインを使っており、Let's Encryptを使ってTLS化する際、cert-managerがHTTP-01チャレンジによってドメインを検証する。
なのでHTTP-01チャレンジに対応したドメインを利用する必要がある（nip.ioとかだと多分不可）


## GitLab＆Runner構築
GitLab構築時にcert-managerやGitLab Runnerも合わせて導入できるが、cert-managerは既に入っていることが多く、GitLab RunnerはGitLab起動後のTokenを必要とするので分けて構築した。

まずcert-managerをインストールする。
```sh
helm repo add jetstack https://charts.jetstack.io --force-update
helm repo update
helm install \
  cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --set installCRDs=true
```

GitLabをインストールする。
```sh
MAIL=xxxx@gmail.com
MYDOMAIN='eks.xxxx.com'
helm upgrade -i gitlab gitlab/gitlab -n gitlab --create-namespace \
  --set certmanager.install=false \
  --set certmanager-issuer.email=$MAIL \
  --set global.hosts.domain=$MYDOMAIN \
  --set global.ingress.annotations."kubernetes\.io/tls-acme"=true \
  --set prometheus.install=false \
  --set gitlab-runner.install=false
```
`MAIL`、`MYDOMAIN`は自身のものを設定する。
オプションに関しては、インストールの際にcert-manager経由でがHTTP-01チャレンジを行うためのIngressのAnnotationを指定している。
`prometheus.install=false`に関してはPrometheusは別で立てることが多いのでここではインストール対象から除外した。

GitLab起動後、初期パスワードを取得する。
```sh
kubectl get secret -n gitlab gitlab-gitlab-initial-root-password -o jsonpath={.data.password} | base64 -d
```
アクセス先を取得する。`Ingress`の`gitlab-webservice-default`がWebUIのアクセス先となる。
```sh
$ kubectl get ing -n gitlab
NAME                        CLASS          HOSTS                   ADDRESS                            PORTS     AGE
gitlab-kas                  gitlab-nginx   kas.eks.xxxx.com        xxxx.us-east-1.elb.amazonaws.com   80, 443   11d
gitlab-minio                gitlab-nginx   minio.eks.xxxx.com      xxxx.us-east-1.elb.amazonaws.com   80, 443   11d
gitlab-registry             gitlab-nginx   registry.eks.xxxx.com   xxxx.us-east-1.elb.amazonaws.com   80, 443   11d
gitlab-webservice-default   gitlab-nginx   gitlab.eks.xxxx.com     xxxx.us-east-1.elb.amazonaws.com   80, 443   11d
```
上記のHOSTSをブラウザで開き、IDを`root`、取得したパスワードでログインできる。
ブラウザからTLSを確認すると、問題なく利用できていることも確認できる。

![20240506155742.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/50342b7e-6ba1-e331-cb4e-e72156c7621c.png)

次にGitLab Runnerを構築する。
なお、Runnerには3つのタイプが存在する。（参考：[Manage runners](https://docs.gitlab.com/ee/ci/runners/runners_scope.html)）
- **Instance Runner**（旧Shared Runner）：全プロジェクトで使えるRunner
- **Group Runner**：グループ内で自由に使えるRunner
- **Project Runner**：特定のProjectのみ使えるRunner

ここではInstance Runnerで作成する。
GitLabのUIにアクセスし、`Admin Area`から左サイドバーの`CI/CD`->`Runners`を選択し、右上の`New instance runner`をクリックする。
Platformは`Linux`、`Tags`は好きなタグ（ここでは`shared`とした）を入力して`Create runner`でGitLab側にRunnerを作成する。
![20240419183333.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/a3747eb2-a90b-26fa-df69-ddefa4bb3f8c.png)
次の画面で`runner authentication token`が表示されるのでこれを控えておく。
![20240419183506.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/726c346f-4b9f-c3fb-eaa5-4b349f74fc83.png)

Kubernetes側にGitLab Runnerを展開する。
```sh
GITLAB="https://gitlab.$MYDOMAIN"
RUNNER_TOKEN="glrt-xxxxx"
helm upgrade -i gitlab-runner gitlab/gitlab-runner -n gitlab \
  --set gitlabUrl=$GITLAB \
  --set runnerToken="$RUNNER_TOKEN" \
  --set certsSecretName=gitlab-gitlab-tls \
  --set rbac.create=true
```
問題なければGitLab UI上から`Online`になっていることが確認できる。
![20240419185133.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/00bd7e0e-a114-2fc5-204d-14be1bdb2ba9.png)


## Runnerの動作確認
適当なリポジトリを作成する。
`+`から`New project/repository`を選択する。
![20240506141208.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/1c1e854d-23aa-7917-58e4-a1d4a4b64e7a.png)
`Create blank project`を選択して適当に埋める。
![20240506142023.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/43f5bed3-97e2-40ed-becd-497cfeb226de.png)
RunnerはInstance Runnerで作成したため、リポジトリを作成した時点でRunnerは利用可能となっている。
作成したリポジトリから`Settings`->`CI/CD`->`Runners`で現在利用可能なRunnerが確認できる。
![20240506144104.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/8affeb46-4155-c453-04e3-d2a580e750d0.png)

このRunnerを使ってJobをキックしてみる。
作成したリポジトリをCloneする。
```sh
git clone https://gitlab.${MYDOMAIN}/root/gitlabrunner-test.git
```
Cloneしたディレクトリに移動し、動作確認用の`.gitlab-ci.yml`を作成する。
```yaml
cd gitlabrunner-test/
cat <<EOF > ./.gitlab-ci.yml
stages:
- echo

echo:
  image: alpine
  stage: echo
  tags:
  - shared
  script:
  - |
    echo "runner test"
EOF
```
`tags`にInstance Runnerと同じTagを指定することで、Instance Runnerを指定してJobを実行させている。
Pushする。
```sh
git add .gitlab-ci.yml
git commit -m "add .gitlab-ci.yml"
git push origin main
```
Pushすると早速Runnerが`.gitlab-ci.yml`を読み込んでJobを実行する。
実行したJobは`Build`->`Jobs`->`ジョブ名`から確認できる。
![20240506152156.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/303a7690-e1eb-7d00-2464-9c77c4957273.png)


ということで、GitLabでRunnerを動かすところまでを確認できた。
なお、Runnerインストール時に`--set rbac.create=true`をつけていないと以下のエラーが出ることがある。
```sh
ERROR: Error cleaning up secrets: resource name may not be empty
ERROR: Job failed (system failure): prepare environment: setting up credentials: secrets is forbidden: User "system:serviceaccount:gitlab:default" cannot create resource "secrets" in API group "" in the namespace "gitlab". Check https://docs.gitlab.com/runner/shells/index.html#shell-profile-loading for more information
```
Namespace `gitlab`内の`default`のService Accountの権限を強化すれば通ると思う。