流行りのKubernetesってやつを触ってみたので頭の整理も兼ねて手順をまとめておく。
Q. GKEなどのKaaSを使えばいいじゃん
A. オタクなの
本記事に書いてあること
- kubeadmと各種OSSで適当にKubernetesクラスタを構築する方法
本記事に書いてないこと
- Kubernetesの使い方
- 本番環境に求められるようなアレコレ
Intel NUCはじめました😆 pic.twitter.com/2B2jDTLSao
— えびーむ🍤 (@ebiiiiim) March 26, 2021
概要
ゴール: 当ブログのホスティング
デファクトスタンダードのコンテナオーケストレータであるKubernetesは、アプリをコンテナイメージで用意し、インフラをYAMLにイライラしながら宣言的に設定するだけで、いろんなことをイイ感じにやってくれて、サービスの運用をめっちゃ簡単にしてくれる。詳細はグーグル大先生に譲るとして、本記事ではこのブログをホスティングできる程度までがんばる。
何をすればいいの?
Kubernetesで当ブログをホスティングするまでの道のりはそれなりに遠い。
- システム構成の検討
- ハードウェアを用意する
- ソフトウェア構成を検討する
- Kubernetesクラスタの構築
- 前提条件を満たす
- コンテナランタイムcontainerdをインストール
- kubeadmでクラスタを構築する
- Calicoでコンテナネットワークを構築する
- 必要な機能の導入
- MetalLBでLoadbalancer Serviceを導入する
- NGINX Ingress ControllerでIngress Serviceを導入する
- cert-managerでTLS証明書を供給できるようにする
- NFS subdir external provisionerでNFSサーバをPersistent Volumeにする
- 外部公開
- アプリのデプロイ
- (追記)アップグレード
- v1.20.5 -> v1.21.7
- v1.21.7 -> v1.22.4
やる
実際にはほぼAnsibleでやったけどわかりやすさのためコマンドで載せる
1. システム構成の検討
構成について述べる。
1.1. ハードウェアを用意する
一般のご家庭にあるようなネットワークを用意した。
- 1つのパブリックIPを持ち、ポートフォワーディングでサービスを公開できる
- 名前解決のためにdnsmasqでDHCPとDNSをやる。hostsに書いてもいいと思う
- 内部用のドメイン名:
lab.in.ebiiim.com
- 外部用のドメイン名:
lab.ebiiim.com
物理マシンとしてIntel NUCを用意した。
- Core-i5 / RAM 16GB / SSD 500GB
- 十分な台数があるので仮想化はせずにそのまま使う
- マスターノードのホスト名:
km0
- ワーカーノードのホスト名:
kw0
kw1
kw2
ストレージはNFSにした。Cephなど分散ストレージもそのうち試したい。
- NFSサーバをインストールしたUbuntu
- ホスト名:
pv0
1.2. ソフトウェア構成を検討する
梅雨くらいの時期にやっていたので、だいたいそのときの最新版。
要素 | 名称 | バージョン |
---|---|---|
OS | Ubuntu | 20.04.2 |
本体 | kubelet | 1.20.5-00 |
CLIツール | kubectl | 1.20.5-00 |
デプロイツール | kubeadm | 1.20.5-00 |
CRI | containerd | 1.4.4 |
CNI | Calico | 3.18.1 |
2. Kubernetesクラスタの構築
インストールしたばかりのUbuntuがある想定で、KubernetesクラスタができてPod間で通信ができるところまでやる。
2.1. 前提条件を満たす
対象: 全ノード
いろいろあるけど公式のドキュメントに全部書いてある。
スワップの無効化
/etc/fstab
のswapって書いてある行をコメントアウトして再起動
カーネルモジュール&カーネルパラメータ
ネットワーク関連のパラメータ。再起動後反映される。
/etc/modules-load.d/k8s-cri.conf
|
|
/etc/sysctl.conf
|
|
レガシーiptables
いくつかのOSでデフォルトになっているnftablesだと動かないのでiptablesをインストールする。
|
|
その他
|
|
2.2. コンテナランタイムcontainerdをインストール
nvidia-docker2
とかをインストールしてコンテナ内でnvidia-smi
できるようにする対象: 全ノード
コンテナを動かすためにコンテナランタイムをインストールする必要がある。最新の情報はこのあたりにある。
|
|
2.3. kubeadmでクラスタを構築する
kubeadmをインストールして、Kubernetesクラスタを構築する。
パッケージの取得
対象: 全ノード
ここに書いてある
|
|
ここで再起動しておく。
sudo reboot
kubeadmの実行
対象: マスターノード
ここに書いてある。
kubeadm init
をマスターノードで実行してクラスタを初期化する。その後、表示されたkubeadm join ...
をワーカーノードで実行してクラスタに参加する。ターミナルを閉じるなどしてコンソールのログが消えた場合はkubeadm token create --print-join-command
でクラスタに参加するためのコマンドを再度作成する。
|
|
対象: ワーカーノード
kubeadm init
を実行するとクラスタに参加するためのコマンドが表示されるので、コピーしてきて実行する。
# だいたいこんな感じ↓
# kubeadm join km0:6443 --token {{ トークン }} --discovery-token-ca-cert-hash sha256:{{ ハッシュ }}
2.4. Calicoでコンテナネットワークを構築する
もうすでにPodを起動できる状態になったが、このままでは異なるノード間でPod間通信ができない。これを解消するためにCNIプラグインのCalicoをインストールする。
詳細はドキュメントに書いてある。
|
|
3. 必要な機能の導入
2までの手順でPodの起動やPod同士の通信が可能になるが、今回の目的は本ブログのホスティングなのでそれだけではダメ。データの保持や外部からのアクセスを可能にしなきゃいけない。そのために必要なことをやる。
3.1. MetalLBでLoadBalancer Serviceを導入する
クラスタの外にサービスを公開するためにはLoadBalancerタイプのServiceを使う。オンプレでこれを実現するためにMetalLBを使う。
インストール手順はちょっと複雑なのでドキュメントを見てほしい。
|
|
アドレスプールの設定
今回はL2モードを使い、サブネットの一部をKubernetes用とした。VRRPのVirtual IPみたいにGARPでフェールオーバーすると思う。L3モードでやる場合はBGPに対応したルータを用意しよう。
LoadBalancer Serviceで使うために10.0.0.0/24
のうち10.0.0.201-10.0.0.220
までを割り当てる。また、後述するIngress Serviceで使うために10.0.0.221
を割り当てる。
metallb-pool-conf.yml
|
|
|
|
3.2. NGINX Ingress ControllerでIngress Serviceを導入する
外部公開がIPレベルしかないと不便じゃん?そこでリバースプロキシ的な機能を追加してくれるのがIngress Serviceである。オンプレでこれを実現するためにINGINX Ingress Controllerを使う。
詳細はここを読んで。
MetalLBと併用するためのアノテーション
manifestをapplyするだけなんだけど、MetalLBと併用する&MetalLBのプール名がdefault
でない場合はアノテーションを1行入れなきゃいけない。
ingress-nginx-pool
という1IPだけのプールを作成した。ポートフォワーディングで80/TCPと443/TCPを10.0.0.221にフォワードすることでサービスの公開を実現する。ただ、これをやるとIngressで使えるIPが10.0.0.221のみになるので、常にバーチャルホストを利用する必要がある。まずはmanifestをダウンロードしてくる。注意点:provider/cloud/deploy.yamlを使うこと
|
|
263行目あたりにこれを追記する。metallb.universe.tf/address-pool: {{ プール名 }}
before
|
|
after
|
|
そしてmanifestを適用する
|
|
3.3. cert-managerでTLS証明書を供給できるようにする
TLS証明書を自動で用意してくれないとかマジ無理なのでcert-managerを使う。
cert-managerをインストールする
manifestをapplyするだけ
|
|
issuerを設定する
lab.ebiiim.com
のサブドメインを使うことにする。まずはレジストラのDNSサーバに次のようなAレコードを登録する。
|
|
次にこのようなClusterIssuerのmanifestをapplyする。
lab.ebiiim.com->10.0.0.221
(NGINX Ingress ControllerのIP; つまりMetalLBでIngress用に予約したもの)とする必要があった。issuer-prod.yml
|
|
これで*.lab.ebiiim.com
のTLS証明書を自動発行できる。Let’s Encryptのレート制限に注意。
利用するとき
こんな感じのアノテーションを書く:
|
|
3.4. NFS subdir external provisionerでNFSサーバをPersistent Volumeにする
Q. NFSサーバしかないのですが、自動プロビジョンに対応した永続ボリュームを使いたいです。
A. nfs-subdir-external-provisionerでできます。
これはhelmを使った。helmのインストールはバイナリをダウンロードしてくるだけなので省略。
|
|
4. 外部公開
3までの手順によりPodで動いているウェブサーバをHTTPSで公開できたのであとは本ブログを公開するだけ。
4.1. アプリをデプロイする
普通にやるだけなので省略
5. (追記)アップグレード
最新版を含む3つのマイナーバージョンがサポートされる。1.20はもう古いので公式のガイド(kubeadmの場合)に従って1.22にアップグレードする。
バージョン間の互換性はここに書いてある。アップグレードの際は要注意。
apt-cache madison kubeadm
または https://www.downloadkubernetes.com/ で最新のパッチバージョンを確認しておこう。5.1. v1.20.5 -> v1.21.7
kubeadmのアップグレード
|
|
コントロールプレーンのアップグレード
|
|
|
|
ノードのアップグレード
--delete-emptydir-data
とかつける
|
|
確認
|
|
5.2. v1.21.7 -> v1.22.4
networking.k8s.io/v1beta1
を使っている前の項と同じなので省略。
kubeadm upgrade plan
するとcgroupDriver
が未設定ですって警告が出た。
W1216 00:52:25.300417 2503 kubelet.go:275] The ‘cgroupDriver’ value in the KubeletConfiguration is empty. Starting from 1.22, ‘kubeadm upgrade’ will default an empty value to the ‘systemd’ cgroup driver. The cgroup driver between the container runtime and the kubelet must match! To learn more about this see: https://kubernetes.io/docs/setup/production-environment/container-runtimes/
1.22以降はデフォでsystemd
にするからな!って書いてある。コンテナランタイムがDockerの場合はここに書いてあるように/etc/docker/daemon.json
を編集したか確認しよう。nvidia-docker2
で動かしているノードはこんな設定にしてる。
|
|
Q. アップグレードしたら○○が動かなくなった
A. それもアップグレードしなきゃいけないかも。今回の例だとcert-manage v1.2.0はここに書いてあるようにK8s 1.21までしか対応していないので最新版のv1.6.1にする。
Q. めっちゃ大変じゃん
A. 大変さをアプリから切り離すっていう目的は達成できているから……
その他
Q. Ubuntuがスリープになるんだけど
A. sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target
Q. Ubuntuで一部のNICが繋がっていないとブート時にめっちゃ待たされるんだけど
A. systemctl disable systemd-networkd-wait-online.service && systemctl mask systemd-networkd-wait-online.service
感想
クソ面倒くさい楽しい!✌(‘ω’)✌
後日談
このうち1台がUltra HD ブルーレイ再生機になりました。
このKubernetesクラスタが手元にある唯一のUHD BD再生環境だと判明した
— えびーむ🍤2日目東ト35b (@ebiiiiim) October 18, 2021
さようなら👋アニメのためなんだ🙏 https://t.co/MUE31yMXEe pic.twitter.com/EUb9jhGy0f