Alibaba Cloud の ACK One で GitOps を実現するためには

この記事では、Alibaba Cloud の Container Service for Kubernetes（ACK）で GitOps のパイプラインを設定する方法を紹介します。

## 前提
Alibaba Cloudでは、開発クラスタ、ステージングクラスタ、製品クラスタなど、複数のクラスタを同時に管理するための分散型クラウドコンテナプラットフォーム（ACK One）を提供しています。

ただし、ACK One はあくまでアプリケーションをデプロイするためのクラスタです。その上で動作するアプリケーションは、ユーザーが管理しなければなりません。

そうなると、CI/CD パイプラインを整備したり、デプロイ後に問題が発生した場合のロールバック手段を考えたり…といろいろ大変です。

では、ACK のクラスタにデプロイされたアプリケーションを、より便利に管理するにはどうすれば良いのでしょうか？

そこで覚えておきたい手法が **GitOps** です。

GitOps は 2017 年に Weaveworks 社がブログで提唱した CD の手法です。
https://www.weave.works/blog/gitops-operations-by-pull-request

Git を使って、アプリケーションだけではなく、Kubernetes のリソースの構成情報まで一元的に管理してしまおう、という手法です。

では、どうやって GitOps を実現すればよいのか。
そこで利用するのが、 GitOps をベースとした CD ツールの [ArgoCD](https://github.com/argoproj/argo-cd)です。

ArgoCD は ACK アプリケーションを継続的に監視し、現在の状態と、Git リポジトリ上の状態を比較します。もし差分がある場合は、その差分のビジュアライズを行ったり、自動的にアプリケーションの差分を同期することが可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/69901624-f466-19e2-d384-9a60043203e5.png)

以下に、Alibaba Cloud でマネージドな ArgoCD を利用するメリットを記載しました！

1. 開発者は Git リポジトリとクラスタ側だけに注目すればよく、CD のことを意識する必要がありません

2. Gitは、ソースコードとデプロイメントの唯一の変更元であり、そのバージョン管理機能により管理が容易です

3. GitOpsは、Gitリポジトリから更新を取得してクラスタにデプロイする「プル型更新」のため、DevOpsよりも安全なCDプロセスであると言えます。一方、従来のDevOpsの「プッシュ型CD」では、CDツール側（Jenkinsなど）で認証情報を追加する必要があります。そのため、セキュリティ上の情報漏えいが発生する可能性があります。

4. GitOpsは、Gitリポジトリ上の最新バージョンとk8sクラスタ上のデプロイ状況の差異を直感的に把握することができます。変更があった場合、GitOpsが即座に調査し、通知します。

5. 新しいアップデートがクラスタにデプロイされた後に問題が発生した場合、ロールバックを簡単に行うことができます。

6. Alibaba Cloud は、Container Registry Service (ACR) にアクセスする簡単な方法を提供し、ArgoCD は ACR をシームレスに統合することができます。

と、色々と記載いたしましたが、開発者目線で簡単にまとめると、開発者としては「Git リポジトリのソースコード変更だけ気にしているだけで良い！」という状態を作ることができるわけです。
コードを修正したら自動的に最新のアプリケーションがクラウド上にデプロイされます。
万が一バグがあった場合は、簡単にロールバックをすることも可能です。

では、そんな便利な GitOps を導入する手順を見ていきましょう。

## ACK One を有効化する
コンソールを開き、「ACK One」を検索し、その結果から「ACK One」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/00cd61ec-e982-73a6-e8a5-8a0e49441670.png)

リージョン、VPC、vSwitch　の情報を追加し、必要に応じて Kubectl でインターネットからアクセスするための EIP を作成します。その後、Enable Multi-cluster Management を押しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/db644624-bbeb-c773-2832-58c1dda33f5b.png)

Multi-cluster 画面で、Running ステータスと表示されていることが確認できれば OK です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/f72ce3c8-39b9-445c-9dab-2b16c4d3f734.png)

Associated Clusters を選択し、 Add Associated Cluster を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/9dabf573-f924-097a-5a4a-a8e2410ed30f.png)

先程作成した Cluster を選択し、OK を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/f529ffd8-bcb2-ae95-5f34-223a24adada4.png)

Associated のステータスになっていれば完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/c6120cf3-1dc7-24e3-8a0a-22802615ad32.png)

次に、Master Cluster の config ファイルをクライアント端末に設定し、Kubectl 経由で cluster にアクセスできるようにしましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/c2794817-6312-78d0-b4f4-e9cff859a5c5.png)

コマンドは以下のとおりです。
```
# Linux version
wget http://ack-one.oss-cn-hangzhou.aliyuncs.com/kubectl-amc-linux && chmod +x kubectl-amc-linux && mv kubectl-amc-linux  /usr/local/bin/kubectl-amc

# Mac version
curl -LO http://ack-one.oss-cn-hangzhou.aliyuncs.com/kubectl-amc-mac && chmod +x kubectl-amc-mac && mv kubectl-amc-mac  /usr/local/bin/kubectl-amc
```

インストールが完了すると `amc get` コマンドで、Associated Cluster を確認することができます。
```shell
(base) user .kube % kubectl amc get managedcluster
Name                                Alias    HubAccepted
cdaad925bd13f4574a64d68b15aca98f4   ACK001   true
```

## GitOps を有効化する

まずは、 Alibaba Cloud Command Tool をインストールします。
AWS でいう AWS CLI ですね。

```shell
# Linux
wget https://aliyuncli.alicdn.com/aliyun-cli-linux-latest-amd64.tgz
cd  $HOME/aliyun
tar xzvf aliyun-cli-linux-3.0.16-amd64.tgz
sudo cp aliyun /usr/local/bin

# Mac
brew install aliyun-cli
```

`aliyun configure --profile default`コマンドを実行し、認証情報の設定を行います。
RAM アカウント作成時に発行された Access Key ID と Access Key Secret を設定しましょう。
```shell
(base) user ~ % aliyun configure --profile default
Configuring profile 'default' in 'AK' authenticate mode...
Access Key Id []:<Access Key ID を設定>
Access Key Secret []: <Access Key Secret を設定>
Default Region Id []: <リージョンIDを設定>
Default Output Format [json]: json
Default Language [zh|en] en: 
Saving profile[default] ...Done.
```

リージョンについては、Master Instance の詳細画面から確認が可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/e7862f92-9322-47f1-d77b-ace3e1192926.png)

### GitOps を有効化する
まずは、Master Instance の ID を取得します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/2a68bd07-2007-6c6e-6f8e-8f718eaa1589.png)

次に、GitOps 機能を有効にするコマンドを実行します。

```
aliyun adcp UpdateHubClusterFeature --ClusterId <取得した Instance Id> --EnableArgoCD true
```

以上で、GitOps の Pod、つまり ArgoCD がデプロイされました。
`kubectl get pods -n argocd` コマンドを実行すると、Status が確認できます。
```
(base) user ~ % kubectl get pods -n argocd                                                                      
NAME                             READY   STATUS    RESTARTS   AGE
argocd-server-759fb4b5fc-jmk8d   8/8     Running   0          52s
```

ここまでの手順で Master Cluster 上に ArgoCD が動いています。
では次に、クライアント端末側に ArgoCD CLI をインストールしましょう。

```
curl https://ack-one.oss-cn-hangzhou.aliyuncs.com/gitops/get-argocd.sh |bash
```

`argocd version` コマンドでインストールができたことを確認します。
```
(base) root ~ % argocd version
argocd: v2.4.14+029be59
  BuildDate: 2022-10-05T17:31:35Z
  GitCommit: 029be590bfd5003d65ddabb4d4cb8a31bff29c18
  GitTreeState: clean
  GoVersion: go1.18.6
  Compiler: gc
  Platform: darwin/amd64
```

以下のコマンドを実行し、初期の管理者パスワードを取得します。
```
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
```

次に、クライアント端末側からのアクセスを Master Instance の GitOps のポートに転送します。

```
(base) user ~ % kubectl port-forward -n argocd service/argocd-server 8080:https
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
```

では、クライアント端末から`127.0.0.1`にアクセスしてみましょう。
ArgoCD の画面が表示されれば OK です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/4e7ac546-b9ce-7599-5940-25c323ad5936.png)

デフォルトのユーザーは `admin` 、パスワードは先程の手順で確認したものになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/2f222670-8ce1-0d54-313f-677498058c17.png)

以下のようなダッシュボードにログインすることができれば OK です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/d9ab7b53-f603-0ff9-1364-2d473e7e59f5.png)

パスワードが間違っているなど、ログインがうまくできず、MacOS をお使いの方は `base64 -d` コマンドで表示されるパスワード自体が原因である場合があります。
パスワードの最後に `%` がついている場合は、`%` は無視するとうまくログインできるはずです。

### パスワードの更新
年のため、パスワードは更新しておきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/4888e407-2c2d-38b2-01e2-3999764378aa.png)

## Git Config の追加
### Git リポジトリの追加
Git リポジトリを追加するために、Settings から Repositories を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/af5b5f59-fed2-0989-4db2-8af530449d81.png)

CONNECT REPO をクリックしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/238a31d2-156c-d44b-1245-c9318ead1369.png)

SSH 接続でリポジトリを追加するため、Git リポジトリに公開鍵をアップロードしたうえで、秘密鍵を ArgoCD に登録します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/fe4e181f-4799-f5d5-1237-53aa744082d5.png)

リポジトリの追加が完了しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/1e55b3d1-de0e-4f7f-66a1-ab1e17aa852b.png)

## アプリケーションのデプロイ
Applications -> NEW APP を選択し、アプリケーションを登録していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/047c2955-98aa-e17a-c4b5-72158e38f39d.png)

以下の通り、設定を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/a5547726-4173-4b3a-5dd2-fecd2e2eda92.png)

ArgoCD がどのブランチを参照すればよいかを設定しましょう。
（※ このブランチには、アプリケーションをデプロイするために必要な deployments や services.yaml などのテンプレートファイルが含まれる helm フォルダが存在する必要があるので、注意してください） 

加えて、ターゲットとなる Cluster の URL と、デプロイを行うための Namespace も指定しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/171ea55f-d6a0-117d-9358-f4448fdbc6ac.png)

Helm フォルダの設定も行います。
Helm フォルダには、values.yaml として定義される "value" ファイルが含まれていることを確認しましょう。
values.yaml の書き方の詳細は [こちら](https://helm.sh/docs/chart_template_guide/values_files/) を参考にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/0cac6014-6fad-75d1-9596-0d71e6a14d2b.png)

ここまでの手順で、アプリケーションの定義を作成することができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/da6379a8-29a3-0630-2b5c-b36a5ba54b73.png)

ここが ArgoCD の素晴らしい機能で、コンポーネント全体を含んだアプリケーションの概要を可視化することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/bdd29f6e-ef56-404d-7f2d-d95197fdb9fd.png)

## GitOps フローを実行する
では、GitOps を実際に使っていきましょう。
Git リポジトリに変更があった際に、ターゲットとなる Culster 内で稼働するアプリケーションが自動的に更新する方法を確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/0783530a-c92c-3cb3-0718-9ab2e6728fad.png)

現在動作しているイメージのバージョンは 0.1.28 です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/d0a5a2f1-099d-4426-44da-1cff585b0375.png)

アプリケーションにバグが見つかった想定で、修正するための新しいブランチを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/5a92d4eb-a1dc-0772-dd5a-4c360b733c7a.png)

バグを修正したので、バージョンを `0.1.29` に更新し、Git 側に Commit します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/257200f3-c570-8059-c7cd-fc86c2f1e513.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/42672be6-0d57-adb7-1d28-f6f69ce82605.png)

Git サーバー側でプルリクエストを発行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/a7e90f1a-b44b-9c1e-e52d-f540ceb68406.png)

バグ修正用のブランチである `bugfix01` をデプロイメントブランチである `appcenter-test` にマージしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/eb0c9ed7-06d7-888c-3d72-85a6a536fe5e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/5b01fd53-a6e9-8c4f-8e22-9e31d594bc51.png)

管理者側が、対象のプルリクエストを確認し、マージを行った想定です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/89f19606-8d6e-6f28-8cd0-075b1e2440a9.png)

マージが成功しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/227b42a5-8243-8352-0bd6-596f005c602f.png)

ArgoCD 側を確認すると、新しいバージョンの Pod がデプロイされようとしていることがわかります。
Git 側の修正を自動的に検知し、デプロイしてくれている、というわけです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/7c666b47-5c19-67b2-f6eb-d7d657fc9f03.png)

最終的に、自動デプロイが完了し、バージョンが更新されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/7a8175e1-59e7-5d1f-ffee-ac1d458fcc70.png)

## ロールバック
非常に便利ですが、自動デプロイを行った後に、何らかのバグが見つかった場合を考えてみましょう。
GitOps があれば、最新のバージョンで何らかの問題が発生した場合、簡単に以前のバージョンにロールバックすることができます。

まず `HISTORY AND ROLLBACK` を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/9f845b30-8a48-ab81-09f2-a732c8a4ca7b.png)

古いバージョンの右上にあるメニューを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/ebb1789e-95f3-9750-600e-1c49b8cca9d1.png)

表示された `Rollback` を選択しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/ee473450-7149-d72a-aa2a-39dd3764af24.png)

ただ、GitOps が Auto-Sync mode になっている場合、定期的に Git リポジトリの最新状態を見に行ってしまうため、ロールバックしてもまた最新のデプロイが行われてしまいます。
そのため、ロールバックする際には無効にしておきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/6d9317da-765a-1ca2-6606-e826cb3686a3.png)

選択したバージョンがデプロイ中のステータスになっており、同期が OutOfSync 状態になっていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/94a228cf-a62b-3132-2b68-27df2b0e119b.png)

少し待つと、古いバージョンへのロールバックが完了しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/4db557da-26e7-11e0-f7ce-f7ce18262b69.png)

また、何がバグの原因だったのか？を確認するために APP DIFF 機能を使うことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/e2392c3f-6b6e-edc5-52b0-b5fa78cf0c36.png)

最新バージョンでバグが発生した場合に、即座にロールバックを行い、DIFF から問題点を見つけるのに役立ちそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964981/36062796-4cd0-c1df-91dd-a0992bee9520.png)

## おわりに
今回は Alibaba Cloud 上でより便利に ACK One を利用するため、GitOps を取り入れてみました。
自動デプロイやロールバック機能が非常に簡単に実装できることがご理解いただけたかと思います。
ACK One を使う際は、K8s のエコシステムを最大限活用するため、ぜひ GitOps を取り入れてみましょう！