kubenews#57 Cloud Nativeなニュース - プロダクト紹介縛り
本記事はkubenewsの第57回目のゲスト枠で参加するRyuSAのコンテンツです。
なお、本登壇および本記事はあくまで 私自身の見解 であり、私の所属団体・企業における立場、戦略、意見を代表するものではありません。
Markdoc
Stripe社の公開したドキュメントをMarkdownで書くためのOSSです。利用できるMarkdownはGitHub Flavored……でありつつも一部AsciiDoc的に似た拡張を使ってドキュメントを記述できます。そのため多くのエンジニアが普段から書き慣れているMarkdownを使ってドキュメントのメンテナンスを行うことができます。
--- title: What is Markdoc? --- # {% $markdoc.frontmatter.title %} {% #overview %} Markdoc is a Markdown-based syntax and toolchain for creating custom documentation sites. Stripe created Markdoc to power [our public docs](http://stripe.com/docs). {% callout type="check" %} Markdoc is open-source—check out its [source](http://github.com/markdoc/markdoc) to see how it works. {% /callout %} ## How is Markdoc different? Markdoc uses a fully declarative approach to composition and flow control, where other solutions… [Read more](/docs/overview). ## Next steps - [Install Markdoc](/docs/getting-started) - [Explore the syntax](/docs/syntax)
またNext.jsやReactなどと組み合わせて複雑なビルドやレイアウトのごにょごにょができたりと、拡張の方法はかなり自由のため社内WikiのGit管理などに使えるような気がします。
Talos Linux
Kubernetes"専用"のOS……え??専用???となりますがそんな不思議なOSがTalos Linux。このLinuxディストリビューションはコンテナ向けOSLinuxのひとつで、特にKubernetesを起動/運用するためのものです。OSにSSHすることはできず、設定はすべてはtalosctl
を使ったAPI経由で行うことになります。
Talos LinuxはDockerで起動することが可能で、手元でサクッと動作検証することができます。
個人的に好みなのは、このOS自体がメモリ上で展開できるためサーバーがステートフルになることを防ぐことができます。PXEブートなどにも当然対応しているため、Raspberry Piなどが活躍するワークロード(IoTや誤自宅勢とか)にはとても便利なんじゃないかなと思います。
trivy
超便利だったので共有したい、というだけ……
23:22:35 ryusa@TUNA-KAN:~/develop/local/kubenews#57 $ trivy kubernetes --report summary cluster 2022-07-13T23:22:54.708+0900 INFO Need to update DB 2022-07-13T23:22:54.708+0900 INFO DB Repository: ghcr.io/aquasecurity/trivy-db 2022-07-13T23:22:54.708+0900 INFO Downloading DB... 32.96 MiB / 32.96 MiB [---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------] 100.00% 19.91 MiB p/s 1.9s 141 / 141 [----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------] 100.00% 7 p/s Summary Report for admin@talos-default ┌─────────────┬──────────────────────────────────────────────────────────────┬────────────────────┬────────────────────┬───────────────────┐ │ Namespace │ Resource │ Vulnerabilities │ Misconfigurations │ Secrets │ │ │ ├───┬───┬───┬────┬───┼───┬───┬───┬────┬───┼───┬───┬───┬───┬───┤ │ │ │ C │ H │ M │ L │ U │ C │ H │ M │ L │ U │ C │ H │ M │ L │ U │ ├─────────────┼──────────────────────────────────────────────────────────────┼───┼───┼───┼────┼───┼───┼───┼───┼────┼───┼───┼───┼───┼───┼───┤ │ kube-system │ Role/system::leader-locking-kube-scheduler │ │ │ │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ kube-system │ Role/system::leader-locking-kube-controller-manager │ │ │ │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ kube-system │ Deployment/coredns │ 1 │ 1 │ │ │ │ │ │ 3 │ 5 │ │ │ │ │ │ │ │ kube-system │ DaemonSet/kube-flannel │ │ 6 │ 8 │ 6 │ 2 │ │ 2 │ 9 │ 30 │ │ │ │ │ │ │ │ kube-system │ Role/system:controller:cloud-provider │ │ │ │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ kube-system │ Role/system:controller:token-cleaner │ │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ │ │ kube-system │ Role/system:controller:bootstrap-signer │ │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ │ │ kube-system │ DaemonSet/kube-proxy │ 6 │ 8 │ 2 │ 57 │ │ │ 2 │ 4 │ 10 │ │ │ │ │ │ │ │ kube-system │ Service/kube-dns │ │ │ │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ kube-public │ Role/system:controller:bootstrap-signer │ │ │ │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ │ ClusterRole/cluster-admin │ │ │ │ │ │ 2 │ │ │ │ │ │ │ │ │ │ │ │ ClusterRole/system:controller:namespace-controller │ │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ │ │ │ ClusterRole/system:controller:job-controller │ │ │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ │ │ ClusterRole/system:controller:endpointslice-controller │ │ │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ │ │ ClusterRole/system:controller:root-ca-cert-publisher │ │ │ │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ │ ClusterRole/system:kube-scheduler │ │ │ │ │ │ │ 2 │ │ │ │ │ │ │ │ │ │ │ ClusterRole/admin │ │ │ │ │ │ 3 │ 7 │ 1 │ │ │ │ │ │ │ │ │ │ ClusterRole/system:controller:endpoint-controller │ │ │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ │ │ ClusterRole/system:controller:resourcequota-controller │ │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ │ │ │ ClusterRole/system:controller:replicaset-controller │ │ │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ │ │ ClusterRole/system:controller:generic-garbage-collector │ │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ │ │ │ ClusterRole/edit │ │ │ │ │ │ 2 │ 7 │ 1 │ │ │ │ │ │ │ │ │ │ ClusterRole/system:aggregate-to-edit │ │ │ │ │ │ 2 │ 7 │ 1 │ │ │ │ │ │ │ │ │ │ ClusterRole/system:controller:deployment-controller │ │ │ │ │ │ │ 2 │ │ │ │ │ │ │ │ │ │ │ ClusterRole/system:controller:horizontal-pod-autoscaler │ │ │ │ │ │ 2 │ │ │ │ │ │ │ │ │ │ │ │ ClusterRole/system:controller:persistent-volume-binder │ │ │ │ │ │ 1 │ 2 │ │ │ │ │ │ │ │ │ │ │ ClusterRole/system:controller:expand-controller │ │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ │ │ │ ClusterRole/system:controller:replication-controller │ │ │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ │ │ ClusterRole/system:aggregate-to-admin │ │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ │ │ │ ClusterRole/system:controller:endpointslicemirroring-contro- │ │ │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ │ │ ller │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ClusterRole/system:kube-controller-manager │ │ │ │ │ │ 5 │ 2 │ │ │ │ │ │ │ │ │ │ │ ClusterRole/system:node │ │ │ │ │ │ 1 │ │ │ │ │ │ │ │ │ │ │ │ ClusterRole/system:controller:cronjob-controller │ │ │ │ │ │ │ 2 │ │ │ │ │ │ │ │ │ └─────────────┴──────────────────────────────────────────────────────────────┴───┴───┴───┴────┴───┴───┴───┴───┴────┴───┴───┴───┴───┴───┴───┘ Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN
う、美しい……!(jsonでのレポートもできるので自動化もしやすいたすかる)
Trivy Operator
というそんなTrivyのOperatorについても紹介、要するに↑をKubernetes内部からチェックしてくれるとても素晴らしいOperator。CRとしてPodや各種設定の脆弱性を出力してくれます。
00:14:21 ryusa@TUNA-KAN:~/develop/local/kubenews#57 $ kubectl apply -f https://raw.githubusercontent.com/aquasecurity/trivy-operator/v0.1.3/deploy/static/trivy-operator.yaml customresourcedefinition.apiextensions.k8s.io/vulnerabilityreports.aquasecurity.github.io created customresourcedefinition.apiextensions.k8s.io/configauditreports.aquasecurity.github.io created customresourcedefinition.apiextensions.k8s.io/exposedsecretreports.aquasecurity.github.io created customresourcedefinition.apiextensions.k8s.io/clusterconfigauditreports.aquasecurity.github.io created customresourcedefinition.apiextensions.k8s.io/clusterrbacassessmentreports.aquasecurity.github.io created customresourcedefinition.apiextensions.k8s.io/rbacassessmentreports.aquasecurity.github.io created namespace/trivy-system created serviceaccount/trivy-operator created clusterrole.rbac.authorization.k8s.io/trivy-operator created clusterrole.rbac.authorization.k8s.io/aggregate-config-audit-reports-view created clusterrole.rbac.authorization.k8s.io/aggregate-exposed-secret-reports-view created clusterrole.rbac.authorization.k8s.io/aggregate-vulnerability-reports-view created clusterrolebinding.rbac.authorization.k8s.io/trivy-operator created role.rbac.authorization.k8s.io/trivy-operator created rolebinding.rbac.authorization.k8s.io/trivy-operator created role.rbac.authorization.k8s.io/trivy-operator-leader-election created rolebinding.rbac.authorization.k8s.io/trivy-operator-leader-election created secret/trivy-operator created secret/trivy-operator-trivy-config created configmap/trivy-operator created configmap/trivy-operator-trivy-config created configmap/trivy-operator-policies-config created Warning: would violate PodSecurity "restricted:latest": runAsNonRoot != true (pod or container "trivy-operator" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "trivy-operator" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost") deployment.apps/trivy-operator created service/trivy-operator created 00:21:19 ryusa@TUNA-KAN:~/develop/local/kubenews#57 $ kubectl create deployment nginx --image nginx:1.16 Warning: would violate PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "nginx" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "nginx" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "nginx" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "nginx" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost") deployment.apps/nginx created 00:22:10 ryusa@TUNA-KAN:~/develop/local/kubenews#57 $ kubectl get vulnerabilityreports -o wide NAME REPOSITORY TAG SCANNER AGE CRITICAL HIGH MEDIUM LOW UNKNOWN replicaset-nginx-7f597d689d-nginx library/nginx 1.16 Trivy 32s 38 74 57 119 1
現在の最新バージョンで用意されているのは - clusterconfigauditreports - clusterrbacassessmentreports - configauditreports - exposedsecretreports - rbacassessmentreports - vulnerabilityreports の6つのリソース、雑に環境に放り込んでおくだけでそれっぽくなりそうな予感
Sigstore
ソフトウェアのサプライチェーンを防ぐための仕組みを考えよう!という実験的なプロジェクト Sigstoreは - cosign - Fulcio - Rekor の3つのソフトウェアを組み合わせて機能でき、最終的な目的としては「アーティファクトをキーレスで署名して、その署名を改竄できないログとして保存して、アーティファクトを公開する」ことです。これにより、だれでもアーティファクトが正しく署名されていることを検証することができつつ鍵の管理が不要なので色々幸せになれそうな予感……!
残念ながら手元のWindows環境ではなぜかうまく動かなかった&話するとかなり長くなるので詳細は先人の神資料を参考に……
OCIイメージに対しての署名もできる一方、当然普通にバイナリにも署名ができるのでJavaのGradleやRubyのRubyGemsなどでIssueとしてあがっています。Sigstoreが広がって、すべてのソフトウェアのサプライチェーンを守れるようなそんな世界が来るといいですね。
とあるYouTube Streamerのファンサイトを作った話
この活動は自分個人の趣味であり、所属する企業や組織の立場、戦略、意見を代表するものではありません。
こんなの作ってました。たのしかった(小並感
リリースしてからしばらく経ったので、少し技術的な選定の話とかをまとめておきます。尖ったことはあまりしてないのでアレですが……🤔
Question. そもそもなんで作ったの?
Answer. 久しぶりにフロントエンド作りたかったから🤪
ここ最近はKubernetesやDNSなどのインフラストラクチャーばかり触ってたので、たまにはリフレッシュしたいな〜と……
要件と技術選定を進める
今回の要件はこんな感じでした。個人プロジェクトなので自分中心で楽しくやりたいってのが理由ですね。
- まだ触ったことがないものに挑戦したい
- 個人開発である以上モチベを維持しやすいように新しいものに触れることを前提に
- 安く早く済ませたい
- 言わずもがな
- マネージドなサーバーを持ちたくない
- 管理したくない(怠惰
- ホットなコンテンツを相手にする以上、もしかしたらスパイクが発生するかも……?(という想定訓練は大事)
- デプロイ自動化が可能
- 令和ですよ?Continuous Deploymentくらいは標準搭載ですよね??
- 万が一怒られた際にロールバックがスムーズにできるようにする(これから怒られる可能性はまだありますので、怒られたら速攻で消します)
- ガイドラインを読む(超大事)
- 趣味の範囲のプロダクトだしプラットフォームにも準拠するようにするし……
- 二次創作ガイドライン | ホロライブプロダクション
- ガイドラインを読む(大事なことなので(ry
- ガイドラインを読む(超大事なことなので(ry
ということを前提に技術選定を進めました。
プラットフォーム
まずはプラットフォームの選定。今回のコンテンツ的には静的なもので十分(=バックエンドで動的にコンテンツを生成する必要がない)のでサーバーどころかLambdaすら不要。単純なSPA等の静的ファイル配信ができればOKです。
そこで今回はNetlifyかVercelかCloudflare Pagesのいずれかをプラットフォームとして使おうかなと🤔Netlify / Vercel / Cloudflare Pages はいずれもフロントエンドホスティングサービスで、ReactやVueなどで作ったSPAなどをホスティング&CDN配信してくれるとても素敵なサービスたちです。……が、実はNetlifyはかつて使ったことがあり、いろんなところで話題に聞くVercelが気になったので今回はまったく触ったことがないVercelでホストすることに決めました👀ごめんねCloudflare Pages
ドメイン名とか証明書とか
このファンサイトは二次創作のプロダクトであり、万が一ご本家様とドメイン名争奪戦が起こっては大変なので自分のドメインryusa.app
からのサブドメインを切り出しました。
Vercelは、ホスティングサイトなので当然ではありますがカスタムドメインを利用してサイトを公開することができます。
自分のryusa.app
はGoogle Domainsで用意しているドメインなので、GoogleのDNSにVercel向けのCNAMEだったりTXTレコードだったりを登録してVercel側にドメインの登録を完了しました。超簡単。
……ちなみにVercelにドメインの登録をすると、自動的にLet’s EncryptでTLS証明書を発行してくれるようになります。マジでなにも考えなくてもTLS証明書がホストされるようになります。超簡単。
言語とか
今回はTypeScript/Reactベースで実装することを決定しました。最初は今アツいSvelteで行こうかと思いましたが、React 18がちょうど出たタイミングだったので波に乗るなら今だ!!と思って今回はReactベースにしました。Svelteはまた今度ね……🥰また最初はSPAとしてビルドしようと思っていましたが、フロントエンドの規模的にそこまで大きくなく、かつ動的なAPI呼び出しも発生しないことを踏まえると静的ビルドで十分と判断し、今回はまだ触ったことのないGatsbyを利用することにしました。
ちなみに、実装中に検証としてExperimentalで公開されてるReactのServer Componentも触ってみましたがかなり良さげでした。そこまでコストかけずにバンドルサイズを減らせるのは強い……!ただ今回は検証の時間がそこまでなかったので見送り……
CI/CD
GitHub ActionでビルドしてVercel側で自動デプロイ……というのが当初の予定でしたが、実はそもそもVercel側にGitリポジトリをfetchして自動ビルドをかける機能が存在しているんですよね。自分は知らなかったのですが、Vercelにはリポジトリを連携するとリポジトリの中身をチェックして自動的にビルドコマンドとデプロイコマンドを生成してくれる神機能が付いていました。
実装周りとか
そんな難しいことしてないし特に書くものなくね??と思っていましたが、個人的に気を配ったことだけ……
IEのサポートを、しない
力強く!
日本はやたらIEシェアが高いらしいですが、別にお仕事でもないプライベートプロジェクトなのでIE対応はしませんでした。React 18からIEのサポートも切れることですしIEそのものも消えますし、まぁ妥当かなと。
(IEを除く)ブラウザシェア上位 95% を(目安に)サポートする
ファンサイトとしてホストする以上、モダンブラウザをサポートしておかないと場合によっては他の熱心なファンが応援できない可能性があります。「(レイアウト崩れを見て)なんだよーFirefoxはサポートしてくれないのかー」となっては悲しいですし、せっかくの盛り上がりに水を差してしまうでしょう。ということで今回はChromeを始めとしてブラウザシェア95%に入るブラウザをサポートすることを目標に動作検証を行いました。なのでCSSのsvh
や@layer
などの超モダンな機能群が使えなくて少し悲しいところではありましたが……
業務ではモダンブラウザサポートなんて当然の作業ですが、個人プロジェクトで動作検証しっかりやったのは初めてでしたね……一部環境の動作検証にお手伝いいただいた方々には、改めてこの場で感謝を。ありがとうございました!(iPhone民/Samsung民)
まとめ
Vercelとフロントエンド周りのエコシステムが本当に充実しており、CI/CDの環境をサクッと構築できるおかげで手元で開発して本番デプロイまでが数分でできる世界観でした。ブランチで本番環境にデプロイするアセットを管理できるので、これであれば大規模なフロントエンド開発チームでの開発フローにも導入できそうです。
今度Cloudflare Pagesも使ってみる予定なので、もしタイミングがあれば具体的なNetlify / Vercel / Cloudflare Pages の比較ができるかもしれないですね👍
最後に、お手伝いいただけたみなさんありがとうございました。wappaさんも素敵なイラストを提供&OGP画像作成ありがとうございました。
久しぶりの人目に触れるプロダクトを公開し、いろんな人からの感想がもらえたのはすごく励みになりました👏ありがとうございました!
あいあいじぇいを退職します👋
エンジニアもすなる退職ブログといふものを……
2022年3月31日を最終出社日として、株式会社インターネットイニシアティブを退職します👏 新卒で入社してちょうど4年間、大変お世話になりました。
退職ブログを書いてみようと筆を走らせてみたものの、思いのほかたくさん書けそうになく……ですが、せっかくなので少しだけですが、将来の自分のためにもエントリーを残しておきます
IIJでどんなことしていたの
僕はIIJのとある金融サービスの部署のエンジニアとして仕事をしていました。最終的な肩書きがただの「エンジニア」なのは、それはそれでちょっぴり寂しい気もする……ww
主な業務内容としては次のようなものに携わってきました。
- アプリケーション開発
- フロントエンド
- バックエンド
- インフラ開発
- AWS関連
- Kubernetes
- プラットフォームエンジニア的なやつ
……おぉ、こうやって並べてみると専門領域がフワッフワしてるなぁw スキルセット的にはインフラ領域1に対してアプリケーション3……ぐらいの立ち位置ですね🤔
最初はアプリケーションエンジニアとして金融システムを開発し、その後インフラに近い領域からプラットフォームエンジニア的な立ち位置で開発メンバーの補佐や技術検証などをやってきました。とはいえ今でも自分の一番の専門と言える領域はアプリケーション開発ですね。コーディング楽しい🤪
メイン業務とは若干外れますが、IIJのブログにこんなネタを投稿していました。多々反響もらえて(特にKubernetesネタ)非常に楽しかったですw
Why 退職?
退職する主な理由は、転職するからです。(?🤔?)
新しい環境で挑戦してみたいな〜と考えていた矢先、とあるクラウドベンダーさんとお仕事する機会があったので挑戦してみようと思い転職を決めました。やっぱりね、刺激が欲しいんですよww
おそらく今の環境に残っていても様々なキャリア、技術面を磨くことはできるとは思いますが……それはあくまでもIIJという会社から見える世界でのみ、やっぱり一度外に出てみたいなと思うわけです。
最後に
4年間、面倒を見てくださったメンバーに最大限の感謝を。たくさん尻拭いしてくださり本当に感謝しております。この4年間は、自分にとって大切な4年間になりました👏
また社内に転がっている様々なコミュニティ(IIJ Bootcamp GitHub - iij/bootcamp: Bootcamp ハンズオンで使用する資料集 とか)での会話も非常に楽しかったです。気軽に困ったことや技術ネタをネットミームとともに盛り上がれる場があるのは、なんというかすごくIIJらしさを感じてますw
とはいえ退職するからと言って人が変わるわけでもなく、今後もTwitter等で元気よく自生しておりますので
ではでは👋
技術書典 #12で「Java開発 for Kubernetes」を頒布します🎉
はじめての技術同人誌ですが、がんばります💪
どんな書籍?
「次のプロジェクトでは、DockerとKubernetesでクラウドネイティブだ!」 ……なーんて話を聞かされて、困っている開発者の人はいませんか?
アプリケーションの実行環境をコンパクトにまとめた隔離環境「コンテナ」 コンテナを自在にデプロイし面倒くさい管理を自動化できるエコシステム「Kubernetes」
大コンテナ時代を迎えようとしている今、どのようにJavaでアプリケーションを書き、どのように開発フローを回し、どのように運用/監視していくのか、ざっくり表面だけ舐め回すことができるコンテンツを集めました。 JavaのWebアプリケーションとしてSpring Bootを使いながら、実際にコマンドを叩いてアプリケーションをコンテナにしてKubernetesにデプロイする開発フローを体験してみましょう!
という感じの本です。つまるところ「Kubernetes上で動かすコンテナアプリケーションを開発するにあたって、どんなツールがあったり嬉しいものがあったりするの?」ってのをざっくりをまとめたエッセンス本です。注意していただきたいのは「これを読めばKubernetes完全に理解できる!」タイプの本ではないです。マジでアプリケーションサイド目線の話しか書いていません。なのでインフラの話はほぼ出てきません。
コンテンツ
- 含まれているもの
- コンテナの概要説明
- Kubernetesの概要説明
- コンテナのための開発フロー体験
- 開発ヘルパーツールの紹介とざっくり使い方
- 運用のために覚えておくこと
- これらのサンプルコード
- 含まれていないこと
- Kubernetesのバックエンド(kubeadmとかkubeletとか)
- インフラの話(OSとかCNIとかコンテナランタイムとか)
ターゲットとなる人
主に開発者、特にJava/Spring Bootの開発を行なっている人にとっては良い本だと思っています。またJavaで書かれたワークロードをメンテナンスするぜ!という(広義での)SREの方も読んでおくとアプリケーション開発者と会話しやすいかもしれないです。
自分はアプリケーション開発者である一方でCKA等も取得しKubernetes完全にわからんを通過してきた身でもあります。その背景を元に「こんな情報が横断的にあったら嬉しかったのにな〜」というものをかき集めてました。すいません、実は書ききれてないです物理的な予算が足りなかったです。
ということで、買って💕
電子書籍版は1000円、電子書籍+物理本セットも1000円で頒布しています!一応別の場所でも頒布する予定はありますが、お値段上がったり電子版/物理本いずれか……など、セットでは購入できなくなると思います。
GitLab OperatorはGitLab運用の自動化の夢を見るか
注意 : GitLab Operatorは10月9日現在まだv0.1.0のリリースがあったばかりです。本番環境への適用にはまーだ早いのでご注意してください🤔
–– さぁ、GitLab OperatorでGitLab運用の自動化をはじめよう!!
背景
GitLabはおそらく多くのエンジニア、組織で利用されているGitリポジトリ管理ツールです。しかし、GitLabには多様な機能が日々追加されており今やGitLabはただのGitリポジトリツールではなくっている……と個人的に思っています。
GitLabのIssue/Milestoneをはじめ、MavenやコンテナイメージのリポジトリやKubernetes Integrationなど多様なコミュニケーション機能や開発者向けの機能が追加されています。GitLabに求められる可用性は日々上がっている一方、ますます複雑になるGitLab運用は人間の手でやりたくないですよね。
そこで使えるのがGitlab Operator、Helmに次ぐ新しい"Cloud Native"なGitlabホスト方法です。
全体像
検証環境
AWSのEKS上で実施します。ただEKS専用の機能を使う部分は限定的なため、他のKubernetes環境でも同じように起動することができるはずです。
apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: ryusa-gitlab version: "1.21" # 後述のExternalDNSとcert-managerをRoute53で管理するためのIRSAを定義 iam: withOIDC: true serviceAccounts: - metadata: name: external-dns namespace: external-dns labels: {} wellKnownPolicies: externalDNS: true roleName: eksctl-ryusa-external-dns-role - metadata: name: cert-manager namespace: cert-manager labels: {} wellKnownPolicies: certManager: true roleName: eksctl-ryusa-cert-manager managedNodeGroups: - name: workers minSize: 1 maxSize: 6 desiredCapacity: 3 spot: true instanceTypes: - t3.medium - t3.large volumeSize: 60 volumeType: "gp3"
Getting Startedする
依存関係のセットアップ
GitLab Operatorは
を利用してGitLabを起動します。まずはこれらを適当にKubernetesにデプロイしておきましょう。
NGINX Ingress Controller
GitLabをKubernetesの外からアクセスできるようにするためのIngress ControllerとしてNGINX Ingress Controllerが推奨されています。実際にはIngress Controllerとして
の2点が必要な機能だと思います。
推奨に従ってNGINX Ingress ControllerをKubernetesにHelmでデプロイします。使うHelmチャートはingress-nginx/ingress-nginx
、Valueファイルは下記のYAMLで実装します。
# Helmチャート ingress-nginx/ingress-nginx controller: ingressClassResource: name: nginx enabled: true default: true # NGINX Ingress ControllerにSSH用のTCPプロキシーを作成する # 22: ${GITLAB_NAMESPACE}/${GITLAB_NAME}-gitlab-shell:22 tcp: 22: "gitlab-system/vulture-gitlab-shell:22"
cert-manager
GitLabのTLS証明書を発行するためにインストールが必須です、GitLabのシステム内部で利用する自己証明書の作成もcert-managerのIssuerを使って実装されています。
推奨に従ってcert-managerをKubernetesにHelmでデプロイします。使うHelmチャートはjetstack/cert-manager
、Valueファイルは下記のYAMLで実装します。一部項目にEKSからRoute53を変更するためのIRSAの設定が入ってますが、不要な方はスルーしてください。
# Helmチャート jetstack/cert-manager installCRDs: true # EKSのIRSAを利用するための設定 serviceAccount: create: false name: cert-manager annotations: eks.amazonaws.com/role-arn: arn:aws:iam::XXX:role/eksctl-ryusa-cert-manager securityContext: enabled: true fsGroup: 1001
今回はIssuerとしてLet's Encryptを利用するため、Let's EncryptのACMEを持つClusterIssuerを先に作成しておきます。
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt namespace: cert-manager spec: acme: email: YOUR_EMAIL privateKeySecretRef: name: letsencrypt-privatekey server: https://acme-v02.api.letsencrypt.org/directory solvers: - dns01: route53: region: YOUR_REGION hostedZoneID: HOST_ZONE_ID
External DNS
Ingressに割り振るドメイン名を自動的にDNSに設定するツールのインストールが推奨されています。GitLabをデプロイ後、デフォルトの状態で「GitLab」「MinIO」「Repository」の3つのIngressが作成され、それぞれ適切なドメイン名で名前解決できることが期待された状態でコンポーネントが起動してきます。
もちろん、Ingress作成後に手動でDNSを操作しても良いですが……素直にExternalDNSを利用した方が良いでしょう。今回はExternalDNSの公式リポジトリでホストされているマニフェストを利用してデプロイすることにします。
# 公式のRBACの定義は省略 --- apiVersion: apps/v1 kind: Deployment metadata: name: external-dns namespace: external-dns spec: strategy: type: Recreate selector: matchLabels: app: external-dns template: metadata: labels: app: external-dns annotations: # IRSAのための設定 iam.amazonaws.com/role: arn:aws:iam::XXX:role/eksctl-ryusa-external-dns-role spec: serviceAccountName: external-dns containers: - name: external-dns image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=service - --source=ingress - --domain-filter=ryusa.example.com - --provider=aws - --policy=upsert-only - --aws-zone-type=public - --registry=txt - --txt-owner-id=some-identifier securityContext: fsGroup: 65534
GitLab Operatorインストール
公式ドキュメントに沿ってインストールしていきます。
❯ GL_OPERATOR_VERSION=0.1.0 ❯ PLATFORM=kubernetes ❯ kubectl create namespace gitlab-system namespace/gitlab-system created ❯ kubectl apply -f https://gitlab.com/api/v4/projects/18899486/packages/generic/gitlab-operator/${GL_OPERATOR_VERSION}/gitlab-operator-${PLATFORM}-${GL_OPERATOR_VERSION}.yaml Warning: apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.k8s.io/v1 CustomResourceDefinition customresourcedefinition.apiextensions.k8s.io/gitlabs.apps.gitlab.com created serviceaccount/gitlab-app created serviceaccount/gitlab-manager created serviceaccount/gitlab-nginx-ingress created role.rbac.authorization.k8s.io/gitlab-leader-election-role created role.rbac.authorization.k8s.io/gitlab-nginx-ingress created clusterrole.rbac.authorization.k8s.io/gitlab-app-role created clusterrole.rbac.authorization.k8s.io/gitlab-manager-role created clusterrole.rbac.authorization.k8s.io/gitlab-proxy-role created Warning: rbac.authorization.k8s.io/v1beta1 ClusterRole is deprecated in v1.17+, unavailable in v1.22+; use rbac.authorization.k8s.io/v1 ClusterRole clusterrole.rbac.authorization.k8s.io/gitlab-metrics-reader created rolebinding.rbac.authorization.k8s.io/gitlab-leader-election-rolebinding created rolebinding.rbac.authorization.k8s.io/gitlab-nginx-ingress created clusterrolebinding.rbac.authorization.k8s.io/gitlab-gitlab-app-rolebinding created clusterrolebinding.rbac.authorization.k8s.io/gitlab-gitlab-manager-rolebinding created clusterrolebinding.rbac.authorization.k8s.io/gitlab-gitlab-proxy-rolebinding created service/gitlab-controller-manager-metrics-service created service/gitlab-webhook-service created deployment.apps/gitlab-controller-manager created Warning: cert-manager.io/v1alpha2 Certificate is deprecated in v1.4+, unavailable in v1.6+; use cert-manager.io/v1 Certificate certificate.cert-manager.io/gitlab-serving-cert created Warning: cert-manager.io/v1alpha2 Issuer is deprecated in v1.4+, unavailable in v1.6+; use cert-manager.io/v1 Issuer issuer.cert-manager.io/gitlab-selfsigned-issuer created Warning: admissionregistration.k8s.io/v1beta1 ValidatingWebhookConfiguration is deprecated in v1.16+, unavailable in v1.22+; use admissionregistration.k8s.io/v1 ValidatingWebhookConfiguration validatingwebhookconfiguration.admissionregistration.k8s.io/gitlab-gitlab-validating-webhook-configuration created ❯ kubectl get all -n gitlab-system NAME READY STATUS RESTARTS AGE pod/gitlab-controller-manager-645466b464-jxn5l 2/2 Running 0 2m5s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/gitlab-controller-manager-metrics-service ClusterIP 10.100.68.88 <none> 8443/TCP 2m10s service/gitlab-webhook-service ClusterIP 10.100.163.107 <none> 443/TCP 2m9s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/gitlab-controller-manager 1/1 1 1 2m10s NAME DESIRED CURRENT READY AGE replicaset.apps/gitlab-controller-manager-645466b464 1 1 1 2m11s
いい感じに起動しますね、ヨシ!これからGitLab OperatorがWatchしているGitLabリソースをKubernetesにデプロイして、GitLab OperatorにGitLab本体をデプロイしてもらいましょう。
GitLabをデプロイする
GitLab Operatorをデプロイした際にGitLabリソースのCustom Resource Definition(CRD)もデプロイされています。
❯ kubectl api-resources --api-group apps.gitlab.com NAME SHORTNAMES APIVERSION NAMESPACED KIND gitlabs gl apps.gitlab.com/v1beta1 true GitLab
GitLab OperatorはOperator SDKのHelm Operatorで実装されています。つまりGitlabリソースのスキーマはHelmチャート(gitlab/gitlab)と同一になっています。
GitLabのHelmチャートを参考にしつつ、cert-managerとExternalDNS、NGINX Ingress Controllerと連携するGitLabリソースを作成していきます。
まずは*.ryusa.example.com
ワイルドカードの証明書のためCertificateリソースを作成しておきます。このリソースをあとでGitLabリソースに連携し、すべてのIngressがこのCertificateリソースを参照できるようにします。
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: gitlab-tls namespace: gitlab-system spec: dnsNames: - "*.ryusa.example.com" issuerRef: group: cert-manager.io kind: ClusterIssuer name: letsencrypt secretName: gitlab-tls
Certificateリソースが作成され、TLS証明書が発行されたらGitLabをデプロイしましょう。
apiVersion: apps.gitlab.com/v1beta1 kind: GitLab metadata: name: vulture namespace: gitlab-system spec: chart: version: "5.2.4" values: global: hosts: # `gitlab` `registory` `minio`のサブドメインが生えてくる domain: ryusa.example.com ingress: # NGINX Ingress Controllerを使うように指定 class: nginx configureCertmanager: false # *.ryusa.example.com ワイルドカード証明書を指定 tls: secretName: gitlab-tls nginx-ingress: enabled: false certmanager: install: false
これでGitLabをKubernetes上に展開できました。(長い……)
サクッと運用してみる
それではGitLabで運用作業をやってみましょう!とはいえGitLab OperatorはDay 2 Operationを効率化するためのツールなので、バックアップやバージョンアップなどは非常にシンプルに行うことができます。
実際にコマンドを叩いて動かしてみます。
バックアップ
GitLabリソースを作成するとデフォルトでハウスキーピング用のTask-Runnerが起動します。このTask-Runnerにバックアップ含め様々な作業をお願いすることができます(らしい)。Task-RunnerのPodにはデフォルトでMinIOへの接続情報が保存されているため、Podの内部でbackup-utility
コマンドをキックするだけでバックアップを保存することができます。
❯ kubectl exec -it \ -n gitlab-system task-runner-b854bfbd7-zrfgw -- backup-utility Defaulted container "task-runner" out of: task-runner, certificates (init), configure (init) Dumping database ... Dumping PostgreSQL database gitlabhq_production ... [DONE] done ... Dumping pages ... empty Packing up backup tar [DONE] Backup can be found at s3://gitlab-backups/XX_gitlab_backup.tar
すごく簡単、これでMinIOのオブジェクトストレージにバックアップが保存されました。
なお、GitLabリソースのTask-Runnerのサブチャートにバックアップのcron設定を追加することで定期的にバックアップを取ってくれるようになるらしいです。(未確認
apiVersion: apps.gitlab.com/v1beta1 kind: GitLab metadata: name: vulture namespace: gitlab-system spec: chart: version: "5.2.4" values: # 省略 gitlab: task-runner: enabled: true backups: cron: enabled: true # 毎日朝3時にバックアップを取得 schedule: '0 3 * * *'
リストア
リストア……を完全自動化することはあまりないと思いますが、手動バックアップと同じようにデータをリストアすることができます。バックアップと同じようにTask-Runner Podのコンテナ上でbackup-utility
コマンドをキックするだけです。
❯ kubectl exec -it -n gitlab-system vulture-task-runner-7dd4d9c4bd-dgs6l \ -- backup-utility --restore -f 'https://minio.ryusa.example.com/gitlab-backups/XXX_gitlab_backup.tar?...' ... [DONE] done
ただし上記コマンドでリストアできるのはデータのみであり、鍵などの秘密情報はリストアしてくれません。GitLabの再インストールなどする場合は、Secretリソースを自分でリストアする必要があります。(ドキュメントに記載あり)
GitLabアップグレード
Gitlabのバージョンをアップグレードするには、対応するHelmチャートのバージョンを変更してapplyすればOKです。あとの処理はOperatorが実施してくれます。
上記でインストールしたGitLabリソースのHelmチャートバージョンは5.2.4
ですので、これを5.3.0
にアップグレードにします。これによりインストールされるGitLabのバージョンが14.2.4
から14.3.0
に上がります。
apiVersion: apps.gitlab.com/v1beta1 kind: GitLab metadata: name: vulture namespace: gitlab-system spec: chart: # 5.2.4 -> 5.3.0 version: "5.3.0" # あとは省略
まとめ
GitLab Operatorを利用することでKubernetes上にGitLabを展開し、Kubernetesの言葉でGitLabを管理できるようになるところを確認しました。日時のバックアップや機能の拡張、アップデートなど日々の作業の多くをkubectl
コマンドだけで管理できるようになるのは、少なくとも個人的には嬉しいですね。
今回はcert-managerやNGINX Ingress ControllerをGitLab Operator内蔵のものではないExternalなものと連携しましたが、他にもいくつかのコンポーネントをExternalに変更できるみたいです。特にPostgreSQLやObject Storageなどの状態を持つものはマネージドサービスで使いたいところですね。
このGitLab Operatorはまだまだ開発中とのことで、Issueを見ている限り面白そうなIssueがいくつか上がってます。(ダウンタイムなしアップグレードとか、アツい……!)
現時点ではまだHelm版とOperator版のGitLabの間のクリティカルなギャップがあるわけではない(と思う)ですが、Operatorによる管理はHelmより柔軟な運用が可能になるのでこれからのロードマップに期待ですね。
Rancher Harvesterを使っておうちHCIを構築する話
HarvesterはRancher社が管理しているKubernetes上でHCIを構築するツールです
自宅で若干持て余している計算資源を使ってHarvesterをインストールし、Hyper-Converged Infrastructureをおうちに構築してみます
Hyper-Converged Infrastructure
通称HCI、これはサーバーの仮想化技術のひとつで、計算資源やネットワーキング、ストレージなどをソフトウェアベースで管理できるようにした製品のことを指すらしいです。
いろいろなアプライアンス製品があるそうですが、残念ながら自分はHCI製品に触れたことがないので細かい解説ができないため詳細はWiki先生を参照ください。 詰まるところ、HCI製品を利用すると簡易なオレオレAWS/GCPが作れるといったところでしょうか?
Harvester
冒頭に話をした通り、HarvesterはRancher社がメンテナンスしているHCI製品です。Kubernetesのエコシステムをフルに活用しながら、Rancher製品をうまく組み合わせてHCIを実現しています。
Harbesterが利用しているツールとしては
- 計算資源管理: KubeVirt
- ネットワーク管理: Multus CNI, VLAN Plugin
- ストレージ管理: Longhorn
が挙げられます。
Harvesterを使ってみる
実際にHarvesterをインストールして仮想マシンを作成してみます。今回の検証環境は下記の通りです。
- 物理サーバー
- 第6世代 Intel NUC NUC6i5SYH
- Harvester
- 0.2.0
ISOインストール
Harvesterはインストール方法にISOによるフルインストール(直接インストールとPXEインストールが選択可能)と既存のKubernetesにインストールするRun as Appの2種類があります。今回はまず動かしてみるということでISOを直接物理サーバーにインストールしていきます。
ISOダウンロード〜インストール完了
GithubのreleaseからISOをダウンロードしてきます。
ダウンロードしてきたISOを適当なUSBメモリに焼き込み、物理サーバーにインストールしていきます。インストール中いくつかオプションの指定ができますが、今回はすべてデフォルト値のまま進みます。
トラブルなくスムーズにインストールが完了するとHarvesterのコンソールが表示されます。
仮想マシンの起動
さっそく仮想マシンを起動してみます。コンソールに指定されているアドレスにアクセスしてダッシュボードを開きます。
仮想マシンを作成するには、事前にインストールするISOファイルとネットワークの設定が必要です。
今回はお試しにUbuntu20.04のISOを用意することに。ISOのURLを指定することになるので、ubuntu.comのURLをそのまま指定します。 ImagesタブのCreateボタンからImageの作成をします。
次に仮想ネットワーク、VLANを作成します。NetworksタブのCreateボタンからNetworkの作成をします。
これで仮想サーバーを作成する準備できました。実際に仮想マシンを作成してみます。 Virtual MachinesタブのCreateボタンから仮想マシンを作成します。今回はお試しということで、先ほど登録したUbuntuのISOとVLANを利用することにします。
Createボタンを押すと実際にサーバーが起動し、HarvesterのWebConsoleからUbuntuのインストール画面へアクセスすることができました。 いやーこれは非常に楽ですね!
少し覗いてみる
少し動きについてみてみます。とりあえずPodの状態を確認。
~ ❯ kubectl get pods NAME READY STATUS RESTARTS AGE virt-launcher-vlan-sample-4bssz 1/1 Running 0 23h
Podの名前から見て、どうもこのPodが先ほど作成した仮想マシン本体のようです。KubeVirtの文字が輝いてますね。
でこのPodのownerReference
を見てみると下記の通り
❯ kubectl get pods -o json virt-launcher-vlan-sample-4bssz | jq .metadata.ownerReferences [ { "apiVersion": "kubevirt.io/v1", "blockOwnerDeletion": true, "controller": true, "kind": "VirtualMachineInstance", "name": "vlan-sample", "uid": "d3cab107-362b-4dfa-a0e7-122457f719ac" } ]
なるほど、この仮想マシンはkubevirt.io/v1のVirtualMachineInstanceで作成されているとのこと。
Harvesterの領域ではなくKubeVirtの領域になりますがもう少し深掘りしてみます。このVirtualMachineInstanceのownerReference
を覗いてみると下記の通り
❯ kubectl get VirtualMachineInstance -o json vlan-sample | jq .metadata.ownerReferences [ { "apiVersion": "kubevirt.io/v1", "blockOwnerDeletion": true, "controller": true, "kind": "VirtualMachine", "name": "vlan-sample", "uid": "b6d42e46-0004-47a3-a86d-78411d878cfc" } ]
つまりVirtualMachineを作成することでVirtualMachineInstanceが作成され、そのVirtualMachineInstanceに合わせてPodが起動する感じでしょうか?
kubectl explain
で覗いてみる限り
- VirtualMachineは仮想マシンのテンプレートとそのステータス(起動中かどうか)を管理
- VirtualMachineInstanceは仮想マシンそのものを管理
- Podは物理的な(?)仮想マシン
という関係性っぽいですね。なるほどー
コードを読んでみると、どうもHarvesterはどんなVirtualMachineオブジェクトでも管理対象とするみたいですね。つまりマニュアルで仮想マシンを作ることができそうかな……?
ためしに下記のようなマニフェストで作成してみます。(ちょっと長い)
apiVersion: kubevirt.io/v1 kind: VirtualMachine metadata: name: manual-vm spec: running: true dataVolumeTemplates: - apiVersion: cdi.kubevirt.io/v1beta1 kind: DataVolume metadata: annotations: harvesterhci.io/imageId: default/image-9dk4s name: manual-vm-cdrom-disk spec: pvc: accessModes: - ReadWriteMany resources: requests: storage: 10Gi storageClassName: longhorn-image-9dk4s volumeMode: Block source: blank: {} - apiVersion: cdi.kubevirt.io/v1beta1 kind: DataVolume metadata: name: manual-vm-rootdisk spec: pvc: accessModes: - ReadWriteMany resources: requests: storage: 10Gi storageClassName: longhorn volumeMode: Block source: blank: {} template: metadata: annotations: harvesterhci.io/diskNames: '["manual-vm-rootdisk","manual-vm-cdrom-disk"]' harvesterhci.io/sshNames: '["github.com"]' labels: harvesterhci.io/creator: RyuSA harvesterhci.io/vmName: manual-vm spec: domain: cpu: cores: 1 devices: disks: - bootOrder: 2 cdrom: bus: sata name: cdrom-disk - bootOrder: 1 disk: bus: virtio name: rootdisk - disk: bus: virtio name: cloudinitdisk interfaces: - macAddress: 52:54:00:57:4c:53 #適当 masquerade: {} model: virtio name: default - bridge: {} macAddress: 2e:61:8d:3d:35:4c #適当 model: virtio name: vlan machine: type: q35 resources: requests: memory: 2Gi evictionStrategy: LiveMigrate hostname: manual-vm networks: - name: default pod: {} - multus: networkName: example-vlan name: vlan volumes: - dataVolume: name: manual-vm-cdrom-disk name: cdrom-disk - dataVolume: name: manual-vm-rootdisk name: rootdisk - cloudInitNoCloud: userData: | #cloud-config ssh_authorized_keys: - >- ssh-rsa (snip) name: cloudinitdisk
これでkubectl create
でオブジェクトを作成してみると
一部の部分(labelやannotation)のお作法さえ守れば、しっかり動きますね。まぁできたからと言ってなにか良いことがあるわけではないのですが……w
まとめ
Harvesterを利用して、Kubernetesクラスタ上にHCIを構築して仮想マシンをKubernetesリソースベースで作成してみました。HarvesterのGUIで指定できる項目がまだ少なかったりしましたが、簡単な用途であれば現在のバージョンでもいい感じに動かせると思います。
本当は既存のKubernetes上にデプロイすることまでやりたかったのですが、手元にあるKuberenetesクラスターはRaspberry Piで構築していたため今回は断念。 というのもKubeVirtのARM64のサポートはまだ完成しておらず、それに引きずられてHarvesterのARM64サポートはこれからの状態です。
なので、気長に待ちつつ、可能なら貢献して行こうかなと思います。
Raspberry Pi上にWi-Fi APを自動構築するKubernetes Operatorを作った話
元ネタ、というよりWhy/作ったモチベはこちらに書いてあります👀
雑に言えば「自宅にメッシュWi-Fiを導入したかったので、Raspberry PiでWi-Fi APを実装してみた」という感じ。
TL;DR
最終形として、こんなOperatorを作成しました。
これによりCRDであるAccessPoint
リソースをKubernetesにデプロイすることで、KubernetesにjoinしているRaspberry Pi上に適切に設定されたWi-Fiアクセスポイントを作成することができるようになりました。
これでkubectlひとつでメッシュなWi-Fiを構築したり来客向けのゲストWi-Fiを用意することができるようになりました、やったぜ✨
Rapsberry PiのAP化 #とは
Raspberry PiがWi-FiのAPとして動かせる話は昔からあり、いろんな方が紹介してくださってます🥰
つまるところRaspberry Piのワイヤレスのネットワークインタフェースとイーサネットのネットワークインタフェースをブリッジでつなぎ、ワイヤレスネットワークインタフェースをAPモードで起動しようということですね。ソフトウェアとしてはhostapdがよく使われているみたいです🤔
Raspberry Pi自体は安価に調達できて、かつPoE Hatを利用することでLANケーブル一本で動かすことができるなど取り回しが良さそう……今回やりたいことにピッタリ。
hostapd
hostapdはネットワークインターフェースカードをアクセスポイントとして動かすためのソフトウェアで、設定ファイルを咬まして起動することで指定したSSID/パスワード/その他設定のアクセスポイントを起動することができます。すごく便利👏
とりあえず手動オペレーション💪
一度、手動でWi-Fi APをRaspberry Pi上に展開するための手順を確認してみます。
- ネットワーク内にDHCPを用意する
- Raspberry Piのネットワークインタフェースを変更する(ブリッジ作ったり)
- Raspberry Piにhostapdをインストール、デーモンとして登録する
- configファイルを作成する
- configファイルにSSIDとパスワード、その他設定を入れる
- デーモンのリロード&再起動
手動オペレーションの場合、この手順をAPにしたいRaspberry Piすべてに実施していくことになります。実際に自宅に転がってたRaspberry Pi上でオペレーションしてみたところ、1つあたり新規作成に1時間程度時間がかかりました。これで運用するのは……かなりいやですね🤔
hostapdのインストールの手順そのものはコンテナを配布することで解決自体はできます。ついでだったのでコンテナイメージを作りました
しかし、コンテナを起動したりconfigファイルを配布したりと運用作業を真心込めて1台1台手作業するのはちょっとありえないという気持ち🤮
Operatorにしていく🦾
ルーチンな運用作業はKubernetesのOperatorにするに限る。ということでOperatorで実装することを決意しました。
Kubernetes Operatorとは、KubernetesのAPIリソースを監視して「現在の状況」と「理想の状況」を計算し、現在の状況をあるべき姿にドリブンしていくアプリケーションのことを指します。通常、後述するCRDと共に実装を行い日々の運用の自動化などを行うことが多いです。
有名なOperatorとしてはPrometheusのデプロイや設定をKubernetesリソースで行えるようにしたPrometheus Operatorや、RabbitMQのクラスターデプロイをKubernetesリソースで定義できるようにしたRabbitMQ Cluster Operatorなどがあります。
スコープ決め
手動オペレーションの各タスクのうち、自動化できそうな範囲を考えてみます。
- ネットワーク内にDHCPを用意する
- これは各ネットワーク内で決定するべき事柄、ここまで責任を持つのは過剰
- → スコープ外
- Raspberry Piのネットワークインタフェースを変更する
- これはcloud-initを利用して自動化(=k8s関係ない範囲)
- → スコープ外
- Raspberry Piにhostapdをインストール、デーモンとして登録する
- 指定したノードにPodとして起動すれば……?
- → DaemonSetとして配布します
- configファイルを作成する
- 最低限の設定を外から渡せればConfigMapに入れるところまで自動化できそう
- → CRDとして定義し、そこからConfigMapを作成&DaemonSetと一緒に配布します
- configファイルにSSIDとパスワード、その他設定を入れる
- 4.と同様
- デーモンのリロード&再起動
- Kubernetesの機能をそのまま利用します
- → 実装しない(DaemonSetに任せる)
ということで、1.と2.以外のタスクを自動化する方針で実装していきます。
Kubebuilder
Operatorを実装するにあたり、ほしいのは"Kubernetesのエコシステム"であってOperatorのフルスクラッチではないです🤔
Kubernetes Operatorを実装するためのフレームワークとして有名なものが2つあります。
- Kubebuilder
- Operator SDK
それぞれを触ってみた感じ、個人的にはKubebuilderの方が使いやすそうに感じたので今回はKubebuilderを利用して実装していこうと思います🥰
こちら参考書籍です。KubernetesのOperatorとはなにか、KubebuilderとOperator SDKの違いとサンプル実装と非常にわかりやすく解説されててマジで助かりました。
CRD
KubernetesにはCuston Resource Definitionというリソースの拡張機能が存在しており、いわば「俺専用のKubernetesリソースを作ってやるぜ〜〜^^」ができます。CRD自体はKubernetes 1.16でGAとなっているAPIです。
今回のパターンでは2種類のCRDを実装しました。
AccessPoint
- アクセスポイントそのものを表すリソース
- SSIDの設定やパスワード、あと細かい設定とかと記述する
AccessPointDevice
- アクセスポイントをデプロイする仮想的なデバイス
- ブリッジの設定や操作するネットワークインタフェースなどを記述する
- 用途としては"Aliceの部屋"とか"1F リビング"とかの単位で書いていく
ストーリーとしては
- まずユーザーが
AccessPointDevice
をデプロイ - ユーザーが
AccessPointDevice
を指定したAccessPoint
をデプロイ - AccessPoint Operatorが
AccessPoint
の作成イベントを受信 AccessPointDevice
と合わせてAccessPoint Operatorが適切なDaemonSetを作成してデプロイ- DaemonSetの力で各Raspberry Pi上にhostapdの設定とhostapdコンテナがデプロイされていく
……といった流れでリソースを操作していくかな?と考えています。
最終的に出来上がったもの
開発そのものについては(ただ実装しただけなので)割愛します。興味がある人が多そうであればどこかに書くなりしておきます。
最初にも紹介しましたが、こんな感じに完成しました。細かい使い方等は一応READMEに書いてあります。なお現時点ですでに可愛いバグ(AccessPointDevice
消してもDaemonSetが消えない等)があったりするのは許してください。。。
開発の環境としては使い捨てできるKubernetesを作成するためのkindを利用しました。便利ですね〜
以前構築したRaspberry Piクラスターのネットワーク設定を変更して……
作成したOperatorをデプロイしてみると……
手元のスマホからWi-Fiに接続&インターネットへアクセスできました!やったぜ🤪
ためしにhostapdがデプロイされている環境でRaspberry Piをインストールしてある部屋から部屋へ移動してみましたが、同じSSID/パスワードでうまくローミング(?)してシームレスに接続を継続してくれました。これはいい感じのモノが作れた……!
完走した感想
実はGo言語でがっつり開発したのは初挑戦だったので色々雑な作りになってしまいました。が、それでも今日も自宅で動いてくれています🥰毎日SSIDとパスワードを変えたい気持ちになりますねw
一方でKubebuilder側がまだM1 Mac(自分の開発環境)に正式対応しておらず、Operatorのテスト機構については全く手が出せていない状況です。ARM対応の実装を自分ですれば良いだけなのですが、なかなか食指が動かず……orz
定期的に開発できたらいいな〜と思ってます。