Flux v2でイメージの自動更新を設定する

環境は以下の通りです。

- クラスタ：EKS v1.19
- Git：AWS上のセルフホストGitLab
- コンテナレジストリ：ECR

Flux v2とセルフホストGitLabとの連携は[セルフホストGitLabと連携したFlux v2のセットアップ](https://qiita.com/moriryota62/items/fa7e42ac220c501ac0e0)にあります。この投稿に記載する自動更新のやり方は公式のガイドにある[Automate image updates to Git](https://toolkit.fluxcd.io/guides/image-update/#automate-image-updates-to-git)を参考にしています。

ざっくりとは以下の流れです。

- [コンポーネントのインストール](#コンポーネントのインストール)
- [ECRアクセス用のシークレット準備](#ecrアクセス用のシークレット準備)
- [ImageRepositoryリソースの作成](#imagerepositoryリソースの作成)
- [ImagePolicyソースの作成](#imagepolicyソースの作成)
- [ImageUpdateAutomationリソースの作成](#imageupdateautomationリソースの作成)
- [自動更新対象のイメージにコメントをつける](#自動更新対象のイメージにコメントをつける)

事前にECRには`test`という名前のレポジトリが作成されており、`{コミットハッシュ}-YYYYMMDDHHMM`形式のタグがつくイメージをいくつか格納しています。また、このイメージを使用するPodのマニフェストはFlux管理下のGitレポジトリに格納済です。

# コンポーネントのインストール

イメージの自動更新機能は現時点(2021/4/21)ではまだアルファ機能です。なので明示的に画像更新機能のコンポーネント群を指定してFluxをデプロイします。

``` sh
$ flux bootstrap git \
  --components-extra=image-reflector-controller,image-automation-controller \
  --url=ssh://git@<EC2ホスト名>/<オーナー名>/<レポジトリ名> \
  --branch=<ブランチ名> \
  --path=<マニフェスト配置場所> \
  --private-key-file=<Key名>
► cloning branch "master" from Git repository "ssh://git@<EC2ホスト名>/<オーナー名>/<レポジトリ名>"
✔ cloned repository
► generating component manifests
✔ generated component manifests
✔ committed sync manifests to "master" ("3027f3194c1f0ea96a8216d0ffdf7c2680ad39fc")
► pushing component manifests to "ssh://git@<EC2ホスト名>/<オーナー名>/<レポジトリ名>"
► installing components in "flux-system" namespace
✔ installed components
✔ reconciled components
► determining if source secret "flux-system/flux-system" exists
► generating source secret
✔ public key: ssh-rsa AAAAB3~略~
Please give the key access to your repository: y█
► applying source secret "flux-system/flux-system"
✔ reconciled source secret
► generating sync manifests
✔ generated sync manifests
✔ sync manifests are up to date
► applying sync manifests
✔ reconciled sync configuration
◎ waiting for Kustomization "flux-system/flux-system" to be reconciled
✔ Kustomization reconciled successfully
► confirming components are healthy
✔ notification-controller: deployment ready
✔ image-reflector-controller: deployment ready
✔ image-automation-controller: deployment ready
✔ source-controller: deployment ready
✔ kustomize-controller: deployment ready
✔ helm-controller: deployment ready
✔ all components are healthy
```

# ECRアクセス用のシークレット準備

FluxのコンポーネントからECRへログインするためにdocker-registryタイプのsecretリソースを作成します。なお、ECRのアクセストークンは12時間で切れてしまうためCronJobで自動更新する様に設定します。

こちらについては[K8sで使うECRアクセス用のSecretを自動更新する](https://qiita.com/moriryota62/items/7d94027881d6fe9a478d)に記載しているので省略します。

namespace:`flux-system`にECRアクセス用のsecretを作成したら次に進みます。（以降で作成する`ImageRepository`リソースと同じnamespaceならどこでもいいと思います。）

# ImageRepositoryリソースの作成

Fluxがスキャンする対象のイメージレポジトリを登録するリソースを作成します。以下コマンドでイメージレポジトリリソースのマニフェストを生成します。

``` sh
$ flux create image repository test \
--image=<ECRイメージ名> \
--interval=1m \
--export > test-registry.yaml
```

ECRへのアクセスseretを設定するため、上記作成したマニフェストに以下の様なsecret指定を追加します。ここで指定するsecretは[ECRアクセス用のシークレット準備](#ecrアクセス用のシークレット準備)で作成したものです。

``` yaml
kind: ImageRepository
spec:
  secretRef:
    name: aws-registry
```

上記マニフェストをFlux管理化のGitレポジトリに配置し、変更をプッシュします。そうすればFluxがK8sにデプロイしてくれます。

以下コマンドでFluxからイメージレポジトリが見えていることを確認します。

``` sh
$ flux get image repository test
NAME         	READY	MESSAGE                      	LAST SCAN                	SUSPENDED
test	        True 	successful scan, found 2 tags	2021-04-23T16:46:00+09:00	False
```

# ImagePolicyソースの作成

イメージ更新のポリシーを定義するリソースを作成します。以下、マニフェストの記述例です。イメージタグが`{コミットハッシュ}-YYYYMMDDHHMM`の形式で付与されており、その中でも最新の日付(YYYYMMDDHHMM)のタグに自動更新したい場合の例です。なお、イメージレポジトリに違う形式のタグが混ざっているとうまく最新イメージタグを拾ってこれなかったため、対象イメージレポジトリ内のタグは整理しておいた方が良いみたいです。

ポリシーの指定方法はいくつか方法があるため公式ガイドにある[examples](https://toolkit.fluxcd.io/components/image/imagepolicies/#examples)も参考にしてください。

``` yaml
apiVersion: image.toolkit.fluxcd.io/v1alpha1
kind: ImagePolicy
metadata:
  name: test
  namespace: flux-system
spec:
  imageRepositoryRef:
    name: test
  filterTags:
    pattern: '[a-fA-F0-9]+-(?P<ts>.*)'
    extract: '$ts'
  policy:
    numerical:
      order: asc
```

上記マニフェストを作成したらFlux管理化のGitレポジトリに配置し、変更をプッシュします。

以下コマンドでFluxから最新のイメージが認識できているか確認します。この時はECRに`244d5623-202104230839`、`4db5dfff-202104230850`、`54edfdfd-202104230903`っという3つのイメージタグがある状態で狙い通り最新日付の`54edfdfd-202104230903`を認識できていることがわかります。

``` sh
$ flux get image policy
NAME         	READY	MESSAGE                                                                                                              	LATEST IMAGE
test        	True 	Latest image tag for '<アカウント>.dkr.ecr.<region>.amazonaws.com/test' resolved to: 54edfdfd-202104230903                 <アカウント>.dkr.ecr.<region>.amazonaws.com/test:54edfdfd-202104230903
```

# ImageUpdateAutomationリソースの作成

以下の様なマニフェストを作成します。`gitRepositoryRef`で指定するGitレポジトリはFluxをデプロイしたときに`flux-system`という名前のgitrepositoriesリソースが作成されているはずなのでその名前を指定します。`kubectl get gitrepositories -n flux-system`でも確認できます。`branch`には任意のブランチ名を指定します。以下の例ではmasterを直で修正させてます。

``` yaml
apiVersion: image.toolkit.fluxcd.io/v1alpha1
kind: ImageUpdateAutomation
metadata:
  name: test
  namespace: flux-system
spec:
  checkout:
    branch: master
    gitRepositoryRef:
      name: flux-system
  commit:
    authorEmail: fluxcdbot@users.noreply.github.com
    authorName: fluxcdbot
    messageTemplate: '{{range .Updated.Images}}{{println .}}{{end}}'
  interval: 1m0s
  push:
    branch: master
  update:
    path: ./test/
    strategy: Setters
```

上記マニフェストを作成したらFlux管理下のGitレポジトリに配置し、変更をプッシュします。

以下のコマンドで自動更新が有効になっているか確認します。

``` sh
$ flux get images update
NAME         	READY	MESSAGE                                                     	LAST RUN                 	SUSPENDED
test        	True 	no updates made; last commit e0b7a6d at 2021-04-23T09:42:21Z	2021-04-23T18:47:40+09:00	False
```

# 自動更新対象のイメージにコメントをつける

Flux v2では自動更新するイメージをコメントで判別している様です。以下のように対象イメージの後ろにコメントを追加します。ここで指定するimagepolicyはさきほど[imagepolicyソースの作成](#imagepolicyソースの作成)作成したimagepolicyの名前です。

``` yaml
apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
      - image: <アカウント>.dkr.ecr.<region>.amazonaws.com/test:244d5623-202104230839 # {"$imagepolicy": "flux-system:test"}
```

上記マニフェストを修正したらFlux管理化のGitレポジトリに配置し、変更をプッシュします。

しばらく(2分くらい)した後にPodの状態を確認します。うまく出来ていればイメージタグがFluxにより最新日付のタグ`54edfdfd-202104230903`へ書き換えられています。以降はECRのイメージを更新するたびにFluxがGitレポジトリのマニフェストを自動で更新し、デプロイしてくれます。Gitレポジトリに対して手動で変更を加えたい時は必ず`git pull`するのを忘れない様に気をつけましょう。