GitLab Agent for Kubernetesを使ってみる(GitLab Kubernetes Agent改め)

毎度、ググっても出てこない小ネタを取り扱っております。
本記事は個人的な見解であり、筆者の所属するいかなる団体にも関係ございません。

# 0. はじめに

## 0-1. GitLab Agent for Kubernetes(GitLab Kubernetes Agent改め)ってなに？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15176/67446622-f3dd-ce76-88f9-533ffd0f144d.png)

簡単に言うとGitLabとKubernetesを連携させる方法です。

## 0-2. 何で連携させるの？

GitLab CI/CDの時にKubernetesクラスターを取り扱うために連携させます。
CI/CDのジョブ内でkubectlを実行すると連携されたKubernetesクラスターにkubectlの実行を反映させることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15176/f53828f5-6da3-74ac-6908-7a83673c5df9.png)

## 0-3. 今までもできたよね？

はい、いままでもできました。

下記記事参照:
[GitLab Kubernetes接続\(オンプレ\) \- Qiita](https://qiita.com/ynott/items/f9509b68406389264faa)

しかし、kubeconfigファイルをGitLabサーバー側に保存する必要があり、それがセキュリティーリスクとなっていました。また、GitLabサーバー側からKubernetesクラスターへ接続する必要があり、KubernetesクラスターにグローバルIPが必要でインターネットに出ている必要がありました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15176/aadc189c-9966-dc01-078c-2041bf755c4d.png)

::: note info
注: GitLab RunnerとKubernetesクラスターが同じプライベートネットワークにある場合は、インターネットに出ている必要はありません。しかし、GitLabサーバーにkubeconfigが必要なのは同じです。
:::

## 0-4. どうなった？

GitLabへ接続するエージェントが開発されて、Kubernetesクラスターへインストールする方式に変わりました。
GitLab Runnerと同じ方法です。GitLabサーバーとagentkはWebSocketで接続します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15176/2dcb8b6f-490c-9271-7b77-089e7c0761d3.png)

これならば、
1. Kubernetesクラスターがインターネットに出ている必要はなく、グローバルIPも不要です。
1. kubeconfigをGitLabサーバー側に保存する必要がなくkubectlを実行する為のkubeconfigを変数に保存する必要がありません。
1. これによりセキュリティーリスクが下がります。

というメリットがあります。

GitLabRunnerとKubernetesクラスターが別々の場所にあっても問題ありません。
GitLabサーバーにだけ接続できるようにしておけば大丈夫です。

例えば、以下のような構成も可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15176/b09ec7e2-7a70-6bef-beb5-369987f96a17.png)


# 1. やってみる

## 1-1. GitLabプロジェクトを作成

普通にプロジェクトを作成するので割愛します。
CI/CDを有効にしてください。
GitLab Runnerはどこにあっても問題ありません。

## 1-2. GitLabプロジェクトのGitリポジトリにファイルを作成

GitLab Agent for Kubernetesのエージェント用のファイルを作ります。
作るファイル名は、`config.yaml`ですが、ファイルを作るパスに特徴があります。

`.gitlab/agents/`ディレクトリを作り、その下に`GitLab Agentの名前`のディレクトリを作り、
その下にconfig.yamlファイルを作ります。config.yamlの中身は空で構いません。
`GitLab Agentの名前`は何でもOKです。`aaa-bbb-ccc`とか好きな名前を付けましょう。

```
.gitlab/agents/<GitLab Agentの名前>/config.yaml
```

この時の`GitLab Agent`の名前はDNS label standard from RFC 1123に準拠してください。

- プロジェクトでユニークであること。
- 最大63文字まで。
- 小文字の英数字または-のみを使用。
- 英数字で始めます。
- 英数字で終了します。

## 1-3. GitLab Agentをプロジェクトから登録します。

「GitLabメニュー」＞「インフラ」＞「Kubernetes Clusters」を開いて、「Connect a cluster」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15176/126e1dd0-7c0e-62cd-3761-9260be7f406d.png)

「Select an agent....」をクリックすると1-2で作ったディレクトリの`GitLab Agentの名前`が表示されるので選択して「Register」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15176/dfd0acdb-f576-7739-e162-d26418f19cbb.png)

以下のような画面が表示されるので、`helm`のコマンドをコピっておきましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15176/823acac8-bce5-a010-805a-0c08e1a77c96.png)


# 2. Kubernetesクラスターを立てる

インターネットに出ていける環境で仮想マシンを動かしてシングルのK3Sをインストールしましょう。

## 2-1. 仮想マシンの用意

簡単にmultipassで用意します。

```bash
multipass launch 20.04 --name test.gitlabagentk
```

test.gitlabagentkにログインします。

```io
multipass shell test.gitlabagentk
```

## 2-2. k3supを使ってK3Sをインストール

シングルサーバーなので、k3supをダウンロードして、K3Sをインストールします。

詳細はこちらを参考にしてください。
k3supを使ってk3sをインストールする - Qiita
https://qiita.com/ynott/items/25df249040ceb7430c3f

```io
curl -sLS https://get.k3sup.dev | sh
sudo install k3sup /usr/local/bin/
```

K3Sをインストールします。

```
k3sup install --local --k3s-extra-args="--write-kubeconfig-mode 644"
```

K3Sの挙動を確認します。
```
export KUBECONFIG=./kubeconfig
kubectl config set-context default
kubectl get node -o wide
```

## 2-3. helmコマンドをインストール

helmコマンドもインストールしておきます。

```
sudo snap install helm --classic
helm 3.7.0 from Snapcrafters installed
```

# 3. GitLab Agent for Kubernetesをインストール

## 3-1. GitLab Agentを helmでインストール

1.3で出てきたhelmコマンドのコピーを貼り付けます。

```io
helm repo add gitlab https://charts.gitlab.io
helm repo update
helm upgrade --install teXXXXXXXXXXXXXXXXXXXXXXXXer gitlab/gitlab-agent \
    --namespace gitlab-agent \
    --create-namespace \
    --set image.tag=v15.1.0 \
    --set config.token=AyamK7XXXXXXXXXXXXXXXXXXXXXPg \
    --set config.kasAddress=wss://kas.gitlab.com
```

## 3-2. GitLab UIを確認

「GitLabメニュー」＞「インフラ」＞「Kubernetes Clusters」に接続したGitLab Agentが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15176/ceb067b7-78d9-4499-7990-9b32fe4830c1.png)

## 3-3. kubectlでgitlab-agentの実行状態を確認

以下のコマンドでgitlab-agentが実行されているか確認します。

```
kubectl get all -n gitlab-agent
```

問題なさそうです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15176/23b6ff60-2d24-d943-b30e-c22c11a90436.png)


# 4. Kubernetesをテストしてみる

.gitlab-ci.yamlのジョブからKubernetesクラスターへ接続できるか試してみます。

## 4-1. .gitlab-ci.ymlファイルを作成

以下のような内容で.gitlab-ci.ymlファイルをGitリポジトリ直下に作成します。
重要なポイントは、`kubectl config use-context`です。
kubeconfig内のcontextsを指定しますが、このkubeconfigはKubernetesクラスターを作ったときに出てくるkubeconfigではなくて、GitLab Agent用にCI/CDジョブ実行時に自動的に生成されるものです。
`<グループ名>/<プロジェクト名>:<GitLab Agent名>`の指定方法が分からない場合は、`kubectl config get-contexts`で出てきたName部分を指定すれば問題ありません。kubectl config use-contextがないと動きませんでした(defaultじゃないので)

```yaml:.gitlab-ci.yml
deploy:
  stage: deploy
  image:
    name: bitnami/kubectl:latest
    entrypoint: ['']
  script:
    - kubectl config get-contexts
    - kubectl config use-context <グループ名>/<プロジェクト名>:<GitLab Agent名>
    - kubectl get pods -A
```

## 4-2. ジョブ実行状態を確認

以下のようにPodのリストが出力されれば問題ありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15176/5d076810-a236-a2df-251e-bc784d62f727.png)

# 5. なぜこんなことができるの？

ジョブ実行時にkubeconfigが自動的に生成されて、Runnerのジョブ上で読み取れるようになるからkubectlを実行してKubernetesクラスターを操作できるのですが、RunnerはKubernetesクラスターの場所を知らないのにkubectlが実行できるのは不思議です。

## 5-1. kubeconfigを見てみる

先ほどの.gitlab-ci.ymlファイルに以下を1行追加してみます。

`- kubectl config view --raw`

以下のようになります。

```yaml:.gitlab-ci.yml
deploy:
  stage: deploy
  image:
    name: bitnami/kubectl:latest
    entrypoint: ['']
  script:
    - kubectl config get-contexts
    - kubectl config use-context <グループ名>/<プロジェクト名>:<GitLab Agent名>
    - kubectl get pods -A
    - kubectl config view --raw
```

追加で出力された結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15176/5dcd3d42-ebb1-181f-6e2f-a899d7ae9133.png)

clusters.cluster.serverは通常KubernetesクラスターのAPI接続Endpointですが、gitlabサーバーを指しています。
GitLabサーバーがProxyになっていて、Kubernetesクラスターへ接続しています。

以下の図は、[Ultimate GitOps: Deploy Secure Microservices to AWS EKS with the GitLab Agent :: GitLab for EKS](https://gitlab-for-eks.awsworkshop.io/)からの引用ですが、一番左の緑のRunnerの枠から真ん中のオレンジのGitLabを経由して右側の水色のKubernetesクラスターへ接続しているのが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15176/086fe3a8-d2dc-1526-6a5e-637e2a0575f3.png)
[GitLab Agent Connections and Flows](https://gitlab-for-eks.awsworkshop.io/070_architecture_patterns/gitlab-agent-connections.html) より引用

GitLab CI/CD内のジョブがRunnerで実行されているときに自動的にkubeconfigが設定されて、接続先はGitLabのKASです。
KASはGitLab AgentをインストールしたKubernetesクラスターへトンネリングを提供して、kubectlコマンドを実行してくれます。

# 7. どう使う？

ジョブ内でkubectlを実行できるので、KubernetesのマニフェストファイルをGitリポジトリ内に置いておいて、kubectl apply -f ./manifest.yamlすればいいでしょう。

```yaml:.gitlab-ci.yml
deploy:
  stage: deploy
  image:
    name: bitnami/kubectl:latest
    entrypoint: ['']
  script:
    - kubectl config use-context <グループ名>/<プロジェクト名>:<GitLab Agent名>
    - kubectl apply -f ./manifest.yaml
```

imageにkustomizeを入れたり、helmを入れれば同様にKubernetesクラスターに適用できます。

# 6. まとめ

- GitLab Agent for Kubernetesは、Kubernetesクラスターへ安全に接続するための方法です。
- GitLab Runnerから安全にKubernetesクラスターへ接続することができます。

# 7. 参考資料

Installing the agent for Kubernetes \| GitLab
https://docs.gitlab.com/ee/user/clusters/agent/install/index.html

Ultimate GitOps: Deploy Secure Microservices to AWS EKS with the GitLab Agent :: GitLab for EKS
https://gitlab-for-eks.awsworkshop.io/

How to use ‘GitLab Kubernetes Agent Working Examples for Training and Demos’ 2022-06-01
https://youtu.be/RGs65Zi-Tno