はじめに
kubernetes(以下 k8s)の Network がどうなっているか、試したい。GNS3 上で Master/Worker VMを構築し、外部の VyOSと eBGP接続することを目指す。
「なんで動くのか?」の言語化とエビデンスの確認が目的のため、少し冗長かもしれない。
動作環境
Master x1, Worker x2の基本的な構成。vCPU/メモリ/ディスクは最小推奨構成。最初これより少ないメモリで試したら、そもそもインストールできなかった。
Host名 | OS | vCPU | メモリ | ディスクサイズ | NICのアドレス |
---|---|---|---|---|---|
k8s-master | ubuntu 24.04.2 | 4 | 8192MB | 40GB | 192.168.11.121/24 |
k8s-worker1 | ubuntu 24.04.2 | 4 | 8192MB | 40GB | 192.168.11.122/24 |
k8s-worker2 | ubuntu 24.04.2 | 4 | 8192MB | 40GB | 192.168.11.123/24 |
ターゲットk8s
2025年4月末時点での最新安定版を使用。
ソフトウェア | Version | コメント |
---|---|---|
k8s | 1.33 | |
containerd | 1.7.24-0 | dockerを利用しない |
calico | 3.29.3 |
事前準備(Master/Workerノードとも)
SWAPを無効にする
ubuntu@k8s-master:~$ sudo swapon --show
ubuntu@k8s-master:~$
試した環境では 最初からSWAP は有効にされていなかった。
/etc/hosts の編集
/etc/hostsにMaster/Workerを追加しておく
ubuntu@k8s-master:~$ cat /etc/hosts
192.168.11.121 k8s-master
192.168.11.122 k8s-master
192.168.11.123 k8s-worker
カーネルモジュールの追加
ubuntu@k8s-master:~$ sudo modprobe overlay
ubuntu@k8s-master:~$ sudo modprobe br_netfilter
overlay:
コンテナのファイルシステム(Unionファイルシステム)を支えるカーネルモジュール。
これがないと、コンテナのレイヤー管理が動かない。
br_netfilter:
Linuxカーネルで「bridgeネットワーク越しのパケット」もiptablesなどでフィルタできるようにするモジュール。
KubernetesではPod-to-Pod通信などでbridgeを使うので、これがないとNetworkPolicyやiptables制御が効かない。
永続化対応
VM再起動時に読み込まれるよう、modules.conf
に設定を追加。
ubuntu@k8s-master:~$ sudo tee /etc/modules-load.d/k8s.conf <<EOF
overlay
br_netfilter
EOF
カーネルパラメータの設定
ubuntu@k8s-master:~$ 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 --system
で設定を反映させる。k8s では仮想 Bridgeを利用しているが、仮想 Bridge間通信で iptables を有効にするためにはnet.bridge.bridge-nf-call-iptables
とnet.bridge.bridge-nf-call-ip6tables
が必要。
Pod間 Routing を行うためにnet.ipv4.ip_forward
を有効にする。
正常性確認
ubuntu@k8s-master:~$ sudo sysctl net.bridge.bridge-nf-call-iptables
net.bridge.bridge-nf-call-iptables = 1
ubuntu@k8s-master:~$ sudo sysctl net.bridge.bridge-nf-call-ip6tables
net.bridge.bridge-nf-call-ip6tables = 1
ubuntu@k8s-master:~$ sudo sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
すべて1であれば正しく設定されている。
コンテナエンジンのインストール
sudo apt install -y containerd
k8s推奨のcontainerd
を使用する。docker はk8s 1.20 以降では非推奨。
containerd設定ファイル作成
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
Systemd Cgroupにする
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
Podのコンテナプロセスを管理するために cgroup(コントロールグループ)を使ってる。cgroupとは、LinuxでCPU、メモリ、ネットワーク帯域などのリソース制御をする仕組み。
containerd 自体でCgroupを管理する行うか、Systemdでシステム一括とするかがある。k8s では後者が推奨されており、かならず SystemdCgroup = true
とする必要がある。
公式情報は以下。
containerd 再起動と有効化
ubuntu@k8s-master:~$ sudo systemctl restart containerd
ubuntu@k8s-master:~$ sudo systemctl enable containerd
k8s のインストール
これでk8s をインストールする準備ができた。k8s のパッケージは ubuntu の標準リポジトリには存在しないため、公開鍵をインポートし、k8s リポジトリを登録する。
そしてインストール。k8s 1.33においてはkuelet, kubeadm, kubectl は別パッケージ。
それぞれの役割は、公式ページによるとざっくり以下。
コマンド名 | 概要 |
---|---|
kubeadm | クラスターを起動するコマンド |
kubelet | クラスター内のすべてのマシンで実行されるコンポーネント。Podやコンテナの起動などを行う |
kubectl | クラスターにアクセスするためのコマンドラインツール |
k8s リポジトリの追加
ubuntu@k8s-master:~$ sudo curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/kubernetes.gpg
ubuntu@k8s-master:~$ echo "deb https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list
パッケージインストール
ubuntu@k8s-master:~$ sudo apt update
ubuntu@k8s-master:~$ sudo apt install -y kubelet kubeadm kubectl
ubuntu@k8s-master:~$ sudo apt-mark hold kubelet kubeadm kubectl
最後のはk8sのバージョン固定。apt upgrade
でもって不用意に上げないようにするためのもの。 Version upするときには 一時的に unhold
して作業を実施する。
sudo apt-mark unhold kubelet kubeadm kubectl
sudo apt update
sudo apt install kubelet=1.33.1-00 kubeadm=1.33.1-00 kubectl=1.33.1-00
sudo apt-mark hold kubelet kubeadm kubectl
ここで書いたサンプルのバージョンはあくまでも例。書いている段階ではまだ存在していない。
Master ノードでの作業
ようやっとここで Master ノードの初期化を行う。k8sのPodに割り当てるアドレスレンジ(Pod Cider)と、k8s 内部でService を識別するために使用する Cluster IPは、このタイミングでしか設定できない。 これらのアドレスは外部ネットワークと重複不可。歴史の長いオンプレミス環境ではこのアドレスをどうやって確保するかが一大事となる(溜息)
本検証でのパラメータ
Network | 付与するNWアドレス |
---|---|
Pod CIDR | 100.64.0.0/16 |
Cluster IP | 172.16.0.0/16 |
なぜここまで大きなアドレスレンジにするかだが、以下の理由による模様。
- どちらのアドレスレンジも後から拡張できない
- Pod/Serviceが廃棄された後、アドレスが使いまわされるまでにはある程度の時間がかかる
実際に作成する
ubuntu@k8s-master:~$ sudo kubeadm init \
--pod-network-cidr=100.64.0.0/16 --service-cidr=172.16.0.0/16
(snip)
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.11.121:6443 --token jkorog.c9yonl55bvubfjjm \
--discovery-token-ca-cert-hash sha256:e4cbc98a34b42a394b24a82d63d86b9af6828b07fde5a9dd955fd84c4e00aeaf
この最後のkubeadm --join
を Worker1/2でも実行することで、MasterにWorkerノードが組み込まれる。このコマンドには制限時間(24時間?)あり、失効すると Worker の登録ができない。その場合はsudo kubeadm token create --print-join-command
で 新しい有効なjoinコマンド が出てくるのでそれを利用する。
kubectl の準備
kubectlが接続する「k8sクラスタ」「ユーザ」「利用する認証情報」を指定するため、admin.conf
をローカルにコピーする。
ubuntu@k8s-master:~$ mkdir -p $HOME/.kube
ubuntu@k8s-master:~$ sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config
ubuntu@k8s-master:~$ sudo chown $(id -u):$(id -g) $HOME/.kube/config
CNI のインストール
CNIもいくつかあるが、今回は Calico を採用する。
Pod 間通信するには必ず必要なので、最初に入れる。後から変えるのはかなり厄介。
ubuntu@k8s-master:~$ kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.29.3/manifests/calico.yaml
正常性確認
名前空間kube-system
上に calico-kube-controllers-*
と calico-node-*
があり、STATUSがRunning であることを確認する。calico-node-*
は Worker ノードが増えていけばその分だけ増えていく。
ubuntu@k8s-master:~$ kubectl -n kube-system get pod
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-79949b87d-k488c 1/1 Running 4 (12h ago) 3d8h
calico-node-8r8kj 1/1 Running 6 (7h13m ago) 3d8h
調べていくと、一部資料では calico.yaml をダウンロードした後、このyaml ファイル内でname: CALICO_IPV4POOL_CIDR
の値を Pod CIDRと同じ値に変更するものもあった。しかし、今回試したバージョンでは no effect. This should fall within --cluster-cidr
. となっており、kubeadm init
で指定した値に自動で組み込まれるように変更されていた。どのバージョンから仕様が変わったかは調査しきれず。
Worker ノード側での作業
Worker ノードをjoinする。このコマンドはMaster ノードでkubeadm init
実行した際、最後のほうの行に出てくるのでコピーして実行。
ubuntu@k8s-worker1:~$ kubeadm join 192.168.11.121:6443 --token jkorog.c9yonl55bvubfjjm \
--discovery-token-ca-cert-hash sha256:XXXXXXXXXXXXXXXXXXXXX
Master ノードでの正常性確認
kubectl get nodes
で確認する。STATUS が ReadyになっていればOK。
ubuntu@k8s-master:~$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane 4d2h v1.33.0
k8s-worker1 Ready <none> 3d1h v1.33.0
k8s-worker2 Ready <none> 3d1h v1.33.0
Worker ノードでkubectl get nodes
を実行してもこの結果は得られない。kubectl
コマンドはkube-apiserverにリクエストを送るコマンドであり、workerノードでは kube-apiserverの情報がないため、localhostへ取りに行って失敗する動きになる。原理的にはMasterノードの~/.kube/config
をworkerノードへコピーすればできるはずだが、kubectl は Master ノードで実行するのが基本であり、あえて行う必要はない。
切り戻し方
k8s クラスタを作ったはよいけれど、設定を間違ったから削除したい。完全削除は次のように行う。Master/Worker ノード両者で行う必要がある。
Master ノードでの完全初期化
# 1. kubeadm による初期化をリセット
ubuntu@k8s-master:~$ sudo kubeadm reset -f
# 2. 各種残存ファイルを削除(念のため)
ubuntu@k8s-master:~$ sudo rm -rf /etc/kubernetes /var/lib/etcd /var/lib/kubelet /etc/cni /opt/cni /var/lib/cni
# 3. ネットワーク設定(iptables)をクリア
ubuntu@k8s-master:~$ sudo iptables -F
ubuntu@k8s-master:~$ sudo iptables -t nat -F
ubuntu@k8s-master:~$ sudo iptables -t mangle -F
ubuntu@k8s-master:~$ sudo iptables -X
# 4. CNI のブリッジインターフェース(cni0 など)が残っていれば削除
ubuntu@k8s-master:~$ sudo ip link delete cni0 2>/dev/null
ubuntu@k8s-master:~$ sudo ip link delete flannel.1 2>/dev/null
# 5. CNI削除
ubuntu@k8s-master:~$ sudo rm -rf /etc/cni/net.d
# 6. kubeconfig 削除(kubectl 設定)
ubuntu@k8s-master:~$ rm -rf ~/.kube/config
# 7. 明示的なノード削除(kubeadm reset 後、kubectl get nodesで残っていた場合)
ubuntu@k8s-master:~$ kubectl delete node <ノード名>
CNI 設定の削除
kubeadm reset
は /etc/cni/net.d
ディレクトリを削除しません。異なる CNI プラグインを導入する場合、前の干渉する可能性があるため、手動で削除することが推奨されている。
Worker ノードでの完全初期化
# 1. kubeadm join の設定を解除
ubuntu@k8s-worker1:~$ sudo kubeadm reset -f
# 2. 設定ディレクトリ等を削除
ubuntu@k8s-worker1:~$ sudo rm -rf /etc/kubernetes /var/lib/kubelet /etc/cni /opt/cni /var/lib/cni
# 3. ネットワーク関連を削除
ubuntu@k8s-worker1:~$ sudo iptables -F
ubuntu@k8s-worker1:~$ sudo iptables -t nat -F
ubuntu@k8s-worker1:~$ sudo iptables -t mangle -F
ubuntu@k8s-worker1:~$ sudo iptables -X
ubuntu@k8s-worker1:~$ sudo ip link delete cni0 2>/dev/null
ubuntu@k8s-worker1:~$ sudo ip link delete flannel.1 2>/dev/null
もう少し高度は k8s 構築方法
1セットの Master/Workerノードに複数のk8s context を作りたくなる時がある。試験用のクラスタを作るとか。こういった際、kubeadm init する際に --config
を使用し、より詳細な設定を行うことができる。
cluster-config.yaml
ここでは k8s cluster の名前を明示してみる。色々設定できる様子だが、Pod CIDR, Cluster IP, cluster名称だけを変更する。
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
clusterName: shakapon-lab
kubernetesVersion: "1.33.0"
networking:
podSubnet: 100.64.0.0/16 # Calico が使用
serviceSubnet: 172.16.0.0/16 # ClusterIP に使用
kubeadm init
cluster-config.yaml
を利用して初期構築実施可能。
ubuntu@k8s-master:~$ sudo kubeadm init --config=cluster-config.yaml
これ以降の作業は特に変わらない。
正常性確認
せっかくなので context が正しく設定されていることを確認する。
ubuntu@k8s-master:~$ kubectl config current-context
kubernetes-admin@shakapon-lab
ubuntu@k8s-master:~$ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* kubernetes-admin@shakapon-lab shakapon-lab kubernetes-admin