FluxCDとGitHub Container Registryを連携させて、Kubernetesでコンテナイメージの自動検出と同期を実現する方法

こんにちは！今回は、Kubernetes環境でGitOpsを実践するためのツールとして注目を集めているFluxCDと、GitHub Container Registry（GHCR）の連携方法についてご紹介します。

## FluxCDとGitOpsって何？

FluxCDは、GitOpsの原則に基づいてKubernetesクラスタの継続的デリバリー（CD）を自動化するためのツールです。GitOpsとは、Gitリポジトリを「真実の唯一の源（single source of truth）」として扱い、インフラストラクチャとアプリケーションの状態を宣言的に管理する方法論です。

FluxCDの主な特徴として：

- Gitリポジトリに記述された望ましい状態に基づく自動同期とデプロイ
- 宣言的な設定管理
- コンテナレジストリの状態をKubernetesオブジェクトとして管理
- 複数クラスタの管理

などが挙げられます。

FluxCDを使うことで、以下のようなメリットが得られます：

1. インフラストラクチャとアプリケーションの状態のバージョン管理が容易になる
2. デプロイプロセスの一貫性と再現性が向上する
3. ロールバックが簡単
4. 運用の自動化による人的ミスの削減

## 本記事の内容

FluxCDでは `ImageRepository` というリソースを作っておくと、コンテナイメージリポジトリの状態をKubernetesのオブジェクトとして扱うことができます。この仕組みを応用すると、デプロイメントやポッドに指定されたイメージのバージョンを自動的にアップデートしていったりといった仕組みが可能になります。こうした基盤ができていると、アプリケーション開発者からすると、コンテナイメージをビルド&プッシュするだけで、アプリケーションをデプロイできるようになるので非常に便利です。 今回は、そこへの足がかり的な実践として、FluxCDとGitHub Container Registry（GHCR）の連携方法を解説します。

なお、この記事で作るファイルなどはGitHubに置いてありますので、必要であればこちらもご覧ください。

https://github.com/suinplayground/kubernetes-playground/tree/main/fluxcd/01-scanning-for-new-tags-in-github-container-registry

## 目次

1. [GHCRへのDockerイメージのプッシュ](#ghcrへのdockerイメージのプッシュ)
2. [FluxCDのセットアップ](#fluxcdのセットアップ)
3. [GHCRからのイメージタグ取得の設定](#ghcrからのイメージタグ取得の設定)
4. [新規タグのプッシュとスキャン結果の確認](#新規タグのプッシュとスキャン結果の確認)
5. [クリーンアップ](#クリーンアップ)

では、早速始めましょう！

## GHCRへのDockerイメージのプッシュ

まずは、GitHub Container RegistryにDockerイメージをプッシュする準備から始めます。

### GitHub Personal Access Token (PAT) の作成

1. 以下のURLにアクセスしてください：
	 https://github.com/settings/tokens/new

2. トークンタイプは「personal access token (classic)」を選択します。
	 注意：現時点では、fine-grained PATにPackage Readスコープがないため、classicを使用します。

3. ラベルは「package-write-token」とし、`write:packages`スコープを選択します。

### GitHub Container Registryへのログイン

作成したPATを使って、GHCRにログインしましょう。

```shell
echo -n $GITHUB_PAT | docker login ghcr.io -u $GITHUB_USERNAME --password-stdin
```

`$GITHUB_PAT`には実際のPATを、`$GITHUB_USERNAME`にはGitHubのユーザー名を入力してくださいね。

### Dockerイメージのビルド

次に、簡単なウェブアプリケーション用のDockerfileを作成します。

```dockerfile
FROM nginx:alpine
WORKDIR /usr/share/nginx/html
RUN echo "<html><body><h1>Hello world</h1></body></html>" > index.html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
```

このDockerfileを使ってイメージをビルドします。

```shell
docker build -t ghcr.io/$GITHUB_ORG_NAME/some-web-app:1.0.0 .
```

`$GITHUB_ORG_NAME`は実際のGitHub組織名に置き換えてください。

### イメージのプッシュ

ビルドしたイメージをGHCRにプッシュします。

```shell
docker push ghcr.io/$GITHUB_ORG_NAME/some-web-app:1.0.0
```

プッシュが完了したら、GitHubの組織ページの「Packages」タブで確認してみましょう。

## FluxCDのセットアップ

次は、FluxCDをKubernetesクラスターにセットアップします。

まず、Helmfileを作成します。`helmfile.yaml`というファイルを作成し、以下の内容を記述してください：

```yaml
repositories:
  - name: fluxcd-community
    url: https://fluxcd-community.github.io/helm-charts

releases:
  - name: flux-system
    namespace: flux-system
    chart: fluxcd-community/flux2
    version: 2.13.0  # 最新バージョンに更新してください
```

そして、以下のコマンドを実行してFluxCDをインストールします：

```shell
helmfile sync
```

## GHCRからのイメージタグ取得の設定

FluxCDがGHCRからイメージを取得できるようにするため、いくつかの設定を行います。

### GitHub Container Registry用のSecretの作成

まず、新しいGitHub Personal Access Tokenを生成します：
https://github.com/settings/tokens/new

今回は「personal access token (classic)」を選択し、ラベルは「package-read-token」、スコープは`read:packages`を選択します。

このトークンを使用して、Kubernetes Secretを作成します：

```shell
kubectl create secret docker-registry github-registry-pull-secret \
  --docker-username=$GITHUB_USERNAME \
  --docker-password=$GITHUB_PAT \
  --docker-server=ghcr.io
```

### FluxCDの`ImageRepository`リソースの作成

次に、FluxCDの`ImageRepository`リソースを定義します。`01-image-repositories.yaml`というファイルを作成し、以下の内容を記述してください：

```yaml
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
  name: some-web-app
  namespace: default
spec:
  image: ghcr.io/$GITHUB_ORG_NAME/some-web-app
  interval: 5m
  secretRef:
    name: github-registry-pull-secret
```

`$GITHUB_ORG_NAME`は実際のGitHub組織名に置き換えてくださいね。

そして、このリソースを適用します：

```shell
kubectl apply -f 01-image-repositories.yaml
```

## 新規タグのプッシュとスキャン結果の確認

ここからが楽しいところです。新しいタグをプッシュして、FluxCDがどう反応するか見てみましょう。

まず、バージョン2.0.0のイメージをビルドしてプッシュします：

```shell
docker build -t ghcr.io/$GITHUB_ORG_NAME/some-web-app:2.0.0 .
docker push ghcr.io/$GITHUB_ORG_NAME/some-web-app:2.0.0
```

そして、FluxCDがこの新しいタグを検出するのを待ちます（約5分）：

```shell
sleep 300 # 5分待機
kubectl get imagerepository some-web-app -o yaml | yq .status.lastScanResult
```

結果は次のようになるはずです：

```yaml
latestTags:
  - 2.0.0
  - 1.0.0
scanTime: "2024-09-05T07:43:34Z"
tagCount: 2
```

新しいタグが追加されていることが確認できましたね！

## クリーンアップ

デモが終わったら、きちんと後片付けをしましょう。以下のコマンドで`ImageRepository`リソースを削除します：

```shell
kubectl delete imagerepository some-web-app
```

これで、GHCRからの定期的なイメージタグ情報の取得が停止します。

## まとめ

FluxCDとGitHub Container Registryを連携させることで、以下のことが実現できました：

1. コンテナイメージリポジトリの状態をKubernetesオブジェクトとして管理
2. 新しいイメージタグの自動検出
3. Kubernetes内でのイメージタグ情報の最新状態の維持

これらの設定は、GitOpsの実践において重要な基盤となります。新しいイメージがプッシュされたときに自動的にデプロイを行うなど、さらに高度な自動化も可能です。

ぜひ、みなさんの環境でも試してみてください！質問やコメントがあれば、ぜひ下のコメント欄でお聞かせください。Happy Kubernetes Life!

## 一緒に働きませんか？

僕の会社(株式会社クラフトマンソフトウェア)では、Kubernetesエンジニアを募集しています！興味がある方はぜひ↓も御覧ください😌

https://craftsman-software.com/recruit/