2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

FUJITSUAdvent Calendar 2022

Day 3

Flux OCI Artifactsサポートを利用したGitOpsについて(ハンズオン編)

Posted at

Fujitsu Advent Calendarの3日目です。2日目と同じテーマであるFluxによるGitOpsについて書きたいと思います。昨日のブログでは、ハンズオン部分が間に合わなかったので3日目も空いていることですし、記事を 概要編 と ハンズオン編 で分けてみました。


ハンズオンで実現するGitOps環境

実現する環境は以下の要素で構成されます:

  • Github上のリポジトリ
  • GitHub ActionによるCIパイプライン
  • Github上のコンテナレジストリ(OCIレジストリ)
  • k8sクラスタ上のFlux

Github上のリポジトリへのコミットによってCIパイプラインがトリガーされ、OCI ArtifactsをOCIレジストリに格納するジョブが実行されます。k8sクラスタ上のFluxがOCI Artifactsのハッシュが更新されたことを検出して、OCI Artifactsに含まれるマニフェストを取得し、クラスタに適用します。

image.png(出典:OCI cheatsheet | Flux

最終的には以下のような構成を作り上げていきます。

image.png

それでは1つずつ見ていきます。

k8sクラスタの作成

まずはローカルにシングルノードクラスタを立ち上げます。

$ kind create cluster
Creating cluster "kind" ...
 ✓ Ensuring node image (kindest/node:v1.25.3) 🖼
 ✓ Preparing nodes 📦
 ✓ Writing configuration 📜
 ✓ Starting control-plane 🕹️
 ✓ Installing CNI 🔌
 ✓ Installing StorageClass 💾
Set kubectl context to "kind-kind"
You can now use your cluster with:

kubectl cluster-info --context kind-kind

Thanks for using kind! 😊

GitOpsのSourceとなる空のGitリポジトリを作成する

Github上に空のリポジトリを作成します。ここにFluxの設定に関するマニフェストをこの後格納していきます。

image.png

この段階では上記のような構成になります。

FluxのVSCode拡張機能を使ってクラスタ上にFlux CRDsをセットアップする

先ほど作成したGitリポジトリをクローンして、VSCodeで開きます。

$ git clone https://github.com/nekia/qiita-podinfo
$ cd qiita-podinfo
$ code .

VSCodeに拡張機能GitOps Tools for Fluxを追加します。ここで1点注意が必要です。デフォルトでインストールされるバージョンではなく、プレリリース版(執筆時点ではv0.22.1668822354)をインストールしないと、私の環境だとうまく動作しませんでした。

image.png

  • 拡張機能のページに満たす必要のある依存関係がきさいしてあるので別途対応が必要です(kubectl/flux/gitコマンドのインストール)

拡張機能をインストールするとサイドメニューにGitOpsのアイコンが現れるので、クリックしてGitOps Viewに移動します。ここで正しくセットアップできていると以下のように、先に生成したk8sクラスタ kind-kind が検出されています。ここから SOURCESもしくはWORKLOADSウィンドウ内の Enable GitOpsをクリックし、クラスタにFluxの各種CRDをインストールします。
image.png
これによりクラスタ内にGitOpsに必要な各種コントローラがインストールされます。
image.png

GitOps Toolkitに対してターゲットとなるソースリポジトリとデプロイメント方法を設定

ここではPodinfoという既存のサンプルアプリ(https://github.com/stefanprodan/podinfo) をターゲットにしてみます。クラスタへのGitOps Toolkitのインストールで追加されたGitRepositoryというリソースを生成しまが、その際にこのターゲットを指定します。アプリのデプロイメント方法に関しては、指定したリポジトリ内にあるKustomizationsのマニフェストファイルへのパスを指定します(./kustomize)。

image.png

上記の設定で + Create をクリックするとターゲットのGitリポジトリとのReconcileが開始され、しばらくするとサービスがクラスタ上で動作していることが確認できます。

$ kubectl port-forward svc/podinfo 9898:9898
Forwarding from 127.0.0.1:9898 -> 9898
Forwarding from [::1]:9898 -> 9898

image.png

この時点での構成は以下のようになっています。ご覧頂くと分かる通り、アプリを構成するマニフェストはローカルのみに存在してGitOpsと呼べる状態になっていません(Podinfo自体はGitリポジトリから参照していますが、これはあくまでRead OnlyなUpstreamのGitリポジトリをサンプルアプリとして利用しているためGitOpsには該当しません)。

image.png

次のステップでは、現在ローカルのみに存在しているマニフェストをGitリポジトリにPushし、それらをOCI ArtifactsとしてOCIレジストリに登録するCIパイプラインを作成して、クラスタからOCI経由で同期するように変更していきます。

なお、ここまでで作成した Sources と Workloads は一旦削除します。

マニフェストファイルとOCIレジストリとの同期設定をGitリポジトリにPushする

まずは先ほどと同じ設定で、SourceとKustomizationをVSCode拡張機能から作成し、今度は YAML を選択してマニフェストファイルをエクスポートします。

# cluster/demo/app.yaml
---
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: GitRepository
metadata:
  name: nekia-qiita-podinfo-main
  namespace: flux-system
spec:
  gitImplementation: go-git
  interval: 1m0s
  ref:
    branch: master
  url: https://github.com/stefanprodan/podinfo

---
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
  name: podinfo
  namespace: flux-system
spec:
  interval: 1m0s
  path: ./kustomize
  prune: true
  sourceRef:
    kind: GitRepository
    name: nekia-qiita-podinfo-main
  targetNamespace: default

これを作成したGitリポジトリの cluster/demo/app.yaml にPushします。このマニフェストは、この後作成するCIパイプラインにて、OCI ArtifactsとしてGithub Container Registryに格納されるファイルになります。

次に、OCIレジストリからマニフェストを含むOCI Artifactsを取得する設定と、そのマニフェストを使ってデプロイメントする設定を作成していきます。

image.png

これも YAML を選択してマニフェストファイルをエクスポートし、Gitリポジトリのcluster/demo/sync.yaml にPushします。

OCIレジストリをターゲットにした同期をローカルからBootstrapする

この段階でGitOpsの同期を開始します。設定がまだ足りておらずエラーが出るので1つずつ対処していきます。Bootstrap方法は以下の通り、先ほどPushしたcluster/demo/sync.yamlをローカルでクラスタに適用します。OCIレジストリ上のOCI Artifacts(この後のステップで作成。app.yamlとsync.yamlを含む)との同期をBootstrapします。一度Bootstrapしてしまえば、以降はGitリポジトリへの変更のたびに更新されるOCI ArtifactsをソースとしたGitOps構成ができあがります。

$ kubectl apply -f cluster/demo/sync.yaml
ocirepository.source.toolkit.fluxcd.io/nekia-qiita-oci-podinfo-main created
kustomization.kustomize.toolkit.fluxcd.io/oci-podinfo created

この時点での構成は以下のようになっています。

image.png

Github Container Registryへアクセスするためのシークレット作成

同期を開始すると新たに OCIRepositoryが見えるようになりますが、作成に失敗していることが分かります。
image.png
設定で指定したシークレットghcr-secretを作成してやる必要がありますので以下のコマンドで作成します。GITHUB_USERとGITHUB_TOKENは別途取得、設定が必要です。

$ flux create secret oci ghcr-secret --url=ghcr.io --username=$GITHUB_USER --password=$GITHUB_TOKEN
► oci secret 'ghcr-secret' created in 'flux-system' namespace
$ kubectl get secrets -n flux-system
NAME          TYPE                             DATA   AGE
ghcr-secret   kubernetes.io/dockerconfigjson   1      7m43s

シークレットを設定するとOCIRepositoryのエラーが AuthenticationFailedからOCIArtifactPullFailedに変わります。まだGithub Container Registry上にsync.yamlで指定したOCI Artifacts nekia/manifests/podinfoが存在しないため、Pullに失敗しています。次のステップでGitHub上にGitHub Actionを使ったCIパイプラインを追加してOCI Artifactsをレジストリに追加していきます。

image.png

CIパイプラインでOCI Artifactsをレジストリに格納する

Github Actionについては、公式ドキュメントでサンプルが紹介されており、その設定を参考にします。

name: push-artifact-staging

on:
  push:
    branches:
      - 'main'

permissions:
  packages: write # needed for ghcr.io access

env:
  OCI_REPO: "oci://ghcr.io/nekia/manifests/podinfo"
  MANIFEST_PATH: "./cluster/demo"

jobs:
  kubernetes:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Setup Flux CLI
        uses: fluxcd/flux2/action@main
      - name: Login to GHCR
        uses: docker/login-action@v2
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      # - name: Generate manifests
      #   run: |
      #     kustomize build ./manifests/staging > ./deploy/app.yaml
      - name: Push manifests
        run: |
          flux push artifact $OCI_REPO:$(git rev-parse --short HEAD) \
            --path=$MANIFEST_PATH \
            --source="$(git config --get remote.origin.url)" \
            --revision="$(git branch --show-current)/$(git rev-parse HEAD)"
      - name: Deploy manifests to staging
        run: |
          flux tag artifact $OCI_REPO:$(git rev-parse --short HEAD) --tag latest

このファイルをリポジトリの .github/workflows配下にPushするとCIパイプラインが作成され、早速PushをトリガーにしてCIジョブがスタートし、以下の通りGithub Container RegistryにOCI Artifactsが格納されます。

image.png

なおCIジョブによってGithub Container Registry上に作成されたOCI Artifactsは以下のコマンドで中身を確認可能です。

$ flux pull artifact oci://ghcr.io/nekia/manifests/podinfo:latest --output ./tmp/
► pulling artifact from ghcr.io/nekia/manifests/podinfo:latest
✔ source https://github.com/nekia/qiita-podinfo
✔ revision main/c43f6a46e67730359a6f2d4db9522f94d20308ff
✔ digest ghcr.io/nekia/manifests/podinfo@sha256:0084c529dad5632a7972a0ac18ac447da37db9593ae8a86ba606bb1e12e2d088
✔ artifact content extracted to ./tmp/
$ find ./tmp/ -type f
./tmp/cluster/demo/app.yaml
./tmp/cluster/demo/sync.yaml

この状態でOCIRepositoryの同期状態を再確認すると、同期に成功しているはずです。合わせてOCI Artifactsから取得されたマニフェストapp.yamlによってGitRepositoryおよびKustomization: podinfoも作成されているはずです。

image.png

前述した手順と同じようにServiceをPort Forwardすると、http://localhost:9898/ からPodInfoアプリにアクセスできるはずです。この段階で、本記事の冒頭に載せていた構成が完成しました。

image.png

PodInfoアプリのバージョンを変更する

cluster/demo/app.yaml内で指定しているアプリのバージョンを 6.2.3 から 6.2.2に変更してみます。

image.png

Gitレポジトリの変更を検出して新たなバージョンのアプリケーションが自動でデプロイされることが以下の通り確認できると思います。

image.png

Fluxで管理されるリソースの由来をトレースする

例えば今回動かしているPodInfoアプリがどのバージョンで、どのマニフェストに基づいてデプロイメントされているのか、を確認したい場合には以下の手順でトレースが可能です。flux CLIの trace コマンドで指定リソースの由来を追跡することが可能です。

$ flux trace -n default deployment podinfo

Object:          Deployment/podinfo
Namespace:       default
Status:          Managed by Flux
---
Kustomization:   podinfo
Namespace:       flux-system
Target:          default
Path:            ./kustomize
Revision:        6.2.2/1cf228c67b8f8102db1a6966f81a95c09954b3e8
Status:          Last reconciled at 2022-12-04 22:07:43 +0900 JST
Message:         Applied revision: 6.2.2/1cf228c67b8f8102db1a6966f81a95c09954b3e8
---
GitRepository:   podinfo
Namespace:       flux-system
URL:             https://github.com/stefanprodan/podinfo
Tag:             6.2.2
Revision:        6.2.2/1cf228c67b8f8102db1a6966f81a95c09954b3e8
Status:          Last reconciled at 2022-12-04 22:02:09 +0900 JST
Message:         stored artifact for revision '6.2.2/1cf228c67b8f8102db1a6966f81a95c09954b3e8'

https://github.com/stefanprodan/podinfo6.2.2/1cf228c67b8f8102db1a6966f81a95c09954b3e8から取得したGitRepositoryに由来することが分かります。更にGitRepositoryリソースpodinfoのラベルをチェックするとkustomizeリソースoci-podinfoに由来することが読み取れます。

$ kubectl describe gitrepositories.source.toolkit.fluxcd.io -n flux-system podinfo | head -n 10
Name:         podinfo
Namespace:    flux-system
Labels:       kustomize.toolkit.fluxcd.io/name=oci-podinfo
              kustomize.toolkit.fluxcd.io/namespace=flux-system
Annotations:  <none>
API Version:  source.toolkit.fluxcd.io/v1beta2
Kind:         GitRepository
Metadata:
  Creation Timestamp:  2022-12-04T01:46:08Z
  Finalizers:

次にkustomizeリソースoci-podinfoの詳細を確認すると、OCIRepositoryリソースnekia-qiita-oci-podinfo-mainが由来であることが更に分かります。

$ kubectl get kustomizations.kustomize.toolkit.fluxcd.io -n flux-system oci-podinfo -o jsonpath='{.spec}' | jq
{
  "force": false,
  "interval": "30s",
  "path": "./",
  "prune": true,
  "sourceRef": {
    "kind": "OCIRepository",
    "name": "nekia-qiita-oci-podinfo-main"
  },
  "targetNamespace": "flux-system"
}

最後にOCIRepositoryリソースnekia-qiita-oci-podinfo-mainの詳細を確認すると、oci://ghcr.io/nekia/manifests/podinfo:latestのOCI Artifactsを参照していることが分かり、そのOCI Artifactsはhttps://github.com/nekia/qiita-podinfoリポジトリのmain/c43f6a46e67730359a6f2d4db9522f94d20308ffから作成されていることが分かります。長かった。。。

{
  "interval": "30s",
  "provider": "generic",
  "ref": {
    "tag": "latest"
  },
  "secretRef": {
    "name": "ghcr-secret"
  },
  "timeout": "60s",
  "url": "oci://ghcr.io/nekia/manifests/podinfo"
}
{
  "checksum": "6941be0504e583be9b631d3a06ae3d7ae28bc05c9661b0aa0c6cd9d3e8d8b5d4",
  "lastUpdateTime": "2022-12-04T13:02:08Z",
  "metadata": {
    "org.opencontainers.image.created": "2022-12-04T13:01:33Z",
    "org.opencontainers.image.revision": "main/c43f6a46e67730359a6f2d4db9522f94d20308ff",
    "org.opencontainers.image.source": "https://github.com/nekia/qiita-podinfo"
  },
  "path": "ocirepository/flux-system/nekia-qiita-oci-podinfo-main/0084c529dad5632a7972a0ac18ac447da37db9593ae8a86ba606bb1e12e2d088.tar.gz",
  "revision": "latest/0084c529dad5632a7972a0ac18ac447da37db9593ae8a86ba606bb1e12e2d088",
  "size": 532,
  "url": "http://source-controller.flux-system.svc.cluster.local./ocirepository/flux-system/nekia-qiita-oci-podinfo-main/0084c529dad5632a7972a0ac18ac447da37db9593ae8a86ba606bb1e12e2d088.tar.gz"
}
  • 本来はflux traceコマンドでOCI Artifactまで辿れるはずなのですが今回作成した環境だとうまくいかず、コミュニティに質問中です。

最後に

アプリのGitレポジトリとマニフェストのGitレポジトリが出てきて分かりにくい部分があったかと思います。私はおうちK8sクラスタ環境でFluxを使っていますが、今回のOCI Artifactsサポートで解決するようなチャレンジを抱えるほど使い込んでいないため、より理解しやすいデモを共有できませんでしたが、少しでもFluxにでもGitOpsにでも興味持って試してみたいと思っていただけたら幸いです。


参考URL

概要編にも載せましたが再掲しておきます。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?