【GitOps】〜実践編①〜 werfでGitOpsを実装する

## 0. 前提
- GitOpsに関する基本的な知識があることが望ましい。（もし無い場合は拙著、[GitOps～基礎編～ GitOpsとは何か？](https://qiita.com/gararu/items/725aa2041a004e66e211)が参考になるかもしれません。）
- 利用した環境情報
    - minikube v1.23.2
    - Ubuntu 18.04.6
    - kubectl v1.22.2

## 1. [werf](https://werf.io/)とは
> `Go`で書かれたOSSのCLIツール。アプリケーションのデリバリをシンプルにし、スピードアップするために開発された。werfを利用するには、アプリのビルド方法とk8sへのデプロイ方法を記載した設定ファイル(werf.yaml)を記述し、Gitリポジトリに保管する必要がある。これは、「a single source of truth」つまり今日でいうGitOpsに当たる。参考[werfのgithubより](https://github.com/werf/werf)

## 2.werfの使い方（この内容は実用上不要なので読み飛ばしてもらって構いません。）
## 2.1 最終的な理想の状態を設定する

- 1 GitのリポジトリにDockerfileを配置する

- 2 `werf.yaml` と呼ばれるwerfの設定ファイルを配置する
werf.yamlでは`project`というパラメータ（projectの名前を保存する役割を持つ）が非常に重要。werfの`converge`プロセス(後述)で利用するため。このパラメータを後で変更すると、アプリにダウンタイムが発生し、再デプロイされることになる。
- 3 アプリをデプロイするためのhelmファイルを配置する
`Helm`のテンプレートに記載する`werf_image`は特殊な役割があり、ビルドされたイメージのフルネームを生成する機能がある。この機能は`werf.yaml`で定義されたイメージに対応する名前のパラメータを持つ。

- 4 `git commit` する

## 2.2 `converge`する
- 1 現在のgitのcommit状態に基づいて、生成するイメージの名前をwerfが計算する
- 2 コンテナレジストリで利用可能なイメージを読み込む
- 3 コンテナレジストリにあるイメージと、git commitされたイメージを比較する
- 4 git commitされたイメージがコンテナレジストリに無ければ、ビルドしてコンテナレジストリにpushする
- 5 現在のgit commit の状態に基づいて、「ターゲットとなるk8sクラスタの**Git**の設定」①を読み込む
- 6 「ターゲットとなるk8sクラスタの状態」②を読み込む
- 7 ①と②を比較し、必要があればkubectl applyを実行する
- 8 全てのリソースがReadyであることを確認し、エラーがあれば迅速に報告する

## 3. werfの動作を確認する
[Quick Start](https://werf.io/documentation/v1.2/quickstart.html)の内容を試す。

### 3.1 `trdl`コマンドをインストール

`trdl`は`werf`のインストールとアップデートを管理するツール

```shell
curl -sSLO "https://tuf.trdl.dev/targets/releases/0.3.2/linux-amd64/bin/trdl" -O "https://tuf.trdl.dev/targets/signatures/0.3.2/linux-amd64/bin/trdl.sig"
curl -sSL https://trdl.dev/trdl-client.asc | gpg --import
gpg --verify trdl.sig trdl
# install -D trdl ~/bin/trdl
sudo install -D trdl /usr/local/bin/trdl
```

### 3.2 `werf`コマンドをインストール

```shell
trdl add werf https://tuf.werf.io 1 b7ff6bcbe598e072a86d595a3621924c8612c7e6dc6a82e919abe89707d7e3f468e616b5635630680dd1e98fc362ae5051728406700e6274c5ed1ad92bea52a2
. $(trdl use werf 1.2 stable)
werf version
```

### 3.3 minikubeにローカルレジストリを立ち上げる

```shell
minikube start --driver=docker --insecure-registry registry.example.com:80

alias kubectl="minikube kubectl --"

echo 'alias kubectl="minikube kubectl --"' >> ~/.bash_aliases

minikube addons enable ingress

minikube addons enable registry

kubectl apply -f - << EOF
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: registry
  namespace: kube-system
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "0"
spec:
  rules:
  - host: registry.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: registry
            port:
              number: 80
EOF


# /etc/docker/daemon.json に下記の内容を書き込む 

{
   "insecure-registries": ["registry.example.com:80"]
}


sudo systemctl restart docker

minikube start --driver=docker --insecure-registry registry.example.com:80


export WERF_INSECURE_REGISTRY=1

echo export WERF_INSECURE_REGISTRY=1 | tee -a ~/.bashrc

echo "$(minikube ip)"

echo "$(minikube ip) vote.quickstart-application.example.com result.quickstart-application.example.com registry.example.com" | sudo tee -a /etc/hosts


minikube ssh -- "echo $(minikube ip) registry.example.com | sudo tee -a /etc/hosts"

```


### 3.3 サンプルアプリをデプロイする
- Gitから必要な資材をクローンする

```shell
git clone https://github.com/werf/quickstart-application
cd quickstart-application
```

```shell
werf converge --repo registry.example.com:80/quickstart-application
```

### 3.4 サンプルアプリを確認する

- http://vote.quickstart-application.example.com
- http://result.quickstart-application.example.com
にアクセスするとデモアプリ（多数決）が起動していることを確認できる

筆者はCLIから確認するため`lynx`をインストール
```shell
sudo apt-get install lynx
```

## 4 `werf`でGitOpsを実装する

**全体像**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475824/16707245-740e-a615-a6e9-29dd4661b74d.png)


では早速実装してみる。

- GitLab Runnerをインストールし、runnerとして登録する。`tag`には`werf`を、`Executor`は`shell`を選択する。

```shell
sudo curl -L --output /usr/local/bin/gitlab-runner "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64"

sudo chmod +x /usr/local/bin/gitlab-runner

sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash

sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner

sudo gitlab-runner start

systemctl status gitlab-runner
```

- `gitlab-runner`を`docker`groupに追加する

```shell
sudo usermod -aG docker gitlab-runner
```


- 先程の手順に従い`werf`をインストールする。


- `kubectl`をインストールし、kubeconfig を`gitlab-runner`userのホームディレクトリに配置する。

```shell
sudo mkdir -p /home/gitlab-runner/.kube && 
sudo cp -i ~/.kube/config /home/gitlab-runner/.kube/config && 
sudo chown -R gitlab-runner:gitlab-runner /home/gitlab-runner/.kube
```

- `.gitlab-ci.yml`を記載する

```shell:.gitlab-ci.yml
stages:
  - build

before_script:
  - trdl add werf https://tuf.werf.io 1 b7ff6bcbe598e072a86d595a3621924c8612c7e6dc6a82e919abe89707d7e3f468e616b5635630680dd1e98fc362ae5051728406700e6274c5ed1ad92bea52a2
  - type trdl && . $(trdl use werf 1.2 stable)
  - type werf && source $(werf ci-env gitlab --as-file)

Build:
  stage: build
  script:
    - git clone https://github.com/werf/quickstart-application
    - cd quickstart-application
    - . $(werf ci-env gitlab --as-file)
    - export WERF_INSECURE_REGISTRY=1
    - env
    - nslookup registry.example.com
    - werf converge --skip-tls-verify-registry=true --repo registry.example.com:80/quickstart-application
  tags:
    - werf
```

- 該当するGitLabのレポジトリにPushする。
CI/CDがこのような感じで動作する。

![GitLab CI/CD](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475824/4e9f3e7f-c631-b9eb-2173-7232e5962e81.png)

## 5. まとめ
今回は`Werf`を用いたGitOpsの実装方法を紹介しました。
今後もGitOps関連の記事を投稿しますので、読んでみて下さい。