検証用Kubernetesクラスタの作成

Pocket

概要

 これまで提供してきたゲームサーバーや周辺サービス等は、基本的にはKubernetesクラスタ上にデプロイして運用してきています。環境はProductionとして1クラスタのみを、namespaceでマルチテナント運用する体制を取っています。(クラスタ本体をメンテナンスするユーザが1人のみ、かつオペレータはRBACが適用されたCD環境+Gitレポジトリでしか触らない為、この運用で必要十分なんですよね)

 しかしながらちょっと訳あって、検証環境としてKubernetesクラスタを新規構築したので、2022年11月時点での構築について備忘録としてメモしていきます。

注意点

  • 今回はデプロイツールにkubeadmのみを使用しています。microk8sやk3s、kubesprayは使用していません。
  • CRIにはcontainerdを使用しています。
  • サービスメッシュのネットワークアドオンにはcalicoを使用しています。
  • 使用したkubernetesバージョンは1.25.4です。

環境情報

$ cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.1 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.1 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
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=jammy

 有効なネットワークアダプタが1つ、ipv4およびipv6アドレスが名前解決可能な状態で付与されています。

$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:15:5d:13:0f:02 brd ff:ff:ff:ff:ff:ff
    inet 192.168.***.***/24 metric 100 brd 192.168.101.255 scope global dynamic eth0
       valid_lft 258832sec preferred_lft 258832sec
    inet6 2405:6584:8540:****:****:****:****:****/64 scope global dynamic mngtmpaddr noprefixroute
       valid_lft 2591666sec preferred_lft 604466sec
    inet6 fe80::215:5dff:fe13:f02/64 scope link
       valid_lft forever preferred_lft forever

作業手順

nftablesからレガシーiptablesへのモード切替え

 Linuxカーネルのiptablesサブシステムは、最近のバージョンではnftablesへの置換えが進んでいます。Ubuntuでも他のディストリと同様に、19.04以降ではnftablesが使用されています。nftablesはkubeadmと現状で非互換であるため、正常に動作させる為にレガシーなiptablesへ切り換えておきましょう。

 切り替えに必要なパッケージを下記でインストールします。

$ sudo apt install -y iptables arptables ebtables

 update-alternativesを利用して、各機能をlegacy iptablesに実際に切り替えていきます。

$ sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
update-alternatives: using /usr/sbin/iptables-legacy to provide /usr/sbin/iptables (iptables) in manual mode
$ sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
update-alternatives: using /usr/sbin/ip6tables-legacy to provide /usr/sbin/ip6tables (ip6tables) in manual mode
$ sudo update-alternatives --set arptables /usr/sbin/arptables-legacy
update-alternatives: using /usr/sbin/arptables-legacy to provide /usr/sbin/arptables (arptables) in manual mode
$ sudo update-alternatives --set ebtables /usr/sbin/ebtables-legacy
update-alternatives: using /usr/sbin/ebtables-legacy to provide /usr/sbin/ebtables (ebtables) in manual mode

kernelパラメータの調整

 使用するkernelモジュールのうち、一部デフォルトで読み込まれていないものがあるので事前に有効化しておきます。

$ echo -e "overlay\nbr_netfilter" | sudo tee /etc/modules-load.d/containerd.conf
$ sudo modprobe overlay
$ sudo modprobe br_netfilter

 iptablesがブリッジインターフェースを通過するパケットを、正常にフォワーディングできるようにkernelパラメータを調整します。

$ echo -e "net.bridge.bridge-nf-call-ip6tables = 1\nnet.bridge.bridge-nf-call-iptables = 1\nnet.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/kubernetes.conf
$ sudo sysctl --system

swapの無効化

 kubeletの実行時にswapが有効化されていると、メモリ使用が逼迫した場合にMemory Evictationを招くため、無効化することが推奨されています。(1.22以降ではWorker nodeでのswap利用がサポートされているようですが、今回はシングルノード構成なので関係ないですね。)

 既にswapが有効化/利用されている環境では、swapoffを実行してswap利用を止めます。fstabに起動時のswapのマウントについて設定が記述されているので削除(またはコメントアウト)しておきましょう。

$ sudo swapoff -a

/etc/fstab

# <file system> <mount point>   <type>  <options>       <dump>  <pass>
# / was on /dev/sda2 during curtin installation
/dev/disk/by-uuid/98955977-1ef1-4e72-a374-d764ef75a953 / ext4 defaults 0 1
# /swap.img     none    swap    sw      0       0

CRIの導入

 今回はCRIとしてcontainerdを導入、利用していきます。productionではなくdevelop環境として利用する為に、最新のバージョンを導入していきましょう。

 containerdの比較的新しいパッケージについては、dockerのレポジトリより利用可能です。まずはDockerのubuntuレポジトリを追加するために、必要なパッケージを導入していきます。(Ubuntuをminimalでセットアップしていない限り、下記パッケージは既に導入されています。)

$ sudo apt update
$ sudo apt install -y ca-certificates curl gnupg lsb-release

 Dockerレポジトリ追加の為に公式のGPGキーを追加します。以前はapt-key add等で追加してたと思うんですが、推奨される方法が変わったみたいですね。

$ sudo mkdir -p /etc/apt/keyrings
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

 aptレポジトリを追加、セットアップします。公式に用意されたインストールドキュメントのワンライナーそのままですね。

$ echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

 パッケージリストを更新して、パッケージをインストールします。

$ sudo apt update && sudo apt install -y containerd.io

 containerdデフォルトの設定では、criプラグインが無効化されているので予め有効化しておきます。config.toml上の該当行をコメントアウト後、containerdを再起動しておきましょう。また末尾にruncのoptionとして、systemdのcgroupドライバを使用するように明示的に指定します。

/etc/containerd/config.toml

# disabled_plugins = ["cri"]
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true
$ sudo systemctl restart containerd

(補遺)nerdctlの導入

 今回のセットアップではDocker Engine自体を導入していないため、各コンテナをデバッグするにはインターフェースを追加で導入する必要があります。containerdにはcliとしてnerdctlが提供されているので、今回はこちらを利用していきましょう。

 パッケージとして提供されてはいないので、GitHubからバイナリをダウンロードして適切なディレクトリに配置していきます。

$ curl -LO https://github.com/containerd/nerdctl/releases/download/v1.0.0/nerdctl-1.0.0-linux-amd64.tar.gz
$ tar zxvf nerdctl-1.0.0-linux-amd64.tar.gz
$ sudo cp nerdctl /usr/local/bin/

 nerdctl自体はdocker-cliとほぼ互換性が保たれているので、特に変わりなく使用することができますね。k8sでデプロイされた各コンテナを参照する際には、–namespace=k8s.ioをオプション付与して利用します。

$ sudo nerdctl --namespace=k8s.io ps
CONTAINER ID    IMAGE                                                    COMMAND                   CREATED         STATUS    PORTS    NAMES
00298ed4aa7a    registry.k8s.io/coredns/coredns:v1.9.3                   "/coredns -conf /etc…"    7 days ago      Up                 k8s://kube-system/coredns-565d847f94-zwwhb/coredns

kubeadmの導入

 CRIが準備できたので、実際にkubernetesのレポジトリ追加、パッケージ導入を作業していきます。レポジトリ追加作業前に必要となるパッケージについて導入しておきましょう。

$ sudo apt update && sudo apt install -y apt-transport-https ca-certificates curl

 先ほどDockerレポジトリを追加したのと同様の手順で、kubernetesのレポジトリを追加していきます。GPGキーのインポートとレポジトリ情報のapt上への登録ですね。

$ sudo curl -fsSLo /etc/apt/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
$ echo "deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main

 登録された情報を元にパッケージリストを更新、実際にkubeadm/kubelet/kubectlの必要パッケージをインストールしていきます。

$ sudo apt update && sudo apt install -y kubelet kubeadm kubectl

クラスターのセットアップ

 kubeadmを利用してクラスターをセットアップしていきます。今回はネットワークアドオンとしてcalicoを使用するので、podのアドレス範囲が他のネットワークと衝突しないように引数を追加しています。

$ sudo kubeadm init --pod-network-cidr="10.244.0.0/16"

 問題無くクラスターが作成されると、下記のメッセージが表示されます。

Your Kubernetes control-plane has initialized successfully!

 現在使用している一般ユーザでkubectl経由でクラスターを利用できるように、configを~/.kubeディレクトリに配置していきます。

$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config

 この時点ではまだネットワークアドオンが展開されていないため、control-planeノードのstatusはNotReadyとなっています。

$ kubectl get nodes
NAME           STATUS     ROLES           AGE   VERSION
k8s-develop1   NotReady   control-plane   24m   v1.25.4

ネットワークアドオンのインストール

 kubernetes上で使用するネットワークアドオンを導入していきます。今回はcaliloを使用するので、最新版のマニフェストファイルを適用していきましょう。詳細なセットアップについては、Install Calico networking and network policy for on-premises deploymentsから確認できます。

$ curl -LO https://raw.githubusercontent.com/projectcalico/calico/v3.24.5/manifests/calico.yaml

 またpod networkに特定のレンジ(10.244.0.0/16)を今回指定しているので、ダウンロードしたマニフェストファイルの特定の箇所を修正していきます。

calico.yaml(アンコメントと設定値の修正)

            # The default IPv4 pool to create on startup if none exists. Pod IPs will be
            # chosen from this range. Changing this value after installation will have
            # no effect. This should fall within `--cluster-cidr`.
            - name: CALICO_IPV4POOL_CIDR
              value: "10.244.0.0/16"

上記のマニフェストの修正後、クラスターに適用および展開します。

$ kubectl apply -f calico.yaml

 calicoに関連するPodのステータスを確認しましょう。各PodのステータスがRunningとなっていれば、CNIが問題なく展開されている状態です。

$ kubectl get pod -n kube-system
NAME                                       READY   STATUS    RESTARTS   AGE
calico-kube-controllers-798cc86c47-z4k7g   1/1     Running   0          2m20s
calico-node-vd8f2                          1/1     Running   0          2m20s
coredns-565d847f94-6ctnq                   1/1     Running   0          37m
coredns-565d847f94-pkz5w                   1/1     Running   0          37m
etcd-k8s-develop1                          1/1     Running   8          37m
kube-apiserver-k8s-develop1                1/1     Running   6          37m
kube-controller-manager-k8s-develop1       1/1     Running   10         37m
kube-proxy-6gthf                           1/1     Running   0          37m
kube-scheduler-k8s-develop1                1/1     Running   8          37m

またCNIプラグインが正常に展開されたので、nodeのstatusがreadyとなっています。

$ kubectl get nodes
NAME           STATUS   ROLES           AGE   VERSION
k8s-develop1   Ready    control-plane   38m   v1.25.4

シングルノードクラスターとして利用する準備

 kubernetesのcontrol-planeには原則としてpodがscheduleされないように設定されています。(control-planeに過剰にpodがscheduleされ、リソースが逼迫するのを防ぐ為にこのような措置が取られています。)podのscheule可否はtaintで制御されていますでの、設定されたtaintを変更しましょう。

$ kubectl taint node k8s-develop1 node-role.kubernetes.io/control-plane:NoSchedule-
node/k8s-develop1 untainted

(補遺)auto-completion入力補完の設定

 kubectlの使用時に入力補完を利用可能にするためには、下記を実行してbash_completion.dに適切なファイルを配置します。

$ kubectl completion bash | sudo tee /etc/bash_completion.d/kubectl > /dev/null

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください