はじめに
こんにちは。金融ソリューション事業部エンジニアリングオフィスの加藤です。
仕事でGKEやAKSといったマネージドKubernetesサービスを利用したインフラ構築を経験してきました。
この記事では、Raspberry Pi 5でK8sクラスタを構築しながら、マネージドK8sのありがたみについて学んでいきます。
ゴール
以下の作業を通して、Kubernetesクラスタのオンプレ環境における構築手順の全体的な流れと、設計判断のポイントについてざっくり理解する
- Raspberry Piをセットアップする
- Kubernetesクラスタを作る
- Prometheus, Grafanaを入れてクラスタの監視環境をセットアップする
- Cloudflare tunnelを利用して、セキュアにインターネット経由からのアクセスをできるようにする
構成
Raspberry Pi 5は手元に3台あります。以下の戦略で構築します。
- マスター1, ノード2 のIPv4シングルスタックのKubernetesクラスタをkubeadmで構築する
- あとでマスターにもノードを追加できるように、高可用性の構成とする
Host Name | IP Address | Description |
---|---|---|
PC | 192.168.3.x | 作業用のPC |
master-1 | 192.168.3.81 | マスター1: Raspberry piにUbuntu 24.04 LTS |
node-1 | 192.168.3.82 | ノード1: Raspberry piにUbuntu 24.04 LTS |
node-2 | 192.168.3.83 | ノード2: Raspberry piにUbuntu 24.04 LTS |
kubernetes-frontend | 192.168.3.90 | コントロールプレーンのAPIサーバ負荷分散のための仮想IP |
(LoadBalancer Service用) | 192.168.3.91-99 | Service Type:Loadbalacerで使用するIPレンジ |
構成イメージは以下のとおりです。
大まかな流れ
-
- Raspberry Piのセットアップ
- カーネルの設定
- コンテナランタイムの設定
- ツールのインストール
-
- HA構成のAPIServer
- クラスタ作成
- Nodeの追加
- テスト用のPodをデプロイして確認
PrometheusとGrafanaのセットアップ(オプション)
- kube-prometheus-stack Helmチャートによる簡単なセットアップ
- インターネット経由でアクセスできるようにする
1. 準備
記事のボリュームの関係上、Raspberry Piそのものについての記述は少し端折ります。
- Raspberry Pi Imagerを利用して、Ubuntu 24.04 LTSのイメージをSDカードに焼きます。
- 複数台ありますので、自宅環境の要件を満たすための汎用的な設定はuser-dataに書いた上で起動したりshellスクリプトにしたりすると、セットアップが捗ります。user-dataのサンプルを一番下に書きましたので、一つの参考としてご参照ください。
環境
SDカードを入れて起動します。以下のようになりました。
# 各種情報確認 $ cat /etc/os-release PRETTY_NAME="Ubuntu 24.04 LTS" NAME="Ubuntu" VERSION_ID="24.04" VERSION="24.04 LTS (Noble Numbat)" VERSION_CODENAME=noble ID=ubuntu ID_LIKE=debian HOME_URL="https://www.ubuntu.com/" SUPPORT_URL="https://help.ubuntu.com/" BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" UBUNTU_CODENAME=noble LOGO=ubuntu-logo $ uname -a Linux node-1 6.8.0-1004-raspi #4-Ubuntu SMP PREEMPT_DYNAMIC Sat Apr 20 02:29:55 UTC 2024 aarch64 aarch64
カーネルの設定
# カーネルの設定 ## カーネルモジュールのロード $ cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF $ sudo modprobe overlay $ sudo modprobe br_netfilter ## カーネルパラメータの設定 $ cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv4.ip_forward = 1 EOF # 確認 $ sudo sysctl net.bridge.bridge-nf-call-iptables $ sudo sysctl net.bridge.bridge-nf-call-ip6tables $ sudo sysctl net.ipv4.ip_forward $ sudo sysctl --system
コンテナランタイムの設定
コンテナランタイム、CNI Pluginを入れていきます。今回はcotainerd + runc
の一般的な構成としました。また、コンテナ管理にcgroupを利用するように設定します。
# containerdのインストール $ ARCH="arm64" $ CONTAINERD_VERSION="1.6.32" $ curl -fsSL https://github.com/containerd/containerd/releases/download/v${CONTAINERD_VERSION}/containerd-${CONTAINERD_VERSION}-linux-${ARCH}.tar.gz -o containerd-${CONTAINERD_VERSION}-linux-${ARCH}.tar.gz $ curl -fsSL https://github.com/containerd/containerd/releases/download/v${CONTAINERD_VERSION}/containerd-${CONTAINERD_VERSION}-linux-${ARCH}.tar.gz.sha256sum -o containerd-${CONTAINERD_VERSION}-linux-${ARCH}.tar.gz.sha256sum $ sha256sum -c containerd-${CONTAINERD_VERSION}-linux-${ARCH}.tar.gz.sha256sum $ sudo tar -C /usr/local -xzvf containerd-${CONTAINERD_VERSION}-linux-${ARCH}.tar.gz $ rm containerd-${CONTAINERD_VERSION}-linux-${ARCH}.tar.gz containerd-${CONTAINERD_VERSION}-linux-${ARCH}.tar.gz.sha256sum # containerdの設定 $ sudo mkdir -p /etc/containerd $ containerd config default | sudo tee /etc/containerd/config.toml $ curl https://raw.githubusercontent.com/containerd/containerd/main/containerd.service | sudo tee /etc/systemd/system/containerd.service > /dev/null # containerdをサービスとして起動 $ sudo systemctl daemon-reload $ sudo systemctl enable --now containerd $ sudo systemctl status containerd
# runcのインストール $ sudo apt-get update -y $ sudo apt-get install -y libseccomp2 gpg $ curl -fsSL https://github.com/opencontainers/runc/raw/main/runc.keyring -o runc.keyring $ gpg --import runc.keyring $ RUNC_VERSION="1.1.12" $ curl -fsSL https://github.com/opencontainers/runc/releases/download/v${RUNC_VERSION}/runc.${ARCH} -o runc $ curl -fsSL https://github.com/opencontainers/runc/releases/download/v${RUNC_VERSION}/runc.${ARCH}.asc -o runc.asc $ gpg --verify runc.asc runc $ sudo install -m 755 runc /usr/local/sbin/runc $ rm runc runc.asc runc.keyring # インストール確認 $ containerd -v $ runc -v
# CNI Pluginのインストール $ sudo mkdir -p /opt/cni/bin CNI_VERSION="1.1.1" $ curl -fsSL https://github.com/containernetworking/plugins/releases/download/v${CNI_VERSION}/cni-plugins-linux-${ARCH}-v${CNI_VERSION}.tgz -o cni-plugins-linux-${ARCH}-v${CNI_VERSION}.tgz $ curl -fsSL https://github.com/containernetworking/plugins/releases/download/v${CNI_VERSION}/cni-plugins-linux-${ARCH}-v${CNI_VERSION}.tgz.sha256 -o cni-plugins-linux-${ARCH}-v${CNI_VERSION}.tgz.sha256 $ sha256sum -c cni-plugins-linux-${ARCH}-v${CNI_VERSION}.tgz.sha256 $ sudo tar -C /opt/cni/bin -xzvf cni-plugins-linux-${ARCH}-v${CNI_VERSION}.tgz $ rm cni-plugins-linux-${ARCH}-v${CNI_VERSION}.tgz cni-plugins-linux-${ARCH}-v${CNI_VERSION}.tgz.sha256
# systemdを利用するようにcontainerdの設定を変更 $ sudo cp /etc/containerd/config.toml /etc/containerd/config.toml.bak $ sudo sed -i '/\[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options\]/,/\[/ s/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml $ diff /etc/containerd/config.toml /etc/containerd/config.toml.bak 127c127 < SystemdCgroup = true --- > SystemdCgroup = false $ sudo systemctl restart containerd
# swapをOFFにする $ sudo swapoff -a
Kubernetes関連のツールのインストール
今回はクラスタの構築に kubeadm
を利用するので、kubeadm
をインストールします。その他、kubelet
も必要になるのでインストールしておきます。kubectl
は必要に応じて入れます。
$ sudo apt-get install -y apt-transport-https ca-certificates curl gpg $ curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list $ sudo apt-get update -y $ sudo apt-get install -y kubelet kubeadm kubectl $ sudo apt-mark hold kubelet kubeadm kubectl # 確認 $ kubeadm version $ kubectl version --client=true $ kubelet --version
2. クラスタの構築
今回は以下の戦略とします。
- Kubernetes v1.30を入れる
- 高可用性クラスタとして構成する
- ※現時点ではマスターノードは1台だけですが、将来的に追加できるようにするため。途中で変更できないため、クラスタ作成時にこの構成にしておく必要があります
- マスターノード上で以下のように構成する
- HAProxyでコントロールプレーンのAPI Server宛のリクエストをリバースプロキシする
- Keepalivedで仮想IPを設定する
- 各ノードのkubelet,kubectlからはこの仮想IPを使用するようにする
- 上記の名前解決は簡易的にhostsを用いる
HA構成のAPIServer
まず、Keepalivedをインストールし、固定したIP(今回は192.168.3.90)でアクセスできるように設定します。
#Keepalivedのインストール/設定 $ sudo apt update $ sudo apt install keepalived $ K8S_VIP="192.168.3.90" $ cat <<_EOF_ | sudo tee /etc/keepalived/keepalived.conf vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { ${K8S_VIP} } } _EOF_ # keepalivedを利用するためのカーネルモジュールのロード設定: https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/load_balancer_administration/s1-initial-setup-forwarding-vsa $ echo "net.ipv4.ip_nonlocal_bind = 1" | sudo tee -a /etc/sysctl.d/k8s.conf $ sudo sysctl net.ipv4.ip_nonlocal_bind $ sudo systemctl start keepalived $ sudo systemctl enable keepalived # 確認 $ ip addr show eth0 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 2c:cf:67:2c:e4:9a brd ff:ff:ff:ff:ff:ff inet 192.168.3.81/24 brd 192.168.3.255 scope global eth0 valid_lft forever preferred_lft forever inet 192.168.3.90/32 scope global eth0 # ←これができる valid_lft forever preferred_lft forever ...中略... # hostsを編集して名前解決できるようにしておく # /etc/cloud/templates/hosts.debian.tmplは起動時にhostsを生成するテンプレートのため、一旦リブートするか、hostsにも直接書くかどちらが必要 $ cat <<_EOF_ | sudo tee -a /etc/cloud/templates/hosts.debian.tmpl # These entry is for testing keepalived configuration for k8s apiserver ${K8S_VIP} kubernetes-frontend.local _EOF_
続いて、HAProxyを設定します。
# HAProxyのインストール $ sudo apt update $ sudo apt install haproxy $ sudo cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg_bak # frontendにKeepalived, backendに後で作成するKubernetes API Serverを設定 $ cat <<_EOF_ | sudo tee /etc/haproxy/haproxy.cfg global log /dev/log local0 log /dev/log local1 notice user haproxy group haproxy daemon defaults log global mode tcp timeout connect 5000 timeout client 50000 timeout server 50000 frontend kubernetes-frontend bind *:8443 default_backend kubernetes-backend backend kubernetes-backend mode tcp balance roundrobin server master-1 127.0.0.1:6443 check verify none _EOF_ $ sudo systemctl reload haproxy
クラスタ作成
K8sクラスタを作成し、Podをデプロイできる状態にします。以下のような流れになります。
コントロールプレーンの設定
kubeadm init
を使います。コントロールプレーンの作成は、以下のような処理が行われることで実現しているようです。
# https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-init/#synopsis # 以下の順序で処理される preflight Run pre-flight checks certs Certificate generation /ca Generate the self-signed Kubernetes CA to provision identities for other Kubernetes components /apiserver Generate the certificate for serving the Kubernetes API /apiserver-kubelet-client Generate the certificate for the API server to connect to kubelet /front-proxy-ca Generate the self-signed CA to provision identities for front proxy /front-proxy-client Generate the certificate for the front proxy client /etcd-ca Generate the self-signed CA to provision identities for etcd /etcd-server Generate the certificate for serving etcd /etcd-peer Generate the certificate for etcd nodes to communicate with each other /etcd-healthcheck-client Generate the certificate for liveness probes to healthcheck etcd /apiserver-etcd-client Generate the certificate the apiserver uses to access etcd /sa Generate a private key for signing service account tokens along with its public key kubeconfig Generate all kubeconfig files necessary to establish the control plane and the admin kubeconfig file /admin Generate a kubeconfig file for the admin to use and for kubeadm itself /super-admin Generate a kubeconfig file for the super-admin /kubelet Generate a kubeconfig file for the kubelet to use *only* for cluster bootstrapping purposes /controller-manager Generate a kubeconfig file for the controller manager to use /scheduler Generate a kubeconfig file for the scheduler to use etcd Generate static Pod manifest file for local etcd /local Generate the static Pod manifest file for a local, single-node local etcd instance control-plane Generate all static Pod manifest files necessary to establish the control plane /apiserver Generates the kube-apiserver static Pod manifest /controller-manager Generates the kube-controller-manager static Pod manifest /scheduler Generates the kube-scheduler static Pod manifest kubelet-start Write kubelet settings and (re)start the kubelet upload-config Upload the kubeadm and kubelet configuration to a ConfigMap /kubeadm Upload the kubeadm ClusterConfiguration to a ConfigMap /kubelet Upload the kubelet component config to a ConfigMap upload-certs Upload certificates to kubeadm-certs mark-control-plane Mark a node as a control-plane bootstrap-token Generates bootstrap tokens used to join a node to a cluster kubelet-finalize Updates settings relevant to the kubelet after TLS bootstrap /experimental-cert-rotation Enable kubelet client certificate rotation addon Install required addons for passing conformance tests /coredns Install the CoreDNS addon to a Kubernetes cluster /kube-proxy Install the kube-proxy addon to a Kubernetes cluster show-join-command Show the join command for control-plane and worker node
kubeadm init
を実行する際のオプションは、コマンド引数として渡すか、yamlで書いて渡すことができます。今回は以下のとおり kubeadm-config.yaml
を書きました。デフォルトから変更する設定項目は以下のとおりです。
- コントロールプレーンを高可用性構成にするための
controlPlaneEndpoint
/apiServer.certSANs
- Podに割り当てるサブネットを設定するための
networking.podSubnet
$ cat <<_EOF_ > ~/kubeadm-config.yaml apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration kubernetesVersion: 1.30.0 controlPlaneEndpoint: "kubernetes-frontend.local:8443" apiServer: certSANs: - kubernetes-frontend.local # hostname of keepalived - 192.168.3.90 # VIP of keepalived - master-1.local # hostname of master-1 - 192.168.3.81 # IP of master-1 networking: podSubnet: "10.64.0.0/16" _EOF_ # kubeadm initを実行する # 他のノードを構成する際の手順を簡略化するために `--upload-certs` オプションをオプションを追加 $ sudo kubeadm init \ --config kubeadm-config.yaml \ --upload-certs # 以下が出力されたら完了 Your Kubernetes control-plane has initialized successfully! To start using your cluster, you need to run the following as a regular user: mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config Alternatively, if you are the root user, you can run: export KUBECONFIG=/etc/kubernetes/admin.conf You should now deploy a pod network to the cluster. Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: https://kubernetes.io/docs/concepts/cluster-administration/addons/ You can now join any number of the control-plane node running the following command on each as root: kubeadm join kubernetes-frontend.local:8443 --token {token} \ --discovery-token-ca-cert-hash sha256:{discovery-token-ca-cert-hash} \ --control-plane --certificate-key {certificate-key} Please note that the certificate-key gives access to cluster sensitive data, keep it secret! As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use "kubeadm init phase upload-certs --upload-certs" to reload certs afterward. Then you can join any number of worker nodes by running the following on each as root: $ kubeadm join kubernetes-frontend.local:8443 --token {token} \ --discovery-token-ca-cert-hash sha256:{discovery-token-ca-cert-hash} # 完成したらkubectlを使えるようにしておく $ mkdir -p $HOME/.kube $ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config $ sudo chown $(id -u):$(id -g) $HOME/.kube/config $ source <(kubectl completion bash) $ echo "source <(kubectl completion bash)" >> ~/.bashrc
Pod Network アドオン
この時点では、まだcorednsが起動してきません。Podが動作するようになるには、Pod Network アドオンをインストールします。
Pod Network アドオンは、主に以下のような責務を負うコンポーネントです。
Pod Network アドオンはCalicoやFlannelなど複数の選択肢がありますが、今回はCalicoを使用します。
- 現時点で、Calicoは、KubeadmプロジェクトがE2Eテストを行っている唯一のアドオンだそうです
今回はCalicoをオペレータを使ってインストールします。
# Calicoをインストールするためのマニフェストを一旦ダウンロード $ curl https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/tigera-operator.yaml -O $ curl https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/custom-resources.yaml -O
kubeadm init
時と同様、Podサブネットをこちらにも設定する必要があります。
# custom-resource.yaml # クラスタ構築時に指定したPod SubnetのCIDRを指定する # This section includes base Calico installation configuration. # For more information, see: https://docs.tigera.io/calico/latest/reference/installation/api#operator.tigera.io/v1.Installation apiVersion: operator.tigera.io/v1 kind: Installation metadata: name: default spec: # Configures Calico networking. calicoNetwork: ipPools: - name: default-ipv4-ippool blockSize: 26 - cidr: 192.168.0.0/16 + cidr: 10.64.0.0/16
$ kubectl create -f tigera-operator.yaml $ kubectl create -f custom-resources.yaml
Nodeの追加
クラスタへのノードの追加は、先ほどの kubeadm init
を実行した後に出力されていた内容に従うだけで簡単にできます。
今回はワーカーノードを2台追加します。
# 先に、API Serverの仮想IPに解決されるホスト名をhostsに追記しておく(リブートして反映) $ cat <<_EOF_ | sudo tee -a /etc/cloud/templates/hosts.debian.tmpl # These entry is for testing keepalived configuration for k8s apiserver ${K8S_VIP} kubernetes-frontend.local _EOF_ # kubeadm init時の出力に従ってノードごとに実行 $ sudo kubeadm join kubernetes-frontend.local:8443 --token {token} \ --discovery-token-ca-cert-hash sha256:{discovery-token-ca-cert-hash}
# nodeが上がっている $ kubectl get node NAME STATUS ROLES AGE VERSION master-1 Ready control-plane 6d11h v1.30.1 node-1 Ready <none> 6d11h v1.30.1 node-2 Ready <none> 6d11h v1.30.1 # Calicoの状態を確認 # Calicoでは、各ノードがBGPピアリングして経路情報を交換し、L3のレイヤでルーティングする $ sudo ./calicoctl node status Calico process is running. IPv4 BGP status +--------------+-------------------+-------+------------+-------------+ | PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO | +--------------+-------------------+-------+------------+-------------+ | 192.168.3.82 | node-to-node mesh | up | 2024-06-07 | Established | | 192.168.3.83 | node-to-node mesh | up | 2024-06-07 | Established | +--------------+-------------------+-------+------------+-------------+ IPv6 BGP status No IPv6 peers found.
MetalLBの設定
オンプレ環境のK8sクラスタ環境では、Type: LoadBalancer のServiceを公開するためにL4のLBを用意する必要があります。今回はMetalLBをLayer2モードで使用し、また、特定のIPアドレスが自動的にアタッチされるように設定します。
# MetalLBのインストール kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.5/config/manifests/metallb-native.yaml # ServiceのExternal-IPに割り当てるIPアドレスを設定する cat <<_EOF_ | kubectl apply -f - apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: first-pool namespace: metallb-system spec: addresses: - 192.168.3.91-192.168.3.99 --- apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: name: example namespace: metallb-system _EOF_
テスト用のPodをデプロイして確認
準備ができたので、テスト用のNginxをデプロイし、複数のタイプのService経由で疎通できるかどうかを確認します。
#テスト用Nginx kubectl create deployment test-nginx --image=nginx --replicas 3 kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES test-nginx-56cc9db4bc-26955 1/1 Running 1 (6d19h ago) 34d 10.64.84.143 node-1 <none> <none> test-nginx-56cc9db4bc-67ddw 1/1 Running 1 (6d19h ago) 34d 10.64.247.16 node-2 <none> <none> test-nginx-56cc9db4bc-6gffj 1/1 Running 1 (6d19h ago) 34d 10.64.84.142 node-1 <none> <none> cat <<_EOF_ | kubectl apply -f - # Service type: ClusterIP apiVersion: v1 kind: Service metadata: name: test-nginx-clusterip spec: type: ClusterIP ports: - name: "http-port" protocol: "TCP" port: 8080 targetPort: 80 selector: app: test-nginx --- # Service type: NodePort apiVersion: v1 kind: Service metadata: name: test-nginx-nodeport spec: type: NodePort ports: - name: "http-port" protocol: "TCP" port: 8080 targetPort: 80 nodePort: 30080 selector: app: test-nginx --- # Service type: LoadBalancer apiVersion: v1 kind: Service metadata: name: test-nginx-metallb spec: type: LoadBalancer ports: - name: "http-port" protocol: "TCP" port: 8080 targetPort: 80 selector: app: test-nginx _EOF_
Pod / Node / PCなどいろいろな場所から疎通確認してみます
# Pod間通信をテストする用のPodを作成 kubectl run test --image=ubuntu -it --rm # From test pod ## -> APIServer curl https://kubernetes/healthz #OK ## -> Type: ClusterIP / NodePort / LoadBalancer curl http://test-nginx-clusterip:8080 #OK curl http://test-nginx-nodeport:8080 #OK curl http://test-nginx-metallb:8080/ #OK # From Node ## -> Type: LoadBalancer curl http:/192.168.3.91:8080/ #OK # From PC ## -> Type: LoadBalancer curl http:/192.168.3.91:8080/ #OK
3. PrometheusとGrafanaのセットアップ
kube-prometheus-stack Helmチャートによる簡単なセットアップ
最後に、PrometheusとGrafanaを設定して監視基盤を構築します。
- AlertManager、各種Monitor、Ruleなどの他にも、NodeExporter、Grafanaなど必要なコンポーネントがたくさんあるので、今回は一括構築・管理が可能なHelmチャートである kube-prometheus-stackを使います。
- ※ いくつか手段が提供されていますが、設定のカスタマイズや管理をする上ではHelmチャートを使うのが融通が利きそうでした
- ※Raspberry Pi 5にもM2.SSD HATが発売されたので、master-1をNFSサーバとしても設定していました。今回、取得した各メトリクスを共有ディレクトリに保存したくなったのですが・・・PrometheusはNFSをサポートしていないようでした。知りませんでした。
# https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update # GrafanaダッシュボードとPrometheusのUIはPort-ForwardなしでPCから確認したいので、ServiceのTypeを変更 cat <<_EOF_ > values.yaml prometheus: service: type: LoadBalancer grafana: service: type: LoadBalancer _EOF_ # monitoring Namespaceを作ってそこにデプロイ kubectl create ns monitoring helm install prom-stack prometheus-community/kube-prometheus-stack -n monitoring -f values.yaml
ダッシュボードは初期の状態でたくさん設定されていますが、追加で、Raspberry Pi & Docker Monitoring というのを入れてみました。Raspberry Pi は温度を気にしたくなりますので、良い感じに表示されていて嬉しいです。
インターネット経由のアクセス (オプション)
このK8sクラスタのメンテナンスを外出時にもしたい、Grafanaダッシュボードを外出先からも確認したい、となった場合、どのようにすれば良いでしょうか。
Cloudflare を使ってみて、非常に体験が良かったので最後に紹介します。
簡単にいうと、オンプレ側のマシンにcloudflaredをインストールして、そこからCloudflareが管理するエッジ環境に対してトンネルを張り、その経路を利用してセキュアに通信できる、かつその仕組みを利用する際、認証機能、サブドメイン用の自動証明書管理、セキュリティを維持するための各種機能も提供されているというものです。自分のドメインさえ持っていれば、今回の用途では無料で利用できます。
- Cloudflare Tunnel の作成
- UIでの作成方法 に従うと、簡単に設定できます。
- cloudflaredは、すべてのサーバに入れる必要はなく、トンネルを作成したいマシンに対して入れれば足ります。残りの設定はUIから行っていきます(今回はmaster-1に入れました)
- Public Hostname(サブドメインとして利用できるHostnameになります)とService(ローカル側からアクセス可能なIP/ポートの組み合わせ)を関連付けます。今回はGrafanaダッシュボードと、SSHアクセスを有効にしたいので、以下をサービスとして登録し、それぞれに対してサブドメインを割り当てました。
http://prom-stack-grafana.monitoring.svc.cluster.local:80
ssh://localhost:22
- Applicationの設定
- 上記で設定したPublic Hostnameに対して、アクセスポリシー、認証の設定などを有効化できます。
- 自分のメールアドレスだけアクセスできるようにしつつ、パスワードをメールワンタイムパスワードに設定しました。
- Browser SSHタイプでApplication設定を作成すると、ブラウザ上でターミナルが表示されます。
まとめ
- Raspberry PiでK8sクラスターを作ってみました。これから育てていきます
- HA構成や家庭のLAN環境特有の問題に対処することで、L2/L3周りの学びを得る機会になりました
- オンプレKubernetesを業務運用する際の難易度の高さを改めて実感しました(N/W、マシン、ストレージ、可用性・信頼性の確保、継続的な改善とメンテナンス、大規模運用・・・)
- Cloudflareはもっと色々な用途に使ってみたいです
user-data
のサンプル
初期設定系はすべてこちらに突っ込みたくなりますが、うまくいかない時のデバッグが難しいので、簡単な最低限の設定項目だけをuser-dataに、それ以外はスクリプトを書くなどして初回起動後に実行する方が個人的には好きです。
#cloud-config hostname: { HOST_NAME } # Configured by Raspberry Pi Imager manage_etc_hosts: true +package_update: true +package_upgrade: true packages: - avahi-daemon + - libseccomp2 + - gpg + - apt-transport-https + - ca-certificates + - curl + - raspi-config apt: ...中略... users: ...中略... +write_files: + # Configure IP Addrress Fixation + - path: /etc/netplan/99_manual_config.yaml + owner: root:root + permissions: "0600" + content: | + network: + version: 2 + ethernets: + eth0: + dhcp4: true + addresses: + - 192.168.3.83/24 + nameservers: + addresses: + - 192.168.3.1 runcmd: - localectl set-x11-keymap "us" pc105 - setupcon -k --force || true + - netplan apply + - | + cat <<_EOF_ | tee -a /etc/cloud/templates/hosts.debian.tmpl + # These entry is for testing keepalived configuration for k8s apiserver + 192.168.3.90 kubernetes-frontend.local + + _EOF_
参考
- kubeadmを使用したクラスターの作成
- Pod Networking
- kubeadm
- kubeadm: High Availability Considerations
- containerd
- Install Calico networking and network policy for on-premises deployments
- CalicoによるKubernetesピュアL3ネットワーキング
- MetalLB
執筆:@kato.shota、レビュー:@kobayashi.hinami
(Shodoで執筆されました)