GKEでArgoCDを使ってGitOpsしてみた

# 概要

- GitOpsを知らない人は、まずこちらを参照
        - [weaveworks GitOps](https://www.weave.works/technologies/gitops/)
- GitOpsを実現できる有名所なツールとして`Agro CD`、`Flux`、`Jenkins X`、の3種類が有る。今回は`Argo CD`を使ってみる
    - Fluxは前回使ってみた
        - [Fluxを使ってGitOpsハンズオンしてみた](https://qiita.com/ttr_tkmkb/items/e923e3aa75c5c5bd46b4)
- Argo CDハンズオン自体はN番煎じですが、勉強も兼ねてやってみます
    - [EKSでArgo CDのチュートリアルを試してみた](https://dev.classmethod.jp/cloud/aws/eks-argocd-getting-started/)
    - [Argo CDによってGKEでGitOpsをする](https://www.1915keke.com/entry/2018/12/15/034843)


# Argo CDハンズオン

- 以下を読みながら進めていく
    - [Argo CD - Declarative GitOps CD for Kubernetes Getting Started](https://github.com/argoproj/argo-cd/blob/master/docs/getting_started.md)

## 事前準備

### Argo CD CLIのインストール
- Windows版のバイナリがないので、WindowsからのCLIでの操作は対応してなさそう
    - https://github.com/argoproj/argo-cd/releases/tag/v1.0.1
- 今回はGUIだけで試してみる。。

### Kubernetesクラスタの構築

- 以下の記事の通りに進めて、GKEクラスタを構築
    - [なるべくCLIでGKEクラスタを作成してみる](https://qiita.com/ttr_tkmkb/items/26328fbbf5f17b920046)

```bash
$ gcloud container clusters create argocd-handson
$ gcloud container clusters list
NAME            LOCATION           MASTER_VERSION  MASTER_IP     MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
argocd-handson  asia-northeast1-a  1.12.8-gke.6    34.85.55.205  n1-standard-1  1.12.8-gke.6  3         RUNNING
```

### ClusterRoleBindingを作る

**※ここはGKE固有の準備部分**

公式ドキュメントより
> GKEでは、アカウントに新しいクラスタロールを作成する権限を付与する必要があります。

ArgoCDでリポジトリ毎にNamespaceの権限をよしなにやってくれるために必要で、GKEでは権限が制限されているのかと推測。

```bash
$ kubectl create clusterrolebinding YOURNAME-cluster-admin-binding --clusterrole=cluster-admin --user=YOUREMAIL@gmail.com
clusterrolebinding.rbac.authorization.k8s.io/YOURNAME-cluster-admin-binding created
```

YOURNAMEは何でも良さそうだったので、そのまま。
YOUREMAILにはGCPを登録したGmailアカウントを設定したけど、何でもよかったのかな？。

ClusterRoleBindingについては[こちらの記事](https://qiita.com/sheepland/items/67a5bb9b19d8686f389d)が分かりやすかった。


## Argo CDのインストール
### Namespaceの作成

```bash
$ kubectl create namespace argocd
namespace/argocd created
```

### Argocdのデプロイ

以下のコマンドでNon-HA構成でインストールできる。

```bash
$ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

```

HA構成は以下でインストール。

```
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v1.0.1/manifests/ha/install.yaml
```

バグを踏むかもしれないけど、折角なのでHA構成でインストールしてみる。

```bash
$ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v1.0.1/manifests/ha/install.yaml
customresourcedefinition.apiextensions.k8s.io/applications.argoproj.io created
customresourcedefinition.apiextensions.k8s.io/appprojects.argoproj.io created
serviceaccount/argocd-application-controller created
serviceaccount/argocd-dex-server created
serviceaccount/argocd-redis-ha created
serviceaccount/argocd-server created
role.rbac.authorization.k8s.io/argocd-application-controller created
role.rbac.authorization.k8s.io/argocd-dex-server created
role.rbac.authorization.k8s.io/argocd-redis-ha created
role.rbac.authorization.k8s.io/argocd-server created
clusterrole.rbac.authorization.k8s.io/argocd-application-controller created
clusterrole.rbac.authorization.k8s.io/argocd-server created
rolebinding.rbac.authorization.k8s.io/argocd-application-controller created
rolebinding.rbac.authorization.k8s.io/argocd-dex-server created
rolebinding.rbac.authorization.k8s.io/argocd-redis-ha created
rolebinding.rbac.authorization.k8s.io/argocd-server created
clusterrolebinding.rbac.authorization.k8s.io/argocd-application-controller created
clusterrolebinding.rbac.authorization.k8s.io/argocd-server created
configmap/argocd-cm created
configmap/argocd-rbac-cm created
configmap/argocd-redis-ha-configmap created
configmap/argocd-redis-ha-probes created
secret/argocd-secret created
service/argocd-dex-server created
service/argocd-metrics created
service/argocd-redis-ha-announce-0 created
service/argocd-redis-ha-announce-1 created
service/argocd-redis-ha-announce-2 created
service/argocd-redis-ha created
service/argocd-repo-server created
service/argocd-server-metrics created
service/argocd-server created
deployment.apps/argocd-application-controller created
deployment.apps/argocd-dex-server created
deployment.apps/argocd-repo-server created
deployment.apps/argocd-server created
statefulset.apps/argocd-redis-ha-server created
```

インストールに問題無ければ、以下のようなserviceとdeploymentが見える。
HA構成にするためにメモリデータストアのredisを使っている様子。

```
$ kubectl get service -n argocd
NAME                         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)              AGE
argocd-dex-server            ClusterIP   10.59.250.4     <none>        5556/TCP,5557/TCP    119s
argocd-metrics               ClusterIP   10.59.245.87    <none>        8082/TCP             119s
argocd-redis-ha              ClusterIP   None            <none>        6379/TCP,26379/TCP   119s
argocd-redis-ha-announce-0   ClusterIP   10.59.245.195   <none>        6379/TCP,26379/TCP   119s
argocd-redis-ha-announce-1   ClusterIP   10.59.255.114   <none>        6379/TCP,26379/TCP   119s
argocd-redis-ha-announce-2   ClusterIP   10.59.248.240   <none>        6379/TCP,26379/TCP   119s
argocd-repo-server           ClusterIP   10.59.249.117   <none>        8081/TCP,8084/TCP    119s
argocd-server                ClusterIP   10.59.245.104   <none>        80/TCP,443/TCP       119s
argocd-server-metrics        ClusterIP   10.59.243.126   <none>        8083/TCP             119s

$ kubectl get deploy -n argocd
NAME                            DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
argocd-application-controller   1         1         1            1           4m28s
argocd-dex-server               1         1         1            1           4m28s
argocd-repo-server              2         2         2            2           4m28s
argocd-server                   2         2         2            2           4m27s
```

### Argo CDにアクセスできるようにする

公式ドキュメントでは、以下の方法かIngressを使うように言っている。

```bash
#ServiceのtypeをLoad Balancerにする方法
$ kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'

#Port Forwardingする方法
$ kubectl port-forward svc/argocd-server -n argocd 8080:443
```

GKEなので、typeをLoadBalancerにするとGCPのネットワークロードバランサーが作成されるはず。
手軽にやるならPort Fowradingだと思うけど、ネットワークロードバランサーを使ってみる。

```
$ kubectl get service argocd-server -n argocd
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
argocd-server   ClusterIP   10.59.245.104   <none>        80/TCP,443/TCP   9m43s

$ kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'

$ kubectl get service argocd-server -n argocd
NAME            TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)                      AGE
argocd-server   LoadBalancer   10.59.245.104   34.85.52.106   80:31804/TCP,443:30731/TCP   16m
```

`34.85.52.106`にアクセス

![Cut2019_0608_0957_10.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411298/c70c724d-eea7-771e-009e-8743710e6c44.jpeg)

ログイン画面が表示された。

### ログインIDとパスワードを取得

管理ユーザの初期パスワードはArgoCD APIサーバのpod名になっているので、取得する。

```
$ kubectl get pods -n argocd -l app.kubernetes.io/name=argocd-server -o name | cut -d'/' -f 2
argocd-server-569c655c64-c7qzr
argocd-server-569c655c64-fld99
```

HA構成にしているためpodが2つでてきてしまった。
とりあえず、`ID:admin`、`PW:pod名`でログインしてみる。

![Cut2019_0608_1003_43.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411298/7672cb4c-60f3-a19e-e2d5-ff6f9859d722.jpeg)

2つ目のpod名でログインできた。

## ArgoCDでGitOpsハンズオン

GUIでポチポチしながらApplicationを作成

![Cut2019_0608_1059_27.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411298/1281a936-f5f5-6988-38e8-e7a1431e0249.jpeg)
![Cut2019_0608_1104_12.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411298/7c831bc7-d6a7-b291-cb22-b045e67c2837.jpeg)


設定をYAMLで表示・変更もできたので、今回設定した情報を記載
Namespaceに`handson`を指定したが、クラスタ上には存在しない。自動で作られるか挙動を確かめる。

```yaml
apiVersion: argoproj.io/v1alpha1
metadata:
  name: handson
spec:
  destination:
    namespace: handson
    server: 'https://kubernetes.default.svc'
  source:
    path: /
    repoURL: 'https://github.com/ssbtn/ArgoCD-handson.git'
    targetRevision: master
    directory:
      recurse: true
  project: default
  syncPolicy:
    automated:
      prune: true
```
`Create`してみたがエラー。

> Failed sync attempt to c5aac260df1f66465a2ebc03042c9a049809de6b: one or more objects failed to apply

![Cut2019_0608_1104_12.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411298/6e74d0ad-e012-6d24-e026-78ffd31a9d37.jpeg)


> Error from server (NotFound): namespaces "handson" not found

![Cut2019_0608_1104_55.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411298/70f3b80e-8e9c-73ea-cd1f-8e6312d3c1f5.jpeg)


やっぱり、事前にNamespaceは作る必要が有る。

そして、エラーログを見るUIも含めて、欲しい情報が直観的に取得できて素晴らしい。

先週Fluxを使ったけど、GUIが無いのでリソースの作成に失敗した場合や、同期の追跡で一々コマンドを叩く必要があった。（Fluxを少し使っただけなので、よりよい見方が有るのかもしれないが。）
例えば、K8s初心者な人も使うことを想定するとArgo CDのこのUIは欲しいなと思った。

Namespaceの作成もGitで管理したいので、クラスタ管理者向けのリポジトリも運用を考えると作らないと。

長くなったけど、作成。

```
$ kubectl create namespace handson
namespace/handson created
```

設定次第なのかもしれないけど、
エラーでデプロイが失敗した場合は、待ってても再デプロイしてくれないみたい。10分ぐらい待った。
手動で`SYNC`をクリックしてみる。

![Cut2019_0608_1122_49.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411298/e206e363-2552-e686-b7cf-5aaa0cd495de.jpeg)

同期された。めちゃくちゃ分かりやすい。K8s初学者にリソースがどういう関連なのかを理解する助けにもなりそう。

ポイントとしては、
[deploymentやserviceでnamespaceを指定していなかった](https://github.com/ssbtn/ArgoCD-handson/blob/master/deployment/deploy-nginx.ym)けど、ArgoCDのアプリケーション作成時に選んだnamespace配下にリソースが作られているところ。
namespaceを指定するとどうなるのか試してみる。

## 設定したnamespace外へのデプロイ
### namespaceを作成
新規にnamespaceを用意。
さっきはkubectlで作ったけど、ymlで書いて、GitOpsしてみる。

https://github.com/ssbtn/ArgoCD-handson/commit/d5dbe3df29fb1f36d76fe9432b82fa9babf0cabc

### deploymentを書く
新規に作成したnamespaceにデプロイするように記述してpush

https://github.com/ssbtn/ArgoCD-handson/commit/cc63bbe92a367df1cef0333c22d516d001845494

### オブジェクトの確認
namespaceも作成できたし、Applicationで指定したnamespace外にもデプロイできた。

![Cut2019_0608_1143_08.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411298/4b257fd3-5e29-0e4b-b668-d08c153b85ef.jpeg)


## 作成したオブジェクトの削除

Fluxを使った時に、リポジトリ上からmanifestを削除しただけだと、クラスタ上にオブジェクトが残ってしまった。ArgoCDでも同様の事象が発生するか確認する。
本来であれば、追跡してくれることを期待したい。

リポジトリ上から削除
https://github.com/ssbtn/ArgoCD-handson/commit/3c58a2eee7790d984d9494bfebb00657ca75b38d

GUIではdeploymentが削除されたため、同期できていないと警告。

![Cut2019_0608_1155_22.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411298/b9e5c597-27af-74ea-6bc1-c4e202f53397.jpeg)


ちゃんとクラスタ上には存在。

```
$ kubectl get deployment -n handson2
NAME    DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx   5         5         5            5           10m
```

GUI上から同期されていないdeploymentを削除できるので、やってみる

![Cut2019_0608_1156_33.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411298/22f51984-6cec-8c1e-e0b8-98f95090ddbc.jpeg)


削除されて、警告も消えた。
この時点で、個人的にFluxよりも確実に使いやすい。

## ロールバック
GUIで`HISTORY AND ROLLBACK`ボタンが有るのでやってみる。
deploymentを削除する前の状態にロールバック。

![Cut2019_0608_1200_31.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411298/05afd741-911d-e3f6-93ff-66151c42c2bb.jpeg)


> Unable to rollback application: rollback cannot be initiated when auto-sync is enabled

自動同期が有効だとロールバックできないとエラー。

自動同期を無効化してロールバックした。
（無効化するスクショ取り忘れた。GUIで簡単に無効化できる。）

![Cut2019_0608_1204_09.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411298/bea5e107-f044-ce10-5968-9ebc04427b31.jpeg)

ロールバックしてくれた。
そして、deploymentに`×`がついているので、最新のmasterの状態と比較もしてくれている。

## namespaceの削除からの復旧

無効化した、自動同期設定は有効化に戻した。

うっかりオペレーションミスでnamespaceを削除した場合を考えて、やってみる。

```
$ kubectl delete ns handson handson2
namespace "handson" deleted
```

GUI上からリソースが無くなった。
![Cut2019_0608_1206_41.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411298/942a4c1f-87b1-88c6-54fb-9b79e02f9ea5.jpeg)


同期走ってGitの状態に戻された。良いですね。
![Cut2019_0608_1208_52.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411298/19ccd71b-2619-7d8c-9178-96b861a974c2.jpeg)


## 所感

好みも有るけど、Fluxよりも使いやすく、運用向きだと感じた。

Fluxだと1つのプロセスで1つのGitリポジトリしか管理できないので、複数のリポジトリを管理するにはFluxを複数起動する必要が有る。
ArgoCDだとアプリケーション単位でリポジトリを選べるので1つのプロセスで複数リポジトリも対応できて、管理がしやすそう。

Namespaceとか誰でもガシガシ作られると問題(?)なので、Applicationは指定したNamespace以下の権限しか持てないような権限設定ができるかとかも今後調べたい。

後はHelm、Kustomizeでのデプロイ方法も試したいな。