KubernetesクラスタのGitOps用レポジトリの紹介
このポストでは最近構築していじっているおうちラボのKubernetesクラスタの、GitOpsのレポジトリについて紹介します。このセットアップで使用しているバージョン管理システムは、おうちラボ上で動かしているGitLabです。
最初に触れておかなくてはいけないのですが、fluxcdの公式ドキュメントより次のリンクで紹介しているようなものほぼそのままです。更には参考用にパブリックレポジトリのリンクもこのドキュメントにあります。それらを参考に私のレポジトリはこうなっていますという紹介が今回のポストの内容になります。
Ways of structuring your repositories
またついでにと言えばよいのか、以前のポストAnsible で作るおうちラボ HA Kubernetes クラスタの流れでGitOpsのセットアップについてもカバーし、デモも一つやります。
お題に到達するまでが長いので、セットアップの流れが不要な方は目次より一番下まで飛んでくださいませ。
流れ
- gitレポジトリを用意する
- owner ロールと api スコープを持つプロジェクトアクセストークンを作成する
-
flux bootstrap
コマンドで使用する必要な変数をエクスポートする
-
- kubectl を使用してクラスタにアクセスできるホストに flux cli をインストールする
-
flux bootstrap
を実行する - リポジトリとクラスタの変更を観察する
- デモ
- 私の GitOps リポジトリ構造の紹介
プロジェクトの作成
"gitops" というグループ内に "homelab" という名前のプロジェクトを作成しました。
プロジェクトアクセストークン
fluxcdが最初のbootstrap時に利用するアクセストークンを用意します。
プロジェクトの"settings" > "access tokens" と移動し、プロジェクト専用のアクセストークンを一つ払い出します。有効期限については心配しないでください。このトークンは最初に一回使用されるだけです。
- 名前を付ける
- owner ロールと api スコープを設定する
https://YOUR_GITLAB_HOST/gitops/homelab/-/settings/access_tokens
最近、owner ロールと api スコープを設定した "hlv3" および "lab-hlv3" という名前の新しいアクセストークンを作成しました。これらは、外部 etcd クラスタを持つ HA クラスタを構築するために私の ansible プロジェクトを使用して構築された最新の Kubernetes クラスタ用です。
トークンを取得したら、fluxのbootstrapを実行するホストでexportしておきましょう。
export GITLAB_TOKEN={access_token_string_here}
export GITLAB_SERVER={YOUR_GITLAB_HOST}
flux のインストール
https://fluxcd.io/flux/installation/
fluxのインストールです。普段kubectl
などでクラスタを管理しているホストにインストールしましょう。kubectl
同様、flux
コマンドも~/.kube/config
なりKUBECONFIG変数を参照してクラスタとやり取りします。
curl -s https://fluxcd.io/install.sh | sudo bash
補完が用意されているのでシェルに設定しておくと便利です。私の場合は~/.bashrc
に以下を書き込みました。
. <(flux completion bash)
ブートストラップ
https://fluxcd.io/flux/installation/bootstrap/gitlab/
以下はfluxでself-hostのGitLabと"lab-hlv3"と名付けていじっているクラスタとをbootstrapした時のコマンドです。上のリンクと少し異なっている部分があるので説明します。
-
--owner=gitops
およびrepository=homelab
で "gitops/homelab" レポジトリを指している -
--hostname="$GITLAB_SERVER"
も合わせ、レポジトリの宛先は "https://GITLAB_SERVER/gitops/homelab.git" となる -
--branch=main
はそのままの通り、対象ブランチはmainとしている -
--path=./cluster/lab-hlv3
はfluxインストールおよびGitOps対象とするパスを指定している- インストールされるfluxのコンポーネントも宣言的で、このディレクトリにマニフェストが書かれpushされる
-
--cluster-domain=lab.example.net
はクラスタのドメインを指定している- デフォルトではkubernetesクラスタのドメインは"cluster.local"であり
flux bootstrap
コマンドのデフォルトも同様
- デフォルトではkubernetesクラスタのドメインは"cluster.local"であり
# do not forget to have these variables set/exported
#export GITLAB_TOKEN={token_string_here}
#export GITLAB_SERVER={YOUR_GITLAB_HOST}
flux bootstrap gitlab \
--deploy-token-auth \
--hostname="$GITLAB_SERVER" \
--owner=gitops \
--repository=homelab \
--path=./clusters/lab-hlv3 \
--branch=main \
--cluster-domain=lab.example.net
# if you mess up anything and want to start over, run uninstall, and you will be ready to run another flux bootstrap
#
# flux uninstall
bootstrap後のクラスタとレポジトリについて
クラスタの状態
まずはクラスタを見ていきます。つくられたものは以下の通りです。
$ kubectl get all -n flux-system
NAME READY STATUS RESTARTS AGE
pod/helm-controller-654c4c4c64-2wtbp 1/1 Running 0 19h
pod/kustomize-controller-55ff9444cd-kkkxm 1/1 Running 0 19h
pod/notification-controller-58ffd586f7-94vkp 1/1 Running 0 19h
pod/source-controller-5b6b6d555c-5dpv5 1/1 Running 0 19h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/notification-controller ClusterIP 10.96.22.37 <none> 80/TCP 19h
service/source-controller ClusterIP 10.96.166.23 <none> 80/TCP 19h
service/webhook-receiver ClusterIP 10.96.197.23 <none> 80/TCP 19h
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/helm-controller 1/1 1 1 19h
deployment.apps/kustomize-controller 1/1 1 1 19h
deployment.apps/notification-controller 1/1 1 1 19h
deployment.apps/source-controller 1/1 1 1 19h
NAME DESIRED CURRENT READY AGE
replicaset.apps/helm-controller-654c4c4c64 1 1 1 19h
replicaset.apps/kustomize-controller-55ff9444cd 1 1 1 19h
replicaset.apps/notification-controller-58ffd586f7 1 1 1 19h
replicaset.apps/source-controller-5b6b6d555c 1 1 1 19h
api-resourcesはこの通りです。
$ kubectl api-resources --namespaced=true | grep flux
helmreleases hr helm.toolkit.fluxcd.io/v2 true HelmRelease
kustomizations ks kustomize.toolkit.fluxcd.io/v1 true Kustomization
alerts notification.toolkit.fluxcd.io/v1beta3 true Alert
providers notification.toolkit.fluxcd.io/v1beta3 true Provider
receivers notification.toolkit.fluxcd.io/v1 true Receiver
buckets source.toolkit.fluxcd.io/v1 true Bucket
gitrepositories gitrepo source.toolkit.fluxcd.io/v1 true GitRepository
helmcharts hc source.toolkit.fluxcd.io/v1 true HelmChart
helmrepositories helmrepo source.toolkit.fluxcd.io/v1 true HelmRepository
ocirepositories ocirepo source.toolkit.fluxcd.io/v1beta2 true OCIRepository
新しいfluxのバージョンでは開発中のコマンドとしてflux tree
があり、fluxが処理しているもののリストが見られるようです。
$ flux tree ks flux-system
Kustomization/flux-system/flux-system
├── CustomResourceDefinition/alerts.notification.toolkit.fluxcd.io
├── CustomResourceDefinition/buckets.source.toolkit.fluxcd.io
├── CustomResourceDefinition/gitrepositories.source.toolkit.fluxcd.io
├── CustomResourceDefinition/helmcharts.source.toolkit.fluxcd.io
├── CustomResourceDefinition/helmreleases.helm.toolkit.fluxcd.io
├── CustomResourceDefinition/helmrepositories.source.toolkit.fluxcd.io
├── CustomResourceDefinition/kustomizations.kustomize.toolkit.fluxcd.io
├── CustomResourceDefinition/ocirepositories.source.toolkit.fluxcd.io
├── CustomResourceDefinition/providers.notification.toolkit.fluxcd.io
├── CustomResourceDefinition/receivers.notification.toolkit.fluxcd.io
├── Namespace/flux-system
├── ResourceQuota/flux-system/critical-pods-flux-system
├── ServiceAccount/flux-system/helm-controller
├── ServiceAccount/flux-system/kustomize-controller
├── ServiceAccount/flux-system/notification-controller
├── ServiceAccount/flux-system/source-controller
├── ClusterRole/crd-controller-flux-system
├── ClusterRole/flux-edit-flux-system
├── ClusterRole/flux-view-flux-system
├── ClusterRoleBinding/cluster-reconciler-flux-system
├── ClusterRoleBinding/crd-controller-flux-system
├── Service/flux-system/notification-controller
├── Service/flux-system/source-controller
├── Service/flux-system/webhook-receiver
├── Deployment/flux-system/helm-controller
├── Deployment/flux-system/kustomize-controller
├── Deployment/flux-system/notification-controller
├── Deployment/flux-system/source-controller
├── NetworkPolicy/flux-system/allow-egress
├── NetworkPolicy/flux-system/allow-scraping
├── NetworkPolicy/flux-system/allow-webhooks
└── GitRepository/flux-system/flux-system
レポジトリの状態
パッとディレクトリとファイルだけ見ると、fluxがbootstrap時に加えた変更が確認できます。APIスコープをセットしたアクセストークンを用いてコミットされました。
$ find . -not -path "*/\.git/*" | sed -e "s/[^-][^\/]*\// |/g" -e "s/|\([^ ]\)/|-\1/"
|-clusters
| |-lab-hlv3
| | |-flux-system
| | | |-kustomization.yaml
| | | |-gotk-sync.yaml
| | | |-gotk-components.yaml
GitLab上で "settings" > "repository" > "deploy tokens" を確認してみるとread-onlyのdeploy tokenが作られていることが確認できます。bootstrap以後、fluxはこのトークンでレポジトリを監視して変更に応じてGitOpsを回していきます。
デモ
デモとして一つpodを動かします。
podのマニフェストファイルをそのまま ./clusters/lab-hlv3/demo-pod.yaml
に配置するのではなく、今回このあと紹介するレポジトリ構造に近づけていきます。
namespace
mkdir ./clusters/lab-hlv3/namespaces
cat <<'EOF' > ./clusters/lab-hlv3/namespaces/testbed.yaml
---
apiVersion: v1
kind: Namespace
metadata:
name: testbed
EOF
# commit and push
これでcommit/pushすればfluxが内容を拾い、新たなnamespace "testbed"を作ってくれます。
placeholders
続けて必要なものを一気に作っていきます。大体形を整えるためのダミーです。最後の方にデモとして動かすpodの分があります。
cat <<'EOF' > ./clusters/lab-hlv3/namespaces/placeholder.yaml
apiVersion: v1
kind: Namespace
metadata:
name: placeholder
EOF
mkdir -p ./infrastructure/lab-hlv3/configs
mkdir -p ./infrastructure/lab-hlv3/controllers
mkdir -p ./apps/base/testbed
mkdir -p ./apps/lab-hlv3
cat <<'EOF' > infrastructure/lab-hlv3/controllers/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- cm-placeholder.yaml
EOF
cat <<'EOF' > infrastructure/lab-hlv3/controllers/cm-placeholder.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: controllers-placeholder
namespace: placeholder
data:
thisis: placeholder
EOF
cat <<'EOF' > infrastructure/lab-hlv3/configs/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- cm-placeholder.yaml
EOF
cat <<'EOF' > infrastructure/lab-hlv3/configs/cm-placeholder.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: configs-placeholder
namespace: placeholder
data:
thisis: placeholder
EOF
cat <<'EOF' > apps/lab-hlv3/kustomization.yaml
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../base/testbed
EOF
cat <<'EOF' > apps/base/testbed/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deploy-tools.yaml
EOF
cat <<'EOF' > apps/base/testbed/deploy-tools.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: tools
namespace: testbed
labels:
app: tools
spec:
replicas: 1
selector:
matchLabels:
app: tools
template:
metadata:
labels:
app: tools
spec:
hostname: tools
containers:
- name: tools
image: registry.k8s.io/e2e-test-images/agnhost:2.39
imagePullPolicy: IfNotPresent
command: ["tail"]
args: ["-f", "/dev/null"]
EOF
インフラとアプリ用のflux kustomization
次の二つは紹介のところで触れる特に重要なものです。
cat <<'EOF' > clusters/lab-hlv3/infrastructure.yaml
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: infra-controllers
namespace: flux-system
spec:
interval: 1m0s
path: ./infrastructure/lab-hlv3/controllers
prune: true
wait: true
sourceRef:
kind: GitRepository
name: flux-system
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: infra-configs
namespace: flux-system
spec:
dependsOn:
- name: infra-controllers
interval: 1h
retryInterval: 1m
timeout: 5m
sourceRef:
kind: GitRepository
name: flux-system
path: ./infrastructure/lab-hlv3/configs
prune: true
EOF
cat <<'EOF' > clusters/lab-hlv3/apps.yaml
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: apps
namespace: flux-system
spec:
interval: 10m0s
dependsOn:
- name: infra-configs
sourceRef:
kind: GitRepository
name: flux-system
path: ./apps/lab-hlv3
prune: true
wait: true
timeout: 5m0s
EOF
tools podでのデモ
docker exec
などに親しみのある方は、kubernetesでも同じようなことができるのだと分かるかと思います。
以下の出力は、クラスタ内のpodでnslookupを実行した例です。このポストではkubernetes公式ドキュメントでも使われているイメージを指定していますが実環境ではdig, drill, openssl, curl, ncなどなど、ちょっとした便利コマンドをあれこれ用意したカスタムイメージを使っています。
$ kubectl exec deploy/tools -n testbed -- nslookup zenn.dev.
Server: 10.96.0.10
Address: 10.96.0.10#53
Non-authoritative answer:
Name: zenn.dev
Address: 104.26.14.203
Name: zenn.dev
Address: 172.67.72.220
Name: zenn.dev
Address: 104.26.15.203
Name: zenn.dev
Address: 2606:4700:20::681a:fcb
Name: zenn.dev
Address: 2606:4700:20::681a:ecb
Name: zenn.dev
Address: 2606:4700:20::ac43:48dc
$ kubectl exec deploy/tools -n testbed -- nslookup kubernetes.default.svc.lab.example.net.
;; Got recursion not available from 10.96.0.10
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: kubernetes.default.svc.lab.example.net
Address: 10.96.0.1
;; Got recursion not available from 10.96.0.10
GitOps レポジトリ構造の紹介
デモは以上で、GitOps用レポジトリの形についてカバーしていきます。
fluxcdのGitOpsの根っこは"flux-system"と名前付けられているflux kustomizationです。その役割は./clusters/lab-hlv3
ディレクトリ配下に配置されているkubernetesクラスタに関するマニフェストと実際のクラスタの状態を同期させるということです。
デモの冒頭で触れたとおりそこに直にpodのマニフェストを配置しても良いのですが、何でもかんでもそこに配置してしまうとすぐ手に負えなくなってしまうと思います。
そういうわけで、fluxcd公式のドキュメントとしてそもそもどのようなディレクトリ構造でレポジトリを用意したらよいかについてガイドがあります。
https://fluxcd.io/flux/guides/repository-structure/
今回のポストで紹介するものも違いはありません。公式のガイドに沿って次のようにレイヤーごとのflux kustomizationの作成および依存関係の設定をしています。
- apps ks (flux kustomization) は
./apps/lab-hlv3
ディレクトリ内のマニフェストに従ってクラスタを更新する- そして infra-configs ks に依存する
- infra-configs ks は
./infrastructure/lab-hlv3/configs
ディレクトリ内のマニフェストに従ってクラスタを更新する- そして infra-controllers ks に依存する
- infra-controllers ks は
./infrastructure/lab-hlv3/controllers
ディレクトリ内のマニフェストに従ってクラスタを更新する
$ flux get ks
NAME REVISION SUSPENDED READY MESSAGE
apps main@sha1:b1a6b397 False True Applied revision: main@sha1:b1a6b397
flux-system main@sha1:b1a6b397 False True Applied revision: main@sha1:b1a6b397
infra-configs main@sha1:b1a6b397 False True Applied revision: main@sha1:b1a6b397
infra-controllers main@sha1:b1a6b397 False True Applied revision: main@sha1:b1a6b397
つまり(1)インフラのコンポーネントを用意し、(2)それらをコンフィグし、(3)それらを基にアプリケーション、ワークロードを立ち上げるという形に整えます。
もう少し例を加えて説明
デモではpodを一つ動かしただけでしたので、cilium gateway実装状態のディレクトリを想定してもう少し説明させてください。
階層、ファイルのリストはこのセクションの最後にあります。また細かい内容については別ポストとして用意ができたらと考えています。
flux-system
Gateway API実装用のnamespaceとして"gateway" namespaceを./clusters/lab-hlv3/namespaces/gateway.yaml
として用意しました。またGateway経由で既存のtestbed namespaceに用意するサービスへのアクセスを設けるためにtestbed.yaml
にも変更を加えています。
変更をcommit/pushすればfluxがgateway namespaceの作成およびtestbed namespaceの更新を実施してくれます。
infra-controllers
fluxのGitOpsで処理されたものではないものの、ここで最初に紹介しなければいけないのはciliumのhelm chartインストール時に用いたvalues.yamlファイル、./infrastructure/lab-hlv3/controllers/values/cilium-values.yaml
です。network add-onをインストールしないとそもそもkubernetesクラスタは動作しないので、クラスタ構築後真っ先に入れましたが、クラスタに関するあらゆる情報はこのレポジトリで管理したいのでこちらに配置してあります。
この先さらにhelm chartを利用してインフラのコンポーネントを何かインストールするとなれば、こちらにvaluesファイルを配置してflux helmrepo, helmreleaseマニフェストを作成してfluxにインストールしてもらうことになります。
Cilium gateway実装に限っては、ここではGateway APIのCRDs v1.2.0を配置し、infra-controllersのkustomizationに追加しています。
infra-configs
Cilium network add-onインストール同様、GitOpsセットアップ以前にcorednsのコンフィグマップも更新していました。従ってそのマニフェストファイルも./infrastructure/lab-hlv3/configs/coredns
に格納しておきます。
ちなみに今後さらにcorednsの設定を更新するといった場合は、変更後のマニフェストを配置しinfra-configsのkustomizationに追加することになります。
そしてcilium gateway実装関連では、ここではgatewayのコンフィグ、IPAMの設定、L2広報の設定を加えています。
apps
Cilium gatewayの実装、ウェブアクセスのデモということでtraefik/whoamiイメージのdeploymentおよびserviceマニフェストを、既存のtestbed namespaceに追加しています。
Cilium gatewayとwhoamiサービスを繋ぐHTTPRoutesマニフェストは./apps/lab-hlv3/httproutes/whoami.yaml
に配置しています。(ちなみにここは./apps/base/testbed
に一緒に入れてしまって良いと思います)
アプリを別レポジトリに分ける例
最後にcilium gateway実装と無関係なところなのですが、アプリに関してはアプリ担当チームの別レポジトリで個別に管理するという形も取れるという紹介もしたく。
GitOpsのレポジトリはこういう形にもできるという紹介として./apps/base/news-logger
と./apps/base/gitlab-report
をレポジトリツリー出力に含めてあります。これら二つに関しては「別レポジトリ用のトークンを使って」「別レポジトリのどこそこのpathを参照すること」といった内容のfluxcdのマニフェストが配置してあり、コードに加えkubernetesクラスタへどうdeployするかといったことが別レポジトリ内で管理されています。
./apps/base/news-logger/repo.yaml
の例は以下の通りです。
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: news-logger
namespace: flux-system
spec:
interval: 1m0s
ref:
branch: main
secretRef:
name: NAME_OF_SECRET_CONTAINING_RO_DEPLOY_TOKEN
url: URL_OF_THE_REPO
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: news-logger
namespace: flux-system
spec:
interval: 1m0s
path: ./deploy/lab-hlv3
prune: true
sourceRef:
kind: GitRepository
name: news-logger
targetNamespace: WHICHEVER_NAMESPACE_ASSIGNED_FOR_THIS_APP
tree output
$ tree
.
|-clusters
| |-lab-hlv3
| | |-flux-system
| | | |-kustomization.yaml
| | | |-gotk-sync.yaml
| | | |-gotk-components.yaml
| | |-app.yaml
| | |-namespaces
| | | |-gateway.yaml
| | | |-placeholder.yaml
| | | |-testbed.yaml
| | |-infrastructure.yaml
|-readme.md
|-sops
|-.git
|-infrastructure
| |-lab-hlv3
| | |-configs
| | | |-kustomization.yaml
| | | |-coredns
| | | | |-cm-coredns.yaml
| | | | |-coredns-modified.yaml
| | | |-cm-placeholder.yaml
| | | |-cilium
| | | | |-ippools-cilium-gateway.yaml
| | | | |-gateway.yaml
| | | | |-l2announcement-cilium-gateway.yaml
| | |-controllers
| | | |-crds
| | | | |-gateway-api
| | | | | |-experimental
| | | | | | |-gateway.networking.k8s.io_tlsroutes-v1.2.0.yaml
| | | | | |-standard
| | | | | | |-standard-install-v1.2.0.yaml
| | | | | |-readme.md
| | | |-kustomization.yaml
| | | |-values
| | | | |-cilium-values.yaml
| | | |-cm-placeholder.yaml
| | | |-default-values
| | | | |-cilium-1.17.2-values.yaml
|-apps
| |-lab-hlv3
| | |-httproutes
| | | |-whoami.yaml
| | |-kustomization.yaml
| |-base
| | |-testbed
| | | |-kustomization.yaml
| | | |-whoami.yaml
| | | |-readme.md
| | | |-tools-deployment.yaml
| | |-news-logger
| | | |-repo.yaml
| | |-gitlab-report
| | | |-repo.yaml
Discussion