ラズパイ Ceph を Zabbix で監視する
自宅ラボでは Cephadm を使ってラズパイに Ceph クラスタを構築して遊んでます。
今回は Ceph の Zabbix モジュールを使って Zabbix からラズパイ Ceph クラスタを監視できるようにします。 ただモジュールを有効化するだけでは Zabbix から監視できなかったので、手順を残します。
ちなみにラズパイ Ceph クラスタは CentOS/RockyLinux/AlmaLinux 各種 OS を使った混合環境です。 本当はクラスタ構築の話から投稿したかったのですが、モチベの関係で先にこのネタから投稿します。
- Zabbix モジュール有効化
- Zabbix 設定
- Ceph コンテナでは Zabbix モジュールが使えない
- ARM64 版 Ceph コンテナに zabbix_sender 追加
- Zabbix から見た Ceph
Zabbix モジュール有効化
Ceph Manager Daemon (MGR) は、モジュールという形でダッシュボード機能や他製品との連携機能を提供しています。
Cephadm 自体も「Orchestrator モジュール」を使って Ceph を管理しているようです。
公式のモジュール一覧は ここ (でいいんですかねぇ…?)
MGR のモジュールの中に「Zabbix モジュール」があるので、このモジュールを有効化して使います。
ceph mgr module enable zabbix
Zabbix モジュールのパラメータのうち、以下の 2 つを設定します。
- zabbix_host: Zabbix サーバのホスト名
- identifier: Zabbix に登録する Ceph クラスタ名
ceph zabbix config-set zabbix_host zabbix.example.com ceph zabbix config-set identifier raspi-ceph
今回はその他のパラメータはデフォルト値のまま使いました。 以下のコマンドでパラメータを確認します。
ceph zabbix config-show
または、ダッシュボードから直接有効にすることもできます。
Zabbix 設定
Ceph 用の Zabbix テンプレート ceph-mgr Zabbix module が公開されているので、Zabbix にインポートします。
Zabbix にラズパイ Ceph クラスタ監視用のホストを登録します。
このとき、ホスト名は Zabbix モジュールの identifier
パラメータと同じ文字列を設定する必要があります。
また、テンプレートに ceph-mgr Zabbix module
を指定します。
ここまで設定すれば Ceph の情報を Zabbix から見れるようになるはずですが、Zabbix には監視データが飛んできません。
Cephadm かつラズパイ (ARM) の場合は追加で対応が必要です。
Ceph コンテナでは Zabbix モジュールが使えない
Cephadm で Ceph を構築した場合、各ノードに Ceph コンテナがデプロイされます。
MON/MGR/OSD それぞれ別コンテナとして起動しますが、すべて同じイメージ quay.io/ceph/ceph が使われます。
この公式 Ceph コンテナイメージには、Zabbix モジュールが利用する zabbix_sender
コマンドが同梱されていません。
ceph/ceph-container の Issue によると、依存関係を懸念してサードパーティ製のパッケージは除外しているようです。 Issue にも書かれている通り、必要なパッケージがあれば自分でイメージに追加すれば Zabbix モジュールを使えるようになります。
ARM64 版 Ceph コンテナに zabbix_sender 追加
上述の通り、Cephadm で Zabbix モジュールを使うには zabbix_sender
コマンドをインストールした Ceph コンテナイメージを使う必要があります。
zabbix_sender
は zabbix-agent パッケージからインストールされます。
しかし残念ながら、 ARM64 向けの zabbix-agent パッケージは公開されていません。
そのため、ソースから zabbix_sender
をビルドして Ceph コンテナイメージに追加します。
以下は Dockerfile の例です。 (Dockerfile のうまい書き方があればツイッターでコメントください🙇)
ちなみにリポジトリの内容を書き換えてるのは CentOS 8: Failed to download metadata for repo 'appstream' の件があったからです。
FROM centos:centos8 AS builder RUN sed -i 's/#baseurl=http:\/\/mirror.centos.org/baseurl=http:\/\/vault.centos.org/' /etc/yum.repos.d/CentOS-Linux-AppStream.repo && \ sed -i 's/#baseurl=http:\/\/mirror.centos.org/baseurl=http:\/\/vault.centos.org/' /etc/yum.repos.d/CentOS-Linux-BaseOS.repo && \ sed -i 's/#baseurl=http:\/\/mirror.centos.org/baseurl=http:\/\/vault.centos.org/' /etc/yum.repos.d/CentOS-Linux-Extras.repo && \ yum install -y git zip automake pcre-devel gcc make && \ git clone https://git.zabbix.com/scm/zbx/zabbix.git -b 5.4.10 --depth 1 WORKDIR /zabbix/ RUN ./bootstrap.sh && \ ./configure --enable-agent --disable-dependency-tracking && \ make && \ make install FROM quay.io/ceph/ceph:v16.2.7 COPY --from=builder /usr/local/bin/zabbix_sender /usr/bin/zabbix_sender
この Dockerfile をラズパイなどの ARM64 上でビルドしたら zabbix_sender
入りの Ceph コンテナができます。
Ceph ノード内の設定ファイルを書き換えて、作成したイメージを使うように MGR の設定を変更します。 ここは正式な手順があるかもしれませんが、そこまで追えませんでした。
- /var/lib/ceph/[fsid]/mgr.ceph1.cxsytc/unit.image
- /var/lib/ceph/[fsid]/mgr.ceph1.cxsytc/unit.run
これで Zabbix に Ceph の監視データを飛ばせるようになりました。
Zabbix から見た Ceph
Zabbix モジュール & テンプレートを使った Ceph 監視データはこんな感じです。
苦労した割にあんまり使い勝手よく無さそうな…正直、Grafana のほうが見やすそう…。
2021 年振り返りと 2022 年の抱負
2021 年も残すところ数日ということで、少し早いですが今年 1 年間の振り返りと来年の抱負を掲げます。
2021 年の振り返り
Japan Rook Meetup で登壇
今年はオンライン登壇を 2 回させていただく機会がありました。
その中でも、2021/4/2 に開催された Japan Rook Meetup #5 での登壇は自分にとって大きな経験でした。 去年登壇した LT 枠では 5~10 分の発表だったのですが、Rook Meetup ではセッション枠だったため 20 分喋りました。
ひょんなことから枠をいただいたのですが、「何を喋ろうか?Rook も Ceph も初心者の域を出てないな?そもそもストレージ全然知らん!降りようかな?!もうなんとでもなれ!」みたいな葛藤がありました。
ちょうど Ceph に cephadm
という新しめの機能が追加されていたので、Rook にギリギリ関連する形でそれを紹介することでなんとか発表を終えました。
20 分の登壇をした結果、20 分も話をするためにはどれくらいの準備が必要か、という感覚が掴めたことが一番の成果だったと思います。 最近はプレゼンする機会がほとんど無くなってしまったので。
そんな登壇の資料はこちらです。 speakerdeck.com
こんな機会をいただいて、運営の皆様には本当に感謝しています。
登壇への緊張もあったのですが、運営メンバーが界隈では名を轟かせている方々ばかりだったので、その点でも震えてました。 あと、自分に kubectl を教えてくださった方が運営にいらっしゃって、一方的に感動していたりもしました。
もっと登壇したい気持ちもあったのですが、オンラインと言えど家族への負担も掛かることもあり、今年後半は控えることにしました。 発表内容のクオリティに満足いかないところもあり、もっと時間を取れる状況になったら再チャレンジしようと思います。
転職活動をはじめた(現在は休止中)
去年あたりからプライベートで Kubernetes を勉強する機会が増えました。 オンライン勉強会に参加する(視聴する)ことも多くなりました。
Kubernetes を触れば触るほど、勉強会に参加するほど、自分にはスキルが足りないことを実感し、プライベートだけでは経験値が貯まらないと痛感しました。 次第に「仕事としても Kubernetes に関わりたい」という気持ちが高まってきました。
残念ながら現職では Kubernetes どころかコンテナもほとんど使う機会がありません(使う必要がない、ということかもしれません)。 また、IT に意欲的なメンバーが(自分が観測できる範囲では)少なく、Kubernetes 関係なくスキルアップに時間が掛かりそうな環境だなと感じてしまいました。
一旦こんな考えをもってしまうと気持ちが離れてしまうのは早く、スキルアップを図れる新しい環境に身を置くために転職活動をはじめました。
LinkedIn や Wantedly などの転職サイトに登録しました。 Twitter でも「転職したい」と呟いたところ、ありがたいことにお声掛けもいただきました。 そんなこともあり、何社かカジュアル面談や面接をさせていただきました。
結局、転職先はまだ決まっておらず、そんなこんなしていたら事情が変わって直近の転職が難しくなり、来年後半くらいまでは活動休止することにしました(来年の抱負に繋がる)。
転職活動はまだ終わってないですが、途中までの感想としては「スピード感が大事」ということと、「永久フルリモート求人は少ない」ということですね。 両方とも「そんなこと当たり前だろ!」って感じですが。
スピード感は、求人が公開されてから手を挙げるスピードもですし、「いつ入社できるか」という早さも必要ということを痛感しました。
永久フルリモート求人のほうは、「フルリモートです!」と案内しておきながら話聞いたら「コロナ明けたら分かりません」って言ってくるところがあって少し萎えました。 フルリモートとは? コロナの影響でリモート勤務が増えたとは言え、永久にフルリモートな求人ってのはまだまだ少ないですね。
Azure & Kubernetes の資格を取った
去年はそこまで資格に固執していなかったですが、転職を考えだしてからは積極的に資格取得もしていきました。 オンライン受験できるものをターゲットに、今年は 3 つの資格を取りました。
- Azure Administrator Associate (AZ-104)
- Certified Kubernetes Administrator (CKA)
- Certified Kubernetes Application Developer (CKAD)
AZ-104 は落としたと思ったのですが、ギリギリ合格ラインに届いていました。 なので正直 Azure はまだまだ身についてない感が否めません。 仕事でも Azure 触ると見込んでの受験だったのですが、途中で雲行きが怪しくなり、結局今年はほとんど Azure に関われませんでした。
CKA/CKAD は Udemy の定番コースを受講したり Kubernetes 完全ガイドを読み込んだりと万全を期したので、そこそこの点数で合格しました(万全を期したのに満点ではないという矛盾)。 Kubernetes の資格を取って転職サイトの保有資格に追記したころから LinkedIn でメッセージを受け取る頻度が増えました。 近頃は Kubernetes 市場がアツそう、というのを体感しました。
Linux の資格を取ろうと 10 月くらいから Red Hat Certified System Administrator (RHCSA) 受験を考えはじめました。 受験費用は会社が負担してくれるのですが、研修費用は対象外なので IBM SkillsBuild で無料公開されている RH124/134 を受講しました。 あとは受験するだけなのですが、家族のほうとスケジュールを合わせられず、年内受験は見送りました。
2022 年の抱負
家族との時間を大切にする
来年は 4 月から 3 ヶ月ほど仕事をお休みする予定です(ナイーブな話ではないです)。
お休み中はガッツリ勉強するつもりはなく、家族と過ごすための時間として専念しようと考えています。 気分転換に自宅ラボ触るくらいになりそうです。
3 ヶ月も何もやらないと世間から完全に置いていかれそうという焦りもありますが、「家族が大事」と考えた結果です。 復帰してからは今まで以上に時間を有効活用できるように取り組みます。
転職の目処をつける
来年後半には仕事復帰して、転職活動も再開しようと思っています。
長期休暇明けてすぐ転職、っていうことに負い目を感じなくもないですが、逆に考えると「一旦引き継ぎしてるんだから大丈夫だよね?」ってことで進めます。 まぁ転職先が見つかるか次第なので、完全に取らぬ狸の皮算用です。
転職活動再開したら Twitter でつぶやくと思うので、もし「弊社フルリモート求人あるよ!」って方いらっしゃったらリプや DM ください🙇
RHCSA は休みに入る前に取っておきたいです。 あとは CKS や Azure 系の資格も年内に取れるよう計画したいところです。
総括
2021 年は気持ちの変化が大きい年でした。
2022 年は環境の変化が大きい年になるような気がするので、計画的に物事を進めたい所存です。
最後に、(主に Twitter で)絡んでくださった皆様、今年は大変お世話になりました。 来年もぜひよろしくお願いいたします。
NUC で Single Node OpenShift を触ってみよう
Red Hat が提供するエンタープライズなコンテナ・プラットフォーム「OpenShift」がシングルノードに対応したようです。
そうとなれば試してみたい欲求が抑えられませんよね?
というわけで要件を満たす機器を選定するところから SNO (Single Node OpenShift) を導入してみました。
ハードウェア要件
SNO をインストールするには以下のスペックが必要です。
普通(?) の OpenShift だとコントロールプレーンで 4 コア/16 GB、コンピュートノードで 2 コア/8 GB が最小要件となっているので、一台辺りのスペックは高くなってしまいます。 一台でコントロールプレーンとコンピュートノードの役割を担うのでそこら辺は仕方ないですね。
機器選定
上記のハードウェア要件を満たす機器を探しました。 すでに ASRock DeskMini A300 というベアボーンを導入しているのですが、今回は別の機器を検討しました。(新しいものが欲しかったので!)
DeskMini 導入時の記事はこちら。 nnstt1.hatenablog.com
結論から言うと、第 11 世代 i5-1135G7 を搭載した NUC11PAHi5 を選びました。 www.amazon.co.jp
選定基準ですが、メモリとストレージは置いといて、まずは CPU コア数をベースに考えました。 自宅ラボで有名な NUC のスペックを確認してみると、都合よくハードウェア要件を満たすモデルがありました。
11 世代 NUC には CPU が異なる 3 モデルがありますが、一番お手頃な NUC11PAHi3 (Core i3-1115G4) は 2 コア 4 スレッドのため要件を満たしません。 NUC11PAHi5 (i5-1135G7) と NUC11PAHi7 (i7-1165G7) は 4 コア 8 スレッドで要件を満たしています。
あとはお財布との相談で、NUC11PAHi5 となりました(5000 兆円あったら NUC11PAHi7 にしてた)。
最近は Minisforum というメーカーが面白そうなベアボーンを出していたのでそちらも検討したのですが、Windows 搭載モデルが多く「OS 入れ替えるのに Windows 分の費用も上乗せされてるんだよなぁ…」とか考えてるうちに候補から外れてしまいました。
NUC11PAHi5 の最大搭載可能メモリ 64 GB と、SNO のハードウェア要件を十分に満たせます。 DeskMini が 32 GB で検証環境としてはギリギリなこともあり、一気に 64 GB にしようかと思ったのですが、ここでもお財布のストップがかかって 32 GB メモリを 1 枚にしました。 いずれ 2 枚目買って 64 GB にするんだ…。
ちなみに、この記事を書いている日はアマゾンのブラックフライデー初日です。 上記メモリが安くなってないかなぁと覗いたら値上がりしてました。なんでや
ストレージは家の中で転がっていた 256 GB の SSD にしました。 m.2 の空きがあるので、いずれストレージが不足してきたら拡張する予定です。
あとは NUC には電源ケーブルが付属しないということで、アマゾンの売れ筋から見繕いました。
以上が SNO を構築するために用意したハードウェアになります。
インストール
機器の準備ができたので、早速 SNO のインストールをおこないます。 SNO に関する公式ドキュメントは以下になります。
他の環境に OpenShift をインストールするのと比べてかなりページ数が少ないのが気になりますね…。
とは言え必要十分な情報は記載されているので、ドキュメント読みながらやればこの投稿は必要ないくらい簡単にインストールできますが、この投稿を意味あるものにするためにドキュメントの手順に合わせてインストール時のスクショを載せていきましょう。
SNO 用 DNS レコード登録
唯一のソフトウェア的な要件として、SNO が利用する DNS レコードの事前登録があります。
自宅ラボでは PowerDNS を使って DNS サーバを構築しており、そこに上記のレコードを静的登録しました。
検出 ISO 生成
Red Hat Hybrid Cloud Console *3 の Install OpenShift with the Assisted Installer というページから「検出 ISO」を作成します。
ベアメタルへの OpenShift インストールには IPI (Installer-provisioned infrastructure) と UPI (User-provisioned infrastructure) の 2 通りの方法があったのですが、新しく Assisted Bare Metal Installer が登場したようです(テックプレビュー段階でした)。
検出 ISO は Hybrid Cloud Console からノードを検出できるようにするためのイメージで、USB メモリなどに焼いて SNO をインストールする機器にぶっ刺して使います。
それでは Assisted Installer のページで SNO のインストールをおこなっていきます。
まずはクラスタの情報として Cluster name
と Base domain
を入力します。
Base domain
は前項で登録した DNS レコードと合わせてください。
そして Install single node OpenShift (SNO)
にチェックを入れます。
チェックを入れると「SNO は高可用性ないですよー」「SNO にはノード追加できませんよー」という注意書きが表示されます。
また、OpenShift version
で選択できるバージョンも限定されます。
SNO をチェック入れてると上記画像のとおり 4.8.12 と 4.9.0 が選択できましたが、チェックを外すと 4.6.16 も選択可能となりました。(2021/11/9 時点)
4.7 はどこいったんだ?という疑問はひとまずスルーして、クラスタの情報を入力したら「Next」です。 次ページの「Generate Discovery ISO」から検出 ISO のイメージをダウンロードできます。
「Generate Discovery ISO」をクリックするとポップアップが表示されます。 ここでは「フル」と「最小」のどちらのイメージをダウンロードするか選択し、SNO にアクセスするための SSH 公開鍵を登録します。 今回は「フルイメージ」を選択しました。
ポップアップの「Generate Discovery ISO」をクリックすると準備中となり、
しばらく待つとダウンロード可能になります。
URL を見るとイメージは S3 に格納されているようです(AWS 詳しくないので合ってるか不安…)。 「Download Discovery ISO」をクリックして検出 ISO をダウンロードします。 検出 ISO のサイズは約 1 GB (今回は 987 MB) でした。
ダウンロードしたイメージを USB メモリなどに焼きます。 今回は Raspberry Pi Imager を使いましたが、問題なく SNO ノードで起動することができました。
USB メディアを使用したインストール
検出 ISO の準備ができたら、NUC に USB メモリを刺して電源を入れます。 USB からブートする設定になっていれば、Hybrid Cloud Console 上に検出されたノードの情報が表示されます。 検出直後は Hostname と Status の項目が警告になっています。
Hostname は「localhost」が使えないということらしいので変更します。
Hostname を変更すると Status の警告も無くなりました。
最後にネットワークの設定をおこないます。
SNO のネットワークは User-Managed Networking
しか選択できない状態となっています。
Available subnets
に SNO ノードが利用できるサブネットが表示されます。
今回は自宅ラボ用ネットワーク 192.168.1.0/24
に繋いでいたのですが、その情報も取得されてプルダウンに表示されていました。
サブネットを選択すると Status が Ready となり、ネットワーク関連の情報も表示されました。
最後に設定内容をレビューして問題なければ、いよいよ SNO がインストールされます。
インストール進行状況も Hybrid Cloud Console から確認できます。
今回のインストールでは途中でインストールが停止してしまいました。 インストール途中に NUC が再起動されたのですが、「BIOS のブートを USB 起動に設定」かつ「USB メモリ挿しっぱなし」という状況だったため、検出 ISO が再度起動してしまったことが原因でした。 上記のどちらかを対処すればインストールが再開します。
無事にインストール完了しました!
これで NUC 一台で OpenShift を稼働させることができました。 あとは kubeconfig をダウンロードしてクラスタに繋いだり、コンソールにアクセスして GUI で Operator を入れたり、OpenShift ならでは検証ができるようになります。
その他
OpenShift の評価版
「Red Hat Developer Suite」という Red Hat 製品のいくつかを無料で使える素晴らしいサブスクリプションがあります。
上記のページで OpenShift も対象っぽい記載があるので「太っ腹じゃん!」と思いながら今回の SNO 構築を決めたのですが、どうやら OpenShift は対象外のようで評価版という形で SNO は使うことになりました。
評価版と言っても期間は 60 日間で、クラスタを再インストールしたら再度 60 日に巻き戻ったので遊ぶ分には十分かなという感じです。
kubeadmin のパスワード
インストールで作成される管理ユーザ「kubeadmin」で oc login
しようとしたのですが、パスワードがなかなか見つかりませんでした。
Hybrid Cloud Console のクラスタページの「Installation progress」の左にある > マークをクリックすると…
こんなところに隠れていました。
結構探したよ…。
ルート証明書
インストール直後のコンソールにブラウザでアクセスしても、証明書エラーとなりログイン画面にすら辿り着けませんでした。
SNO のページではないですが、OpenShift のドキュメントにルート証明書を変更する手順はありました。 しかし今回はそのままのルート証明書でアクセスするようにしました。
oc get secret router-ca -n openshift-ingress-operator -o jsonpath='{.data.tls\.crt}' | base64 -d > router-ca.crt
というコマンドで証明書を抽出して、クライアント PC にインストールしました。
これでコンソールにもアクセスできるようになりました。
所感
自分が初めて OpenShift を触ったのは 4.2 くらいのときで、やれブートストラップノードが必要だの、やれ Ignition がどうだのと、勉強にはなったのですが中々つらい気持ちもありました。
それに比べて SNO (Single Node OpenShift) のインストールはとても簡単でした(Assisted Installer のおかげ?)。 もっとヒィヒィ言いながらインストールさせてくれてもよかったのに…って気持ちも湧きそうなくらいです。
わざわざ NUC で OpenShift 用意して自宅でなにするよって疑問も残ってますが、kubeadm で作ったクラスタと比較しながら Kubernetes の勉強に使えればよいですね。
SNO の中で各コンポーネントがどのように動いているか等は改めて投稿したいと思います。
何はともあれ、OpenShift を気軽に触れる環境が自宅にあるというのはとても精神衛生上よろしいので、ぜひこれを読んだ人も SNO やってみてはどうでしょう。
*1:https://cloud.redhat.com/blog/deploy-openshift-at-the-edge-with-single-node-openshift
*2:https://access.redhat.com/documentation/ja-jp/openshift_container_platform/4.9/html/installing/minimum-resource-requirements_installing-bare-metal
*3:Red Hat Insights で提供されるサイトのようです。Ansible Automation Platform とも連携できるようなのでいつか試してみたい。rheb.hatenablog.com
AWX Operator を使って外部 PostgreSQL と連携する AWX をデプロイ
Ansible AWX バージョン 18.0 から AWX Operator を使うインストール方法に変更されました。
AWX Operator を使うと Kubernetes クラスタへの AWX デプロイが簡単にできます。
標準的な設定では AWX 関連のコンテナをまとめた Pod と一緒に PostgreSQL Pod もデプロイされますが、今回は AWX Operator 管理外の PostgreSQL インスタンスと連携するように AWX をデプロイします。
環境情報
ソフトウェア | バージョン |
---|---|
Kubernetes | 1.21.2 |
AWX | 19.3.0 |
AWX Operator | 0.13.0 |
Zalando Postgres Operator | 1.6.3 |
AWX Operator
AWX Operator は公式の マニュアル 手順通りにインストールしていきます。
特筆する点はないのでマニュアルを参照してください。
PostgreSQL
AWX で利用する PostgreSQL インスタンスは Zalando Postgres Operator を使って用意します。
Operator のインストール方法は下記の投稿を参照してください。
以下の postgresql
リソースのマニフェストで、AWX 用の PostgreSQL インスタンスがデプロイされます。
apiVersion: acid.zalan.do/v1 kind: postgresql metadata: labels: team: acid name: acid-awx namespace: awx spec: allowedSourceRanges: [] databases: awx: awx numberOfInstances: 1 postgresql: version: '13' resources: limits: cpu: 500m memory: 500Mi requests: cpu: 100m memory: 100Mi teamId: acid users: awx: [] volume: size: 10Gi patroni: pg_hba: - local all all trust - hostssl all +zalandos 127.0.0.1/32 pam - host all all 127.0.0.1/32 md5 - hostssl all +zalandos ::1/128 pam - host all all ::1/128 md5 - hostssl replication standby all md5 - hostssl all +zalandos all pam - hostssl all all 0.0.0.0/0 md5 - host all all 0.0.0.0/0 md5
postgresql
リソースでデプロイされる registry.opensource.zalan.do/acid/spilo-13
コンテナは pg_hba.conf
が以下のようになっています。
# Do not edit this file manually! # It will be overwritten by Patroni! local all all trust hostssl all +zalandos 127.0.0.1/32 pam host all all 127.0.0.1/32 md5 hostssl all +zalandos ::1/128 pam host all all ::1/128 md5 hostssl replication standby all md5 hostnossl all all all reject hostssl all +zalandos all pam hostssl all all all md5
この状態では AWX コンテナからアクセスできないため、上記のように spec.patroni.pg_hba
で定義します。
また、postgresql
マニフェストでは StorageClass を指定するか、クラスタの StorageClass にデフォルト設定をしておきます。
$ kubectl get storageclass NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE local-storage kubernetes.io/no-provisioner Delete WaitForFirstConsumer false 69d rook-ceph-block (default) rook-ceph.rbd.csi.ceph.com Delete Immediate true 12d
うまくデプロイできると以下のリソースが作成されています。
$ kubectl get pods,svc,secret,pvc NAME READY STATUS RESTARTS AGE pod/acid-awx-0 1/1 Running 0 2d pod/awx-operator-69c646c48f-cgkbl 1/1 Running 2 8d NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/acid-awx ClusterIP 10.107.168.117 <none> 5432/TCP 2d service/acid-awx-config ClusterIP None <none> <none> 2d service/acid-awx-repl ClusterIP 10.104.194.254 <none> 5432/TCP 2d service/awx-operator-metrics ClusterIP 10.105.177.117 <none> 8383/TCP,8686/TCP 8d NAME TYPE DATA AGE secret/awx-operator-token-8rdhp kubernetes.io/service-account-token 3 8d secret/awx-postgres-configuration Opaque 7 2d secret/awx.acid-awx.credentials Opaque 2 2d secret/default-token-m56vf kubernetes.io/service-account-token 3 8d secret/postgres.acid-awx.credentials Opaque 2 2d secret/standby.acid-awx.credentials Opaque 2 2d NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE persistentvolumeclaim/pgdata-acid-awx-0 Bound pvc-d47938d5-fd94-4bcb-865f-467fd8647b82 10Gi RWO rook-ceph-block 2d
このうち、secret/awx.acid-awx.credentials
に AWX から PostgreSQL にアクセスするための認証情報が格納されているので、以下のコマンドで確認しておきます。
$ kubectl get secret awx.acid-awx.credentials -o jsonpath='{.data.password}' | base64 -d
AWX
PostgreSQL インスタンスを用意できたら AWX をデプロイします。
必要なものは AWX Operator が参照する AWX
リソースと Secret
リソースのマニフェストです。
apiVersion: awx.ansible.com/v1beta1 kind: AWX metadata: name: awx namespace: awx spec: admin_user: admin admin_password_secret: awx-admin-password ingress_type: ingress ingress_tls_secret: awx-secret-tls hostname: awx.k8s.nnstt1.work postgres_configuration_secret: awx-postgres-configuration
AWX
リソースの spec
で AWX の各種設定をおこないます。
今回は Ingress の設定、admin ユーザと外部 PostgreSQL の設定を格納した secret の指定をおこないました。
Secret
リソースでは、上記の secret を作成します。
apiVersion: v1 kind: Secret metadata: name: awx-admin-password namespace: awx stringData: password: password --- apiVersion: v1 kind: Secret metadata: name: awx-postgres-configuration namespace: awx stringData: host: acid-awx port: "5432" database: awx username: awx password: oqIgEGDuCDG40LI2tIQ4OdIUtdKFGiLDkAbUiCyrZgMnKFSTZrQsQmihtTnOkvdH sslmode: prefer type: unmanaged type: Opaque
stringData
は Zalando Postgres Operator で構築した PostgreSQL インスタンスの情報を記載します。
stringData.type
には unmanaged
を指定します。
この値により、AWX Operator が「PostgreSQL インスタンスを自前で構築する」か「外部 PostgreSQL を参照する」かを判断します。
(「Secret リソースの内容で Operator の挙動を変える」って仕様がよろしくなさそうに感じたんですがどうなんでしょう?)
上記のマニフェストを Apply することで、AWX Operator がいい感じに AWX をデプロイしてくれます。
うまく AWX から PostgreSQL にアクセスできたら初期構築が始まります、そこそこ時間が掛かるようなので気楽に待ちましょう。 自分の環境では 15 分ほど掛かかりました。
初期構築も完了したら Ingress 経由でアクセスします。 今回のマニフェストでは AWX へのアクセスは Ingress 経由になるため、NGINX Ingress Controller などを使ってクラスタで Ingress を使えるように事前に準備しておいてください。
AWX のログイン画面が表示できたらデプロイ成功です。 お疲れさまでした。
NGINX Ingress controller + MetalLB で Ingress の IP アドレスがうまく払い出されなかった話
NGINX Ingress Controller と MetalLB を使った Ingress の構築に失敗していた話です。
背景
自宅ラボの Kubernetes クラスタでは、NGINX Ingress Controller
と MetalLB
をデプロイしています。
これらを使って、Ingress リソースに NGINX Ingress Controller 向け LoadBalancer Service の External-IP を割り当てて、各種サービスを Ingress 経由で公開しています。
一方、Kubernetes クラスタとは別に自宅ラボ用の DNS サーバを構築しており、夏季休暇中に CoreDNS
から PowerDNS
に入れ替える作業をしました(この話は別途投稿したいと思います)。
するとどうでしょう、DNS サーバの入れ替え作業後に Ingress で公開していたサービスに接続できなくなってしまいました。
状況
Ingress リソースを確認したところ、設定されている IP アドレスが想定していたアドレスと異なっていました。 想定アドレスは上述の通り「NGINX Ingress Controller 向け LoadBalancer Service の External-IP」です。
しかし、実際には「Kubernetes クラスタの Worker Node の IP アドレス」が設定されていました。
$ kubectl get ingress -A NAMESPACE NAME CLASS HOSTS ADDRESS PORTS AGE argocd argocd-server-ingress <none> argocd-ingress.k8s.nnstt1.work 192.168.2.29 80, 443 22h monitoring grafana <none> grafana.k8s.nnstt1.work 192.168.2.29 80 20h monitoring k8s <none> prometheus.k8s.nnstt1.work 192.168.2.29 80 20h sandbox sample-app <none> sample-app.k8s.nnstt1.work 192.168.2.29 80, 443 20h # 192.168.2.29 は Worker Node の IP アドレス
Node Port のように Worker Node の IP アドレスでアクセスしても NGINX Ingress Controller のサービスには到達できないため、Ingress で指定したサービスにも接続できていませんでした。
原因
根本的な原因は、NGINX Ingress Controller の引数に --publish-service
を設定できていなかったことでした。
調査のため Ingress や NGINX Ingress Controller を消しては作り直しを繰り返したのですが、最終的には GitHub の こちらの Issue を見つけたことで原因を特定できました。
自宅ラボの Kubernetes クラスタでは NGINX Ingress Controller 公式ドキュメントの ベアメタル向け Installation Guide を参照し、ベアメタル向けのマニフェスト を使って Ingress Controller をデプロイしていました。
しかし、ベアメタル向けのマニフェストは「MetalLB を使ってベアメタルでも LoadBalancer Service を使えるようにしている環境」向けではないため、--publish-service
の引数が設定されていませんでした。
MetalLB を使っている場合は --publish-service
が記載されている Cloud 向けのマニフェスト を使うほうがよさそうです。
NGINX Ingress Controller の引数に --publish-service
をつけることで、無事に LoadBalancer の External-IP が割り当てられるようになりました。
# 説明箇所のみ抜粋 apiVersion: apps/v1 kind: Deployment metadata: name: ingress-nginx-controller spec: template: spec: containers: - name: controller image: k8s.gcr.io/ingress-nginx/controller:v0.48.1@sha256:e9fb216ace49dfa4a5983b183067e97496e7a8b307d2093f4278cd550c303899 args: - /nginx-ingress-controller - --election-id=ingress-controller-leader - --ingress-class=nginx - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller - --validating-webhook=:8443 - --validating-webhook-certificate=/usr/local/certificates/cert - --validating-webhook-key=/usr/local/certificates/key - --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller # この行を追加
--publish-service とは
NGINX Ingress Controller 公式ドキュメントの Command line arguments ページ に記載があります。
Service fronting the Ingress controller. Takes the form "namespace/name". When used together with update-status, the controller mirrors the address of this service's endpoints to the load-balancer status of all Ingress objects it satisfies.
(機械翻訳) Ingressコントローラの前にあるサービス。 "namespace/name"という形式をとる。 update-statusと一緒に使用すると、コントローラは、このサービスのエンドポイントのアドレスを、満足するすべてのIngressオブジェクトのロードバランサステータスにミラーリングします。
NGINX Ingress Controller に --publish-service
を付けなかった場合、今回のように Worker Node の IP アドレスが Ingress リソースに割り当てられるようですね。
このページをしっかり読んでいれば、今回の事象は防げていたはずです。
そもそも何で今までアクセスできていたの?
なんと、DNS サーバの入れ替え前(CoreDNS を使っていたとき)は、DNS サーバの /etc/hosts に直接 Ingress 用の DNS レコードを記述していたのです。
$ cat /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.2.244 argocd-ingress.k8s.nnstt1.work 192.168.2.244 grafana.k8s.nnstt1.work 192.168.2.244 prometheus.k8s.nnstt1.work 192.168.2.244 sample-app.k8s.nnstt1.work
元々 Ingress Controller を正しく設定できていなかったので、ワークアラウンド的に無理やり名前解決させていたようですね(他人事)。
それが PowerDNS への入れ替え時に /etc/hosts を綺麗に整理したことで名前解決できなくなり、Ingress 経由のサービスにアクセスできない事象が発生しました(正確には元々繋がらない設定だった)。
教訓
趣味でワークアラウンドな対応は(極力)しない。
ドキュメントはちゃんと読もう(N 回目の登場)。
MinIO Operator を試してみた(インストール編)
(2021/5/18 追記) Operator のインストールしかしてないじゃん、ってことでタイトル変更しました。 実際に Operator で構築した Minio を試して、続編として投稿したいと思います。
前回の投稿から 3 ヶ月ほど空いてしまいました。
その間に、誕生日に Japan Rook Meetup で登壇したり…
本日の登壇資料です。改めてありがとうございました! #japanrookhttps://t.co/WZzoEYEnku
— ののし (@nnstt1) April 2, 2021
CKA (Certified Kubernetes Administrator) の資格を取ったり…
CKA 受かりました!俺たちの Kubernetes はこれからだ!完 pic.twitter.com/ivkWe9FxzG
— ののし (@nnstt1) May 3, 2021
したのですが、まったくブログにアウトプットできてませんでした。
現在は CKAD (Certified Kubernetes Application Developer) に向けて勉強中なのですが、裏で MinIO Operator を触ってみたので気晴らしに久しぶりの投稿をします。
MinIO とは
MinIO は、Amazon S3 互換のオープンソースオブジェクトストレージです。
プライベート/ハイブリッドクラウドの標準オブジェクトストレージとなることを前提とした設計のようです。
そのためか、公式サイトではファイルシステムやブロックストレージには結構キツい物言いをしている感じがします(個人の感想です)。
ハイブリッドクラウドストレージは、パブリッククラウドで確立されたモデルに従い、パブリッククラウドプロバイダーは全会一致でクラウドネイティブオブジェクトストレージを採用しています。
パブリッククラウドの成功により、ファイルとブロックストレージは事実上時代遅れになりました。
すべての新しいアプリケーションは、POSIXではなくAWS S3API用に作成されています。
クラウドネイティブテクノロジーのようにスケーリングして実行するには、古いアプリケーションをS3 API用に書き直し、コンテナ互換になるようにマイクロサービスにリファクタリングする必要があります。
また、かつて Rook (v1.2)でもストレージプロバイダとして MinIO が対象となっていたのですが、残念ながら現在は対象外となってしまったようです。
ちなみに、MinIO の読み方は「ミン・アイオー」のようです(ミニオって言ってしまってました…)。
MinIO Operator
そんな MinIO を Kubernetes にデプロイして運用までしてくれる MinIO Operator がリリースされたようです。
今回は公式リポジトリの手順に沿って MinIO Operator をインストールして、オブジェクトを格納するためのテナントを作成するところまで試してみます。
前提条件
MinIO Operator のインストール、およびテナント作成の前提条件は以下の 4 つです。
Kubernetes クラスタのバージョンが 1.17.0 以上であること
1.17.0 未満だったら Kubernetes 公式を参照してアップグレードします。
今回使用したクラスタは v1.21.0 のため、そのまま使用します。
$ kubectl version Client Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.0", GitCommit:"cb303e613a121a29364f75cc67d3d580833a7479", GitTreeState:"clean", BuildDate:"2021-04-08T16:31:21Z", GoVersion:"go1.16.1", Compiler:"gc", Platform:"linux/amd64"} Server Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.0", GitCommit:"cb303e613a121a29364f75cc67d3d580833a7479", GitTreeState:"clean", BuildDate:"2021-04-08T16:25:06Z", GoVersion:"go1.16.1", Compiler:"gc", Platform:"linux/amd64"}
Kubernetes クラスタに MinIO テナント用の namespace があること
MinIO Operator はテナント毎に namespace を使用します。
今回は検証用の
minio-tenant-1
namespace を作成します。
$ kubectl create namespace minio-tenant-1 namespace/minio-tenant-1 created
Kubernetes クラスタに
volumeBindingMode: WaitForFirstConsumer
の StorageClass があることMinIO Operator は
volumeBindingMode: WaitForFirstConsumer
の StorageClass にデータを格納します。 今回使用する Kubernetes クラスタには Rook/Ceph が導入済みのため、Rook/Ceph を使って MinIO Operator 用の StorageClass を作成します。
apiVersion: ceph.rook.io/v1 kind: CephBlockPool metadata: name: minio-pool namespace: rook-ceph spec: failureDomain: host replicated: size: 3 requireSafeReplicaSize: true --- apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: minio-rook-ceph-block provisioner: rook-ceph.rbd.csi.ceph.com parameters: clusterID: rook-ceph pool: replicapool imageFormat: "2" imageFeatures: layering csi.storage.k8s.io/provisioner-secret-name: rook-csi-rbd-provisioner csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph csi.storage.k8s.io/controller-expand-secret-name: rook-csi-rbd-provisioner csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph csi.storage.k8s.io/node-stage-secret-name: rook-csi-rbd-node csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph csi.storage.k8s.io/fstype: ext4 allowVolumeExpansion: true reclaimPolicy: Delete volumeBindingMode: WaitForFirstConsumer
Krew がインストールされていること
MinIO Operator は kubectl コマンドラインツールの
Krew
を使用してインストールします。以下のサイトを参照して Krew をインストールします。
インストール
Krew を使って MinIO Operator をインストールしていきます。
$ kubectl krew update Updated the local copy of plugin index. $ kubectl krew install minio Updated the local copy of plugin index. Installing plugin: minio Installed plugin: minio \ | Use this plugin: | kubectl minio | Documentation: | https://github.com/minio/operator/tree/master/kubectl-minio | Caveats: | \ | | * For resources that are not in default namespace, currently you must | | specify -n/--namespace explicitly (the current namespace setting is not | | yet used). | / / WARNING: You installed plugin "minio" from the krew-index plugin repository. These plugins are not audited for security by the Krew maintainers. Run them at your own risk.
MinIO プラグインをインストールできたら、Operator を初期構築します。
$ kubectl minio init namespace/minio-operator created serviceaccount/minio-operator created clusterrole.rbac.authorization.k8s.io/minio-operator-role created clusterrolebinding.rbac.authorization.k8s.io/minio-operator-binding created customresourcedefinition.apiextensions.k8s.io/tenants.minio.min.io created service/operator created deployment.apps/minio-operator created serviceaccount/console-sa created clusterrole.rbac.authorization.k8s.io/console-sa-role created clusterrolebinding.rbac.authorization.k8s.io/console-sa-binding created configmap/console-env created service/console created deployment.apps/console created ----------------- To open Operator UI, start a port forward using this command: kubectl minio proxy -n minio-operator -----------------
上記出力の通り、proxy 経由で MinIO Operator の管理画面にアクセスできるようになります。
$ kubectl minio proxy -n minio-operator Starting port forward of the Console UI. To connect open a browser and go to http://localhost:9090 Current JWT to login: eyJhbGciOiJSUzI1NiIsImtpZCI6Ii0zbFc4cm51LXNPTWliSUVOYXdTNmI3ejRWeWRuVEF0dU9aenpKY0xaNGMifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJtaW5pby1vcGVyYXRvciIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJjb25zb2xlLXNhLXRva2VuLWJmNDZyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImNvbnNvbGUtc2EiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI3ZDgwZDNjOS0wMzUyLTRjNDItOWQ5Yy0xM2I3ZDg2ZjA4OWIiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6bWluaW8tb3BlcmF0b3I6Y29uc29sZS1zYSJ9.F8XsI2buT71U4QUi7tfShaDYAOs0rcgjPmZO5HiJYyWYZ0ZYN5LDZbIRf4il23CGRjGVUWksKsfeUqRFD0iG2lP21WxvTgIbUov3DbZtItB3Sj1dO4xI5WH7PLjyYAyE5eYGRQwd3K0qSpaexh4cKsG8vj5pxzd8g-f6vwWjE1Co7Ax83PzP_ATmNnOWVQE-6lI287QijtH-PfdK3UEHM1d1WU67yvei0YGLTyMgC3t6F8xKwqay0B2OLEUGirDcq74xZA5qB_Ipuvys5K05nOCKbQiWujv0J_gyyaEAwszRpGc4Gy8Mrc-bhAYe7EGLh8_BoQiwJ2d4UVcBEuEmmw Forwarding from 0.0.0.0:9090 -> 9090
ブラウザで kubectl minio proxy
コマンドを実行しているサーバにアクセスするとログイン画面が表示されるので、コマンド実行時に出力された文字列を入力してログインします。
テナント作成
次に、MinIO Operator を使ってテナントを作成します。
デプロイされる Pod やストレージサイズを指定するオプションがあるのですが、クラスタと相談のうえ設定してください。
$ kubectl minio tenant create minio-tenant-1 \ --servers 1 \ --volumes 4 \ --capacity 4Gi \ --namespace minio-tenant-1 \ --storage-class minio-rook-ceph-block Tenant 'minio-tenant-1' created in 'minio-tenant-1' Namespace Username: admin Password: ac8a676c-d4a3-4cb0-98b9-c432f3c9cd5c Note: Copy the credentials to a secure location. MinIO will not display these again. +-------------+------------------------+----------------+--------------+--------------+ | APPLICATION | SERVICE NAME | NAMESPACE | SERVICE TYPE | SERVICE PORT | +-------------+------------------------+----------------+--------------+--------------+ | MinIO | minio | minio-tenant-1 | ClusterIP | 443 | | Console | minio-tenant-1-console | minio-tenant-1 | ClusterIP | 9443 | +-------------+------------------------+----------------+--------------+--------------+
これでオブジェクトを格納するためのテナントが完成しました。
自分の環境では、テナントを正常に作成できた状態では以下のリソースが作られていました。
$ kubectl get secret -n minio-tenant-1 NAME TYPE DATA AGE default-token-ntlzm kubernetes.io/service-account-token 3 2m24s minio-tenant-1-console-secret Opaque 4 2m22s minio-tenant-1-console-tls Opaque 2 62s minio-tenant-1-creds-secret Opaque 2 2m22s minio-tenant-1-tls Opaque 2 2m2s operator-tls Opaque 1 2m17s operator-webhook-secret Opaque 3 2m17s $ kubectl get pods -n minio-tenant-1 NAME READY STATUS RESTARTS AGE minio-tenant-1-console-6b7488946f-2mvkf 1/1 Running 0 2m43s minio-tenant-1-console-6b7488946f-6djht 1/1 Running 0 2m43s minio-tenant-1-ss-0-0 1/1 Running 0 3m43s $ kubectl get csr NAME AGE SIGNERNAME REQUESTOR CONDITION minio-tenant-1-console-minio-tenant-1-csr 17s kubernetes.io/legacy-unknown system:serviceaccount:minio-operator:minio-operator Approved,Issued minio-tenant-1-minio-tenant-1-csr 77s kubernetes.io/legacy-unknown system:serviceaccount:minio-operator:minio-operator Approved,Issued operator-minio-operator-csr 4m5s kubernetes.io/legacy-unknown system:serviceaccount:minio-operator:minio-operator Approved,Issued $ kubectl get tenant -n minio-tenant-1 NAME STATE AGE minio-tenant-1 Initialized 4m43s
ちなみに、--volumes
が 4 未満だった場合、エラーとなります。
$ kubectl minio tenant create minio-tenant-1 \ --servers 1 \ --volumes 3 \ --capacity 3Gi \ --namespace minio-tenant-1 \ --storage-class minio-rook-ceph-block Error: pool #0 setup must have a minimum of 4 volumes per server
サーバ 1 台につき 4 ボリュームが必要なようです。
注意点
テナント作成時にユーザ情報が表示されますが、このとき表示される Password は再度表示することができないので、必ず控えておいてください。
また、万人に該当する注意点ではないかもですが、自分の環境では Operator の処理が遅く、上記のユーザ情報が表示されたあともテナントに必要なリソースがすべてデプロイされていませんでした。
厳密に言うと、minio-tenant-1-tls
Secret が作成されなかったため、Secret をマウントできずに Pod が起動してきませんでした。
原因は不要な CSR リソースが存在していたことで、テナント作成時にデプロイされるべき CSR リソースがすでに存在していたため、minio-tenant-1-tls
Secret が作成されなかったのだと推測しています。
この不要な CSR リソースは、テナント作成時のオプションを失敗して何度かテナント作成をやり直していたことで残っていたと思われます。
テナントを作成する際には CSR リソースも確認しておいたほうが良さそうです。
外部公開用サービス
ここまでの手順では Kubernetes クラスタ外のアプリケーションから MinIO テナントに接続するサービスがデプロイされていません。 そのため、Ingress や Load Balancer が必要です。
今回は MinIO テナント用の Load Balancer を作成します。
クラスタには MetalLB と ExternalDNS をデプロイ済みで、LoadBalancer を作成するとクラスタ外から接続可能な IP アドレスが振られて、 クラスタ外の DNS にレコードを登録してくれます。
外部から接続するサービスは minio
と console
の 2 種類があります。
MinIO
こちらは実際にオブジェクトストレージを操作するための API と GUI を提供するサービスです。
テナント作成時に表示された admin ユーザでログインします。
apiVersion: v1 kind: Service metadata: namespace: minio-tenant-1 name: minio-loadbalancer labels: component: minio-tenant-1 annotations: external-dns.alpha.kubernetes.io/hostname: minio-tenant-1.nnstt1.work. # ExternalDNS 用アノテーション spec: type: LoadBalancer ports: - port: 9000 targetPort: 9000 protocol: TCP selector: v1.min.io/tenant: minio-tenant-1
Console
こちらは MinIO Operator と同時にリリースされた MinIO Console という管理ツールです。
テナントの管理や状態監視をおこなえます。 ログインは同じく admin ユーザを使用します。
ログインすると管理ポータルが表示されます。
apiVersion: v1 kind: Service metadata: namespace: minio-tenant-1 name: console-loadbalancer annotations: external-dns.alpha.kubernetes.io/hostname: minio-console.nnstt1.work. # ExternalDNS 用アノテーション spec: type: LoadBalancer ports: - name: https-console port: 9443 protocol: TCP targetPort: 9443 selector: v1.min.io/console: minio-tenant-1-console
アンインストール
作成したテナントを削除し、MinIO Operator をアンインストールしてみます。
テナント削除も MinIO Operator アンインストールも kubectl minio
コマンドを使用します。
テナント
kubectl minio tenant delete
で削除するテナントを指定します。
ここで指定する tenant リソースは namespace 毎に作成されるため、-n
オプションで対象の namespace を指定してください。
# テナント削除 $ kubectl minio tenant delete minio-tenant-1 -n minio-tenant-1 This will delete the Tenant minio-tenant-1 and ALL its data. Do you want to proceed?: y Deleting MinIO Tenant minio-tenant-1 Deleting MinIO Tenant Credentials Secret minio-tenant-1-creds-secret Deleting MinIO Tenant Console Secret minio-tenant-1-console-secret # namespace 確認 $ kubectl get pods -n minio-tenant-1 No resources found in minio-tenant-1 namespace. $ kubectl get secret -n minio-tenant-1 NAME TYPE DATA AGE default-token-swx2m kubernetes.io/service-account-token 3 2d
MinIO Operator
kubectl minio delete
で MinIO Operator がアンインストールされます。
$ kubectl minio delete Are you sure you want to delete ALL the MinIO Tenants and MinIO Operator?: y namespace "minio-operator" deleted serviceaccount "minio-operator" deleted clusterrole.rbac.authorization.k8s.io "minio-operator-role" deleted clusterrolebinding.rbac.authorization.k8s.io "minio-operator-binding" deleted customresourcedefinition.apiextensions.k8s.io "tenants.minio.min.io" deleted service "operator" deleted deployment.apps "minio-operator" deleted serviceaccount "console-sa" deleted clusterrole.rbac.authorization.k8s.io "console-sa-role" deleted clusterrolebinding.rbac.authorization.k8s.io "console-sa-binding" deleted configmap "console-env" deleted service "console" deleted deployment.apps "console" deleted
アンインストールはあっさりですね。
おわりに
今回は Amazon S3 互換のオブジェクトストレージ MinIO の オペレータ MinIO Operator
を試してみました。
MinIO 自体、Kubernetes にとても簡単にデプロイできるため Operator が活躍する場面はまだ見えてませんが、 そもそも MinIO を使い込んでいないので、色々試してみようと思います。
本来は Operator は簡単にインストールできるのですが、注意点の節でも述べた CSR リソースの件でかなり時間を持っていかれました。 なかなか思うようにできないですね。 だけど、今回の件で CSR リソースのことを注意するようになったのでヨシ!
全然関係ないですが、MinIO のロゴってかっこいいですよね。フラミンゴかな?
Kubernetes クラスタのバックアップツール Velero を試してみた
Kubenews #8 を視聴していたら Velero というツールの話題が出て、そういえば試そうと思って手付かずのままだったなぁと思い出し、試せるのはいつになるかなぁと Twitter で呟いたら「今でしょ!」とも言われたので、Velero を試してみました。
Velero とは
Velero は、Kubernetes クラスタのリソースと永続データをバックアップ、リカバリ、移行するためのツールです。 VMware のプロジェクトとして管理されており、VMware Tanzu (VMware の Kubernetes 製品群) の一員です。
Velero は Kubernetes クラスタに対して以下のような使い方ができます。
Velero の特徴としては、Kubernetes API を使ってバックアップ・リストアをする API-driven な点があります。 他の Kubernetes 用バックアップツールはクラスタ内の etcd を直接参照してバックアップ・リストアするようで、その点が異なります。
API-driven なバックアップツールには以下のようなメリットがあります。
- 名前空間、リソースタイプ、ラベルによってバックアップ・リストア対象を柔軟に選択可能
- マネージド K8s クラスタの場合、etcd を直接参照できずバックアップ・リストアできないことがあるが、API 経由なら可能
- 別の etcd にリソースが保存されていてもバックアップ・リストア可能
正直なところ、3点目はどのような場合を想定しているのか理解できていません…。
また、Velero は Kubernetes のリソースだけでなく、永続データもバックアップ・リストアの対象とすることができますが、今回はリソースを対象にしたバックアップ・リストアのみ試しています。
オブジェクトストレージの用意
Velero はバックアップデータをオブジェクトストレージに格納します。
Amazon S3 や Azure Blob Storage といったクラウドサービスとしてのオブジェクトストレージを使ってもよいのですが、今回はオンプレ環境の K8s クラスタ内に2種類のオブジェクトストレージを用意しました。
対応しているストレージプロバイダの一覧は以下に記載されていますが、今回使用する S3 互換のオブジェクトストレージは十分なテストはされていない点は要注意です。
MinIO
まずは S3 互換のオブジェクトストレージとしてよく使われているであろう MinIO です。(今回、初めて存在を知りました…)
MinIO の場合は Velero 公式サイトに参考手順が載っています。
上記手順でも使われていますが、公式リポジトリに K8s クラスタに MinIO をデプロイするサンプルマニフェストが用意されています。
今回はこちらのサンプルマニフェストを一部変更して MinIO を用意しました。
変更箇所は kind: Service
に対する以下の2点です。
- ExternalDNS 用に
external-dns.alpha.kubernetes.io/hostname
アノテーションを付与 spec.type: ClusterIP
からspec.type: LoadBalancer
へ変更
以下は変更済みサンプルマニフェストのデプロイ結果です。
$ kubectl apply -f examples/minio/00-minio-deployment.yaml $ kubectl get all -n velero NAME READY STATUS RESTARTS AGE pod/minio-5b84955bdd-2qh6f 1/1 Running 0 26h pod/minio-setup-nfcjq 0/1 Completed 0 26h NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/minio LoadBalancer 10.103.161.124 192.168.2.244 9000:31475/TCP 26h NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/minio 1/1 1 1 26h NAME DESIRED CURRENT READY AGE replicaset.apps/minio-5b84955bdd 1 1 1 26h NAME COMPLETIONS DURATION AGE job.batch/minio-setup 1/1 13s 26h
service/minio
は type: LoadBalancer に変更したため External-IP が振られており、 ExternalDNS による DNS 登録もされている状態です。
デプロイから数分待てば、アノテーションで指定したホスト名で MinIO のサービスにアクセスできるようになります。
ExternalDNS については以下の記事を参考にしてください。
Rook Ceph
もう一つは、Rook Ceph のオブジェクトストレージです。
既にクラスタ用のブロックストレージとして Rook Ceph は使っていたのですが、オブジェクトストレージとしての利用はしていなかったので今回を機に用意してみました。
Rook Ceph オブジェクトストレージのデプロイには、公式ドキュメントと以下の記事を参考にしました。
$ kubectl apply -f rook/cluster/examples/kubernetes/ceph/object-test.yaml $ kubectl apply -f rook/cluster/examples/kubernetes/ceph/storageclass-bucket-delete.yaml $ kubectl apply -f rook/cluster/examples/kubernetes/ceph/object-bucket-claim-delete.yaml
既に Rook が入っていれば、これだけでオブジェクトストレージが使えるようになります。
が、自分の環境では OBC (Object Bucket Claim ) の status が Pending からずっと変わらない事象が発生しました。 (正しく動けば Bound になるはず)
Pending の状態だからオブジェクトストレージとしては使えないだろう、と思い数日原因を探っていたのですが、結局分からないままでした。
試しに Rook 公式ドキュメントに記載されている s3cmd
を使ってテストしたところ、Pending の状態でもオブジェクトの格納や取得はできてしまいました。
今回の検証は上記のような状態でおこなっていますが、後日ちゃんと対応しようと思います。
また本筋から逸れますが、なぜ MinIO 以外のオブジェクトストレージを用意したのかというと「K8s クラスタ上に MinIO をデプロイしても内部では Rook Ceph のブロックストレージを使うためオーバーヘッドが掛かるのでは」と考えたからです。
Ceph のアーキテクチャ図を見ると分かりやすいのですが、Ceph 自体は RADOS (Reliable Autonomic Distributed Object Store) というオブジェクトストアを土台として構築し、その上で S3 互換オブジェクトストレージの RADOSGW
や ブロックストレージの RDB
、ファイルストレージの CephFS
が動いています。
そのため、MinIO を使って K8s クラスタ内にオブジェクトストレージを構築しても、Rook Ceph の StorageClass (ブロックストレージ) を使っていては「オブジェクトストレージ on ブロックストレージ on オブジェクトストア」のようになってしまうのでは、RADOSGW を使ってオブジェクトストレージを使ったほうが性能が良いのでは、と考えました。
考えました……。
が、執筆時に MinIO のサンプルマニフェストを見返して気付いたのですが、MinIO の volumes では emptyDir を使っていました。 つまり、Rook Ceph のブロックストレージを使っていませんでした。
最初に試した MinIO のデプロイは上記サンプルのものではなく別の方のマニフェストを参考にしていて、そちらでは PVC を使っていたので Rook Ceph を使っているものと勘違いしたまま考察してしまいました。
上記の考察は、Velero 公式リポジトリの MinIO サンプルマニフェストでは意味がないです。
こちらも後日 PVC を使った MinIO を用意して RADOSGW との性能差を測定をしてみます。
Velero を試す
オブジェクトストレージの用意ができたので、いよいよ Velero を試してみます。
インストール
Velero を K8s クラスタにインストールする方法は以下の2通りあります。
- velero コマンドを使った
velero install
- Helm chart
今回は、velero コマンドを Linux クライアント環境にインストールする方法で試しました。 (Helm に苦手意識があるので…)
まずは velero コマンドを準備します。
Mac や Windows だと Homebrew や Chocolatey といったパッケージマネージャが使えるのですが、Linux のため公式からバイナリをダウンロードしてきました。
velero
ファイルを PATH の通ったとこに配置するだけで完了です。
次に、オブジェクトストレージの認証情報を記載したファイル (./credentials-velero) を用意します。
[default] aws_access_key_id = minio aws_secret_access_key = minio123
上記の認証情報は MinIO (サンプルマニフェスト)の場合ですが、Rook Ceph の場合は以下のコマンドで認証情報を取得できます。
$ kubectl get secret ceph-delete-bucket -o jsonpath='{.data.AWS_ACCESS_KEY_ID}' | base64 --decode $ kubectl get secret ceph-delete-bucket -o jsonpath='{.data.AWS_SECRET_ACCESS_KEY}' | base64 --decode
velero コマンドの準備ができたらクライアントから velero install
すればよいのですが、MinIO と Rook Ceph の場合でバケット名や s3Url など微妙に異なるので、適宜変更してください。
- MinIO
$ velero install \ --provider aws \ --plugins velero/velero-plugin-for-aws:v1.0.0 \ --bucket velero \ --secret-file ./credentials-velero \ --use-volume-snapshots=false \ --backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://minio.minio.svc:9000
- Rook Ceph
$ velero install \ --provider aws \ --plugins velero/velero-plugin-for-aws:v1.0.0 \ --bucket ceph-bkt-c71df44b-8657-4f02-b680-fe0894debc07 \ --secret-file ./credentials-velero \ --use-volume-snapshots=false \ --backup-location-config region=us-east-1,s3ForcePathStyle="true",s3Url=http://rook-ceph-rgw-my-store.rook-ceph.svc
namespace: velero
に velero Pod がデプロイされていればインストール完了です。
バックアップ
Velero 公式リポジトリに用意された Nginx のサンプルマニフェストを使って、バックアップ・リストアの確認をします。
# テスト用リソースの準備 $ kubectl apply -f https://github.com/vmware-tanzu/velero/blob/main/examples/nginx-app/base.yaml $ kubectl get deployments -l component=velero --namespace=velero NAME READY UP-TO-DATE AVAILABLE AGE velero 1/1 1 1 24h $ kubectl get all --namespace=nginx-example NAME READY STATUS RESTARTS AGE pod/nginx-deployment-57d5dcb68-tks6f 1/1 Running 0 24h pod/nginx-deployment-57d5dcb68-wd456 1/1 Running 0 24h NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/my-nginx LoadBalancer 10.101.167.57 192.168.2.242 80:32308/TCP 24h NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/nginx-deployment 2/2 2 2 24h NAME DESIRED CURRENT READY AGE replicaset.apps/nginx-deployment-57d5dcb68 2 2 2 24h # バックアップ $ velero backup create nginx-backup --selector app=nginx Backup request "nginx-backup" submitted successfully. Run `velero backup describe nginx-backup` or `velero backup logs nginx-backup` for more details. # バックアップリソースの確認 $ velero backup get NAME STATUS ERRORS WARNINGS CREATED EXPIRES STORAGE LOCATION SELECTOR nginx-backup Completed 0 0 2021-02-13 00:05:24 +0900 JST 29d default app=nginx
無事にバックアップは取れたようです。
リストア
Velero によるバックアップが成功したら、サンプルリソースを削除してバックアップデータからリストアできるか確認します。
# テスト用リソースの削除 $ kubectl delete namespace nginx-example namespace "nginx-example" deleted $ kubectl get all --namespace=nginx-example No resources found in nginx-example namespace. # リストア $ velero restore create --from-backup nginx-backup Restore request "nginx-backup-20210213000816" submitted successfully. Run `velero restore describe nginx-backup-20210213000816` or `velero restore logs nginx-backup-20210213000816` for more details. # リストアリソースの確認 $ velero restore get NAME BACKUP STATUS STARTED COMPLETED ERRORS WARNINGS CREATED SELECTOR nginx-backup-20210213000816 nginx-backup Completed 2021-02-13 00:08:16 +0900 JST 2021-02-13 00:08:16 +0900 JST 0 0 2021-02-13 00:08:16 +0900 JST <none> $ kubectl get all --namespace=nginx-example NAME READY STATUS RESTARTS AGE pod/nginx-deployment-57d5dcb68-tks6f 1/1 Running 0 29s pod/nginx-deployment-57d5dcb68-wd456 1/1 Running 0 29s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/my-nginx LoadBalancer 10.109.90.104 192.168.2.242 80:30316/TCP 29s NAME DESIRED CURRENT READY AGE replicaset.apps/nginx-deployment-57d5dcb68 2 2 2 29s
一部リストアもできたようですが、Deployments だけがリストアできていません。
これは Nginx サンプルマニフェストで Deployments にラベルが設定されておらず、バックアップ対象のリソースとして選択されなかったからです。 Nginx サンプルマニフェストを弄ってラベルをつけてあげると、ちゃんとバックアップ・リストアされるようになりました。
おわりに
今回は Kubernetes クラスタのバックアップツール Velero
を試してみました。
Velero 自身はとても簡単に使えるのですが、オブジェクトストレージへの理解が低いためか、オブジェクトストレージの準備にとても時間が掛かってしまいました。 記事もオブジェクトストレージ中心で Velero はオマケ程度になってしまいました。
また、K8s クラスタ内にオブジェクトストレージを用意したため、クラスタが壊れてしまったらバックアップデータも吹き飛ぶ構成となっています。 ちゃんとバックアップとして利用するためには外部ストレージが必要ですので、自宅でも別途ストレージを用意してみたい気持ちが出てきましたので、お財布と相談してみます。