GitOps on OpenShift 入門

本記事は、[赤帽エンジニア Advent Calendar 2019](https://qiita.com/advent-calendar/2019/rh_engineers) の16日目です。

# はじめに
本記事では、OpenShift 上で GitOps が実現できることを紹介するため、[ArgoCD](https://argoproj.github.io/argo-cd/) を使って簡単な GitOps を実践してみます。


# GitOps とは
GitOps とは、Git を宣言的なインフラとアプリケーションの "Single Source of Truth" として、Kubernetes クラスタを構成管理するためのプラクティスです。

アプリケーションのソースコードを Git で管理するのと同様に、Pull Request などのアプリケーション開発で一般的に利用されているプラクティスを、Kubernetes のマニフェストの管理にも適用することができます。

CNCF (Cloud Native Computing Foundation) の Sandbox プロジェクトとしてホストされている [Flux](https://fluxcd.io/) の開発を推進している Weaveworks 社は、GitOps の基本原則として以下の4つを紹介しています。

* システム全体が宣言的に記述されていること (The entire system described declaratively)
* 標準的な状態が Git でバージョン管理されていること (The canonical desired system state versioned in Git)
* 承認された変更をシステムに自動的に適用できること (Approved changes can be automatically applied to the system)
* 正確性の担保と変更を通知できること (Software agents to ensure correctness and alert on divergence)


# ArgoCD とは
ArgoCD は、Kubernetes のマニフェストの構成管理に利用され、Continuous Delivery (継続的デリバリー) に特化したツールです。前述の Flux との違いとしては、Flux が1つのプロセスで1つの Git リポジトリを管理するのに対し、ArgoCD では1つのプロセスで複数の Git リポジトリを管理することができます。

ArgoCD のアーキテクチャ図は以下の通りです。

![argocd_architecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136020/92dd1c25-c34f-ca12-e02d-1f6b19d55ad7.png)

また、2019/11/14 に [Flux](https://fluxcd.io/) の開発を推進している Weaveworks 社と ArgoCD の開発を推進している Intuit 社がパートナーシップを結んだことが発表されました。これにより、ArgoCD プロジェクトと Flux CD プロジェクトが統合された、[GitOps Engine](https://github.com/argoproj/gitops-engine) プロジェクトが開始されています。

Introducing Argo Flux - A Weaveworks-Intuit-AWS Collaboration
https://www.weave.works/blog/argo-flux-join-forces


# OpenShift 上で ArgoCD を動かしてみた
ここからは ArgoCD を使って簡単な GitOps を実践してみます。

## ArgoCD インストール
### ArgoCD インストール
まずは OpenShift 上に ArgoCD を以下のコマンドを実行してインストールします。

```console
$ oc create namespace argocd
namespace/argocd created

$ oc -n argocd apply -f https://raw.githubusercontent.com/argoproj/argo-cd/v1.2.2/manifests/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-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-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-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-ssh-known-hosts-cm created
configmap/argocd-tls-certs-cm created
secret/argocd-secret created
service/argocd-dex-server created
service/argocd-metrics created
service/argocd-redis 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-redis created
deployment.apps/argocd-repo-server created
deployment.apps/argocd-server created
```

ArgoCD のインストールが完了すると、以下のような Pod が起動されます。

```console
$ oc get po
NAME                                             READY   STATUS    RESTARTS   AGE
argocd-application-controller-7b96cb74dd-82dpf   1/1     Running   0          4m51s
argocd-dex-server-58f5b5b44f-nzn6p               1/1     Running   0          4m51s
argocd-redis-868b8cb57f-vw6vj                    1/1     Running   0          4m51s
argocd-repo-server-5bf79d67f4-c5zgx              1/1     Running   0          4m50s
argocd-server-68df77dbb6-vfj4q                   1/1     Running   0          4m50s
```

### Route 作成
次に Web コンソールや CLI ツールからの接続に利用するため Route を作成します。
本記事の環境では自己証明書を利用しているため、以下のコマンドのように argocd-server の Deployment にパッチを適用してから、argocd-server の Service を元に Route を作成します。

```console
$ PATCH='{"spec":{"template":{"spec":{"$setElementOrder/containers":[{"name":"argocd-server"}],"containers":[{"command":["argocd-server","--insecure","--staticassets","/shared/app"],"name":"argocd-server"}]}}}}'
$ oc -n argocd patch deployment argocd-server -p $PATCH
deployment.extensions/argocd-server patched

$ oc -n argocd create route edge argocd-server --service=argocd-server --port=http --insecure-policy=Redirect
route.route.openshift.io/argocd-server created
```

### ArgoCD CLI ツールのインストール
Web コンソールからも操作することができますが、本記事では ArgoCD CLI ツールを使って GitOps の実践を行います。
以下のコマンドを実行して ArgoCD CLI ツールをインストールします。

```console
$ sudo curl -L https://github.com/argoproj/argo-cd/releases/download/v1.2.2/argocd-linux-amd64 -o /usr/local/bin/argocd
$ sudo chmod +x /usr/local/bin/argocd
```

### ArgoCD Server への CLI ツールからのログイン
ArgoCD CLI ツールを使って、ArgoCD Server へログインするコマンドは以下の通りです。

```console
$ ARGOCD_SERVER_PASSWORD=$(oc -n argocd get pod -l "app.kubernetes.io/name=argocd-server" -o jsonpath='{.items[*].metadata.name}')
$ ARGOCD_ROUTE=$(oc -n argocd get route argocd-server -o jsonpath='{.spec.host}')

$ argocd --insecure --grpc-web login ${ARGOCD_ROUTE}:443 --username admin --password ${ARGOCD_SERVER_PASSWORD}
'admin' logged in successfully
Context 'argocd-server-argocd.apps.cluster-9f3a.sandbox1743.opentlc.com:443' updated
```

また、ArgoCD のインストールを行うとデフォルトで Admin ユーザのパスワードが設定されますが、以下のようなコマンドを実行することで Admin パスワードの変更を行うことができます。

```console
$ argocd --insecure --grpc-web --server ${ARGOCD_ROUTE}:443 account update-password --current-password ${ARGOCD_SERVER_PASSWORD} --new-password (新しいパスワード)
```


### Web コンソールへの接続確認
本記事では ArgoCD CLI ツールを使って GitOps の実践を行いますが、Web コンソールから操作を行うこともできます。以下のコマンドを実行して取得した URL をブラウザから開くことで、ArgoCD の Web コンソールに接続することができます。

```console
$ oc -n argocd get route argocd-server -o jsonpath='{.spec.host}'
```

Web コンソール画面は以下の通りです。

![スクリーンショット 2019-12-13 14.50.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136020/936d94ed-b6ed-78e3-0eb3-58e375e3f575.png)


## 簡単な GitOps の実践
### OpenShift クラスタの確認
上記の通り ArgoCD をインストールした場合、自動的に OpenShift クラスタが ArgoCD に追加されます。以下のコマンドを実行することで、自動的に追加された OpenShift クラスタを確認することができます。

```console
$ argocd cluster list
SERVER                          NAME  STATUS      MESSAGE
https://kubernetes.default.svc        Successful
```

### Git リポジトリの追加
マニフェストを格納する Git リポジトリを ArgoCD Server に以下のコマンドを実行して追加します。

```console
$ argocd repo add https://github.com/mamoru1112/gitops-on-openshift.git
repository 'https://github.com/mamoru1112/gitops-on-openshift.git' added
```

追加された Git リポジトリは以下のコマンドで確認することができます。

```console
$ argocd repo list
REPO                                                   INSECURE  LFS    USER  STATUS      MESSAGE
https://github.com/mamoru1112/gitops-on-openshift.git  false     false  -     Successful 
```

### アプリケーション追加
同期を行う OpenShift クラスタと Git リポジトリの追加ができたので、次に以下のコマンドを実行してアプリケーションの追加を行います。

```console
$ argocd app create --project default --name reverse-words-app \
    --repo http://github.com/mamoru1112/gitops-on-openshift.git \
    --path simple-app/reversewords_app/ \
    --dest-server https://kubernetes.default.svc \
    --dest-namespace reverse-words \
    --revision master --sync-policy automated
application 'reverse-words-app' created
```

また、上記のコマンドのそれぞれのオプションの説明は以下の通りです。ここで、プロジェクト・アプリケーションという用語が使用されていますが、OpenShift のプロジェクト・アプリケーションを指しているのではなく、ArgoCD のプロジェクト・アプリケーションを指しています。

* `--project` ： ArgoCD アプリケーションが所属する ArgoCD プロジェクト
* `--name` ： ArgoCD アプリケーション名
* `--repo` ： Git リポジトリ
* `--path` ： Git リポジトリ内のマニフェストが格納されたディレクトリのパス
* `--dest-server` ： OpenShift クラスタ
* `--dest-namespace` ： ArgoCD アプリケーションをデプロイする先の OpenShift プロジェクト
* `--revision` ： Gitリポジトリのブランチ
* `--sync-policy` ： Git リポジトリとの同期のポリシー

以下のコマンドによりアプリケーションが追加されたことを確認できます。Git リポジトリと OpenShift クラスタが正常に同期されると STATUS 欄に "Synced" が表示されます。

```console
$ argocd app list
NAME               CLUSTER                         NAMESPACE      PROJECT  STATUS  HEALTH   SYNCPOLICY  CONDITIONS  REPO                                                  PATH                          TARGET
reverse-words-app  https://kubernetes.default.svc  reverse-words  default  Synced  Healthy  Auto        <none>      http://github.com/mamoru1112/gitops-on-openshift.git  simple-app/reversewords_app/  master
```

アプリケーションの詳細情報は以下のコマンドで確認できます。

```console
$ argocd app get reverse-words-app
Name:               reverse-words-app
Project:            default
Server:             https://kubernetes.default.svc
Namespace:          reverse-words
URL:                https://argocd-server-argocd.apps.cluster-GUID.sandboxXXXX.opentlc.com/applications/reverse-words-app
Repo:               http://github.com/mamoru1112/gitops-on-openshift.git
Target:             master
Path:               simple-app/reversewords_app/
Sync Policy:        Automated
Sync Status:        Synced to master (36306dc)
Health Status:      Healthy

GROUP  KIND        NAMESPACE      NAME           STATUS   HEALTH   HOOK  MESSAGE
       Namespace   reverse-words  reverse-words  Running  Synced         namespace/reverse-words unchanged
       Service     reverse-words  reverse-words  Synced   Healthy        service/reverse-words unchanged
apps   Deployment  reverse-words  reverse-words  Synced   Healthy        deployment.apps/reverse-words unchanged
       Namespace                  reverse-words  Synced   Unknown 
```


### デプロイされたアプリケーションの確認
ArgoCD により Git リポジトリに格納されたマニフェストが OpenShift クラスタ上にデプロイされたことを確認します。
本記事で紹介した Git リポジトリには、Deployment・Service・Namespace のマニフェストファイルが格納されており、デプロイされたアプリケーションでは POST された文字列の順序を逆転した文字列が返されるエンドポイントを提供しています。

```console
$ oc get namespace reverse-words 
NAME            STATUS   AGE
reverse-words   Active   2m29s

$ oc get deployment -n reverse-words
NAME            READY   UP-TO-DATE   AVAILABLE   AGE
reverse-words   1/1     1            1           2m47s

$ oc get svc -n reverse-words
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
reverse-words   ClusterIP   172.30.244.93   <none>        8080/TCP   3m9s

$ oc expose svc reverse-words -n reverse-words
route.route.openshift.io/reverse-words exposed

$ curl -X POST http://$(oc -n reverse-words get route reverse-words -o jsonpath='{.spec.host}') -d '{"word":"PALC"}'
{"reverse_word":"CLAP"}
```


### 削除したリソースが Git リポジトリから復旧されることの確認
GitOps の実践のため、以下のコマンドにより Deployment を削除します。

```console
$ oc delete deployment reverse-words -n reverse-words
deployment.extensions "reverse-words" deleted
```

リソースが削除された後、以下のコマンドによりアプリケーションの状態を確認すると、STATUS 欄に "OutOfSync" に変わっていることが確認できます。

```console
$ argocd app list
NAME               CLUSTER                         NAMESPACE      PROJECT  STATUS     HEALTH   SYNCPOLICY  CONDITIONS  REPO                                                  PATH                          TARGET
reverse-words-app  https://kubernetes.default.svc  reverse-words  default  OutOfSync  Missing  Auto        <none>      http://github.com/mamoru1112/gitops-on-openshift.git  simple-app/reversewords_app/  master
```

次に、Git リポジトリに格納されたマニフェストファイルを "Single Source of Truth" として、以下のコマンドにより同期させ OpenShift クラスタの状態を復旧させます。

```console
$ argocd app sync reverse-words-app
TIMESTAMP                  GROUP                     KIND   NAMESPACE                     NAME    STATUS    HEALTH        HOOK  MESSAGE
2019-12-13T01:31:21+00:00                       Namespace                        reverse-words    Synced   Unknown              
2019-12-13T01:31:21+00:00                         Service  reverse-words         reverse-words    Synced   Healthy              
2019-12-13T01:31:21+00:00   apps               Deployment  reverse-words         reverse-words  OutOfSync  Missing              
2019-12-13T01:31:21+00:00  route.openshift.io       Route  reverse-words         reverse-words  OutOfSync  Unknown              

Name:               reverse-words-app
Project:            default
Server:             https://kubernetes.default.svc
Namespace:          reverse-words
URL:                https://argocd-server-argocd.apps.cluster-GUID.sandboxXXXX.opentlc.com/applications/reverse-words-app
Repo:               http://github.com/mamoru1112/gitops-on-openshift.git
Target:             master
Path:               simple-app/reversewords_app/
Sync Policy:        Automated
Sync Status:        OutOfSync from master (36306dc)
Health Status:      Progressing

Operation:          Sync
Sync Revision:      36306dc264cea403e33b756de6faf95f605fee5d
Phase:              Succeeded
Start:              2019-12-13 01:31:20 +0000 UTC
Finished:           2019-12-13 01:31:25 +0000 UTC
Duration:           5s
Message:            successfully synced (all tasks run)

GROUP               KIND        NAMESPACE      NAME           STATUS     HEALTH       HOOK  MESSAGE
route.openshift.io  Route       reverse-words  reverse-words  OutOfSync  Unknown            ignored (requires pruning)
                    Namespace   reverse-words  reverse-words  Running    Synced             namespace/reverse-words unchanged
                    Service     reverse-words  reverse-words  Synced     Healthy            service/reverse-words unchanged
apps                Deployment  reverse-words  reverse-words  Synced     Progressing        deployment.apps/reverse-words created
                    Namespace                  reverse-words  Synced     Unknown            
FATA[0007] 1 resources require pruning  
```

上記のコマンドの実行結果では、Route を手動で作成したため FATAL メッセージが出力されてしまっていますが、Deployment リソースの HEALTH が "Progressing" になっており、Git リポジトリと OpenShift クラスタが同期されていることが分かります。

Git リポジトリと OpenShift クラスタの同期が完了すると、以下のコマンドによりデプロイされたアプリケーションが復旧したことを確認できます。

```console
$ curl -X POST http://$(oc -n reverse-words get route reverse-words -o jsonpath='{.spec.host}') -d '{"word":"PALC"}'
{"reverse_word":"CLAP"}
```


### Web コンソールから登録されたアプリケーションを確認
ここまでは ArgoCD CLI ツールを使って、Git リポジトリと OpenShift クラスタが同期されることを確認してきましたが、同様の手順を Web コンソールから実行することもできます。全く同じ手順を Web コンソールを使って実行しても面白くないので、上記のコマンド例により追加したアプリケーションが Web コンソール上でどのように表示されるかのみ紹介したいと思います。

Web コンソールでは、以下の画面キャプチャのように Git リポジトリに管理されているマニフェストファイルとリソースの関係や、Git リポジトリと OpenShift クラスタの同期状況などを確認することができます。

![スクリーンショット 2019-12-13 14.53.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136020/35773a9b-3955-dd61-6d2b-3fa3dca4f5e3.png)

また、画面上部に表示されている "APP DETAILS" や "APP DIFF" ボタンを押下することにより、アプリケーションの詳細情報の確認や Git リポジトリとの差異を確認することもできます。


# さいごに
本記事では、OpenShift でも GitOps を実現できることを紹介するため、ArgoCD を使って非常に簡単な GitOps の実践を試してみました。
Web コンソールからの操作の紹介や ArgoCD の機能説明などを本記事では十分にできていませんので、OpenShift 上で実際に GitOps を実践したい方は、以下の ArgoCD のドキュメントを読んで色々と試してもらえると嬉しいです。

https://argoproj.github.io/argo-cd/#what-is-argo-cd


# 参考
* [Introduction to GitOps with OpenShift](https://blog.openshift.com/introduction-to-gitops-with-openshift/)
* [Guide To GitOps](https://www.weave.works/technologies/gitops/)