Fluxでk8sをGitOpsしてみる

はじめに
今回はコンテナ仮想化プラットフォーム「docker」のオーケストレーションツールである「Kubernetes(k8s)」の話。
k8sを運用する場合に、マニフェストだったりdockerイメージだったりをリポジトリで管理すると思うのですが、
その際に出てくる考え方がGitOpsです。
FluxはGitOpsを実現するためのツール

今回はいくつかあるツールの中でも、
GitOps提唱者であるweaveworks社が出している「Flux」を使ってみたいと思います。
(他にもArgoCDやJenkinsXなどがあります)
k8sクラスタ環境が前提となりますが「Flux」の導入はとっても簡単です。
k8sクラスタ環境の構築については以下のREADMEにまとめてあります。
では早速導入していきましょう。
前提
今回の導入環境です。
| 項目 | 値 | 備考 |
|---|---|---|
| OS | CentOS Linux release 8.1.1911 (Core) | Hyper-Vゲスト |
| CPU | 2vCPU | |
| メモリ | 8GB | |
| docker | 17.06 | |
| kubernetes | v1.18.1 | マスターノード |
| Gitリポジトリサービス | Github | https://github.com/ultimania |
fluxctlの導入
fluxのセットアップにはfluxctlというツールが必要になります。
Linuxの場合はsnapdを使ってインストールします。
dnf install epel-release dnf install snapd systemctl enable --now snapd.socket ln -s /var/lib/snapd/snap /snap
ここでsnapdを有効化するために再起動。
reboot
再起動後にfluxctlをインストール。
snap install fluxctl --classic
ちなみに再起動しないままやっちゃうと以下のエラーがおきます。
error: too early for operation, device not yet seeded or device model not acknowledged
同期先リポジトリの準備
今回は同期先のリポジトリとしてサンプルで用意されている以下のリポジトリをforkして使用します。
| サンプルリポジトリ | fork後のリポジトリ |
| https://github.com/fluxcd/flux-get-started | https://github.com/ultimania/flux-get-started |
fluxのセットアップ
flux用のnamespaceを作成。
kubectl create ns flux namespace/flux created
fluxをセットアップ。
GHUSER環境変数にはGithubのアカウント名を入れてください。
export GHUSER="ultimania"
fluxctl install \
--git-user=${GHUSER} \
--git-email=${GHUSER}@users.noreply.github.com \
--git-url=git@github.com:${GHUSER}/flux-get-started \
--git-path=namespaces,workloads \
--namespace=flux | kubectl apply -f -
serviceaccount/flux created
clusterrole.rbac.authorization.k8s.io/flux created
clusterrolebinding.rbac.authorization.k8s.io/flux created
deployment.apps/flux created
secret/flux-git-deploy created
deployment.apps/memcached created
service/memcached created
fluxctl install はfluxコンポーネントを作成するためのマニフェスト群を標準出力するコマンドです。
それを"|"(パイプ)で kubectl apply に渡しているわけですね。
なので同じ方法でkubectl deleteに渡せばすぐにuninstallできちゃいます。
fluxがインストールされていることを確認します。
kubectl get all -n flux NAME READY STATUS RESTARTS AGE pod/flux-59bc5545b-9ln86 1/1 Running 0 17m pod/memcached-5bd7849b84-9zwds 1/1 Running 0 17m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/memcached ClusterIP 10.101.159.19 <none> 11211/TCP 17m NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/flux 1/1 1 1 17m deployment.apps/memcached 1/1 1 1 17m NAME DESIRED CURRENT READY AGE replicaset.apps/flux-59bc5545b 1 1 1 17m replicaset.apps/memcached-5bd7849b84 1 1 1 17m
Runningになっており問題ないようです
fluxとGithubリポジトリとの同期
Githubとの同期をとるために、対象のリポジトリにFluxで作成した公開鍵を登録します。
公開鍵の作成
まずFluxで公開鍵を作成します。
fluxctl identity --k8s-fwd-ns flux ssh-rsa *******= root@flux-********
Githubの対象リポジトリにデプロイキーとして登録。
Githubのサイトからデプロイキーを登録します。

対象リポジトリの画面の「Setting」をクリック

左のサイドバーから「Deploy keys」をクリックし、
右上に出てくる「Add deploy key」をクリック。

登録フォームの画面で以下を入力する
すべての入力が完了したら「Add key」をクリック

デプロイキーが登録されます。
Githubの対象リポジトリとk8sクラスタを同期
現状ではまだリポジトリの中身(サンプルコンテナ)はk8sにデプロイされてません。
デフォルトではfluxは5分に1回対象リポジトリにプルしにいくみたいですが、
すぐに同期をとりたい場合は以下のコマンドを実行します。
fluxctl sync --k8s-fwd-ns flux Synchronizing with ssh://git@github.com/ultimania/flux-get-started Revision of master to apply is e38a100 Waiting for e38a100 to be applied ... Done.
ちなみに鍵がうまく登録されていなかったり、リポジトリやアカウント名が間違っており
うまく同期がとれない場合は上記コマンドが失敗します。
fluxctl sync --k8s-fwd-ns flux Error: git repository ssh://git@github.com/ultimania/flux-get-started Full error message: git clone --mirror: fatal: Could not read from rem Cloning into bare repository '/tmp/flux-gitclone047582877'... git@github.com: Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists. Run 'fluxctl sync --help' for usage.
きちんと同期がとれているかどうか確認するためにもfluxctl syncは実行しておきましょう。
サンプルコンテナがデプロイされたことを確認
うまく同期がとれたので、対象リポジトリに登録されているマニフェストにもとづいて
ローカルのk8sクラスタにコンテナがデプロイされているはずです。
確認してみましょう。
kubectl get all -n demo NAME READY STATUS RESTARTS AGE pod/podinfo-58df84dbff-gk5lc 1/1 Running 0 47s pod/podinfo-58df84dbff-vb22g 1/1 Running 0 29s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) service/podinfo ClusterIP 10.96.116.154 <none> 9898/TCP NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/podinfo 2/2 2 2 113s NAME DESIRED CURRENT READY AGE replicaset.apps/podinfo-58df84dbff 2 2 2 48s replicaset.apps/podinfo-789f8bd555 0 0 0 113s replicaset.apps/podinfo-9f6bdc7d8 0 0 0 66s
demoという名前空間にPodやらserviceやらが登録されています!
どうやら成功したみたいです。
サンプルサービスへの疎通確認
ちなみに今回デプロイされたserviceはClusterIPなので、
ポートフォワードさせて試しにアクセスしてみたいと思います。
(ブラウザからもアクセスできますが今回はcurlで)
kubectl port-forward svc/podinfo 8080:9898 -n Forwarding from 127.0.0.1:8080 -> 9898 Forwarding from [::1]:8080 -> 9898
curl localhost:8080
{
"hostname": "podinfo-58df84dbff-gk5lc",
"version": "3.1.5",
"revision": "948de81ed319b4cae86ef9758866165acd4426a2",
"color": "#34577c",
"logo": "https://raw.githubusercontent.com/stefanprodan/podinfo/gh-pages/cuddle_clap.gif",
"message": "greetings from podinfo v3.1.5",
"goos": "linux",
"goarch": "amd64",
"runtime": "go1.13.6",
"num_goroutine": "8",
"num_cpu": "2"
}簡単な情報を表示するためのロゴページみたいです。
JSONでちゃんと返してくれるあたりがいいですね。