🏗️

雑に作るkubernetesクラスタ with cri-o & Cilium

に公開

概要

本家kubernetesの復習も兼ねて構築手順をまとめた記事です。

開発環境?

構築する環境はこんなかんじ

control-plane

  • CPU: 2vCPU
  • RAM: 2GB
  • DISK: 60GB
  • OS: Ubuntu 24.04
kubernetes version : v1.32
CRI-O version      : v1.32
Cilium version     : v1.17.2

簡易的なk8sクラスタなのでシングルノード構成で作ります

kubernetesの最低要件はこちらです

  • 1台当たり2core,2GB以上
  • すべてのノード間で通信可能であること
  • swapがオフであること
  • 特定のポートが開いていること

CRI(コンテナランタイムインターフェース)

コンテナを動かすためのインタフェースとなるものをインストールする。
kubernetesが公式で利用可能なランタイムは次のとおりですわ

  • Docker
  • containerd
  • cri-o

今回は使ったことがないcri-oで組んでみる。
cri-oはdocker,containerdより軽量なkubernetes特化のコンテナランタイムらしい。
https://cri-o.io/
余談 : ずっと勘違いしてたけどcri-oって大文字じゃなくて小文字なのね

CNI(コンテナネットワークインターフェース)

コンテナ間のネットワークを管理するプラグインです。
今回使用するCiliumとは別でcalicoなんてものもあるらしい。
https://cilium.io/

構築

kubernetesとCRIのインストール

基本的には公式ページに書かれてる手順と変わらないはず。
rootユーザかsudoで実行することを忘れずに!

面倒ならsudo su -なりsudo -iu rootでユーザ変更してもろて

1. 必要なパッケージのインストール

apt update
apt install -y software-properties-common curl

2. バージョン宣言

KUBERNETES_VERSION=v1.32
CRIO_VERSION=v1.32

3. kubernetesとcri-oのリポジトリを登録

# kubernetes repos
curl -fsSL https://pkgs.k8s.io/core:/stable:/$KUBERNETES_VERSION/deb/Release.key |
    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:/$KUBERNETES_VERSION/deb/ /" |
    tee /etc/apt/sources.list.d/kubernetes.list

# cri-o repos
curl -fsSL https://download.opensuse.org/repositories/isv:/cri-o:/stable:/$CRIO_VERSION/deb/Release.key |
    gpg --dearmor -o /etc/apt/keyrings/cri-o-apt-keyring.gpg

echo "deb [signed-by=/etc/apt/keyrings/cri-o-apt-keyring.gpg] https://download.opensuse.org/repositories/isv:/cri-o:/stable:/$CRIO_VERSION/deb/ /" |
    tee /etc/apt/sources.list.d/cri-o.list

4. 各種パッケージのインストール

apt-get update
apt-get install -y cri-o kubelet kubeadm kubectl

5. 各種設定

swapをオフにして、コンテナ間の通信等ができるようにする。
ipフォワーディングも有効化する

swapoff -a
modprobe br_netfilter
sysctl -w net.ipv4.ip_forward=1

6. CRIの有効化

systemctl enable --now crio

7. kubernetesの初期化(立ち上げ)

$ sudo kubeadm init
[init] Using Kubernetes version: v1.32.3
[preflight] Running pre-flight checks
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection

...

[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy

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/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 172.16.1.31:6443 --token SECRET \
        --discovery-token-ca-cert-hash sha256:SECRET 

kubectlでアクセスするためにconfigをhomeディレクトリにコピーします。

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

特権ユーザでkubectlを使用する場合は次のコマンドで有効になります

export KUBECONFIG=/etc/kubernetes/admin.conf

8. 動作確認

systemctl status kubeletでkubernetesのステータスを確認してみよう

● kubelet.service - kubelet: The Kubernetes Node Agent
     Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; preset: enabled)
    Drop-In: /usr/lib/systemd/system/kubelet.service.d
             └─10-kubeadm.conf
     Active: active (running) since Thu 2025-04-17 01:56:03 UTC; 4min 46s ago
       Docs: https://kubernetes.io/docs/
   Main PID: 3892 (kubelet)
      Tasks: 12 (limit: 2320)
     Memory: 33.3M (peak: 33.9M)
        CPU: 9.830s
     CGroup: /system.slice/kubelet.service
             └─3892 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/>

Apr 17 02:00:04 kubernetes-test kubelet[3892]: E0417 02:00:04.257287    3892 kubelet.go:3002] "Container runtime network not ready" ...

ログに"Container runtime network not ready"と出ていることからわかるように、kubectl get nodesを実行してもNotReady状態でスタックしていることが確認できます。
コンテナのネットワークを動作させるためのCNIが導入されていないため、このようにスタックします。
次にCNIのインストールを行います。

CNIのインストール+etc

1. Cilium CLIのインストール

Ciliumのdocsに書かれてるものと同じです

CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
CLI_ARCH=amd64
if [ "$(uname -m)" = "aarch64" ]; then CLI_ARCH=arm64; fi
curl -L --fail --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}
sha256sum --check cilium-linux-${CLI_ARCH}.tar.gz.sha256sum
sudo tar xzvfC cilium-linux-${CLI_ARCH}.tar.gz /usr/local/bin
rm cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}

2. Ciliumのk8sへのインストール

cilium install

次のようなログが流れてCNIのインストールが完了します。

root@kubernetes-test:~# cilium install
ℹ️  Using Cilium version 1.17.2
🔮 Auto-detected cluster name: kubernetes
🔮 Auto-detected kube-proxy has been installed

3. Ciliumとkubernetes nodeのステータス確認

インストール実行してからしばらく待って各種ステータスを確認するとインストールが完了したことが確認できます。

root@kubernetes-test:~# cilium status
    /¯¯\
 /¯¯\__/¯¯\    Cilium:             OK
 \__/¯¯\__/    Operator:           OK
 /¯¯\__/¯¯\    Envoy DaemonSet:    OK
 \__/¯¯\__/    Hubble Relay:       disabled
    \__/       ClusterMesh:        disabled

DaemonSet              cilium                   Desired: 1, Ready: 1/1, Available: 1/1
DaemonSet              cilium-envoy             Desired: 1, Ready: 1/1, Available: 1/1
Deployment             cilium-operator          Desired: 1, Ready: 1/1, Available: 1/1
Containers:            cilium                   Running: 1
                       cilium-envoy             Running: 1
                       cilium-operator          Running: 1
                       clustermesh-apiserver
                       hubble-relay
Cluster Pods:          2/2 managed by Cilium
Helm chart version:    1.17.2
Image versions         cilium             quay.io/cilium/cilium:v1.17.2@sha256:3c4c9932b5d8368619cb922a497ff2ebc8def5f41c18e410bcc84025fcd385b1: 1
                       cilium-envoy       quay.io/cilium/cilium-envoy:v1.31.5-1741765102-efed3defcc70ab5b263a0fc44c93d316b846a211@sha256:377c78c13d2731f3720f931721ee309159e782d882251709cb0fac3b42c03f4b: 1
                       cilium-operator    quay.io/cilium/operator-generic:v1.17.2@sha256:81f2d7198366e8dec2903a3a8361e4c68d47d19c68a0d42f0b7b6e3f0523f249: 1

root@kubernetes-test:~# kubectl get nodes,pods -A
NAME                   STATUS   ROLES           AGE   VERSION
node/kubernetes-test   Ready    control-plane   12m   v1.32.3

NAMESPACE     NAME                                          READY   STATUS    RESTARTS   AGE
kube-system   pod/cilium-dng7v                              1/1     Running   0          5m38s
kube-system   pod/cilium-envoy-ms74t                        1/1     Running   0          5m38s
kube-system   pod/cilium-operator-59944f4b8f-dbs2w          1/1     Running   0          5m38s
...

4. control-planeのtaintを解除(シングルノード構成等のみ)

デフォルトではcontrol-planeでのデプロイはできないようにtaintが付与されています。
ノードのロールにはworkerやetcd等がありますが、control-planeはその名の通りクラスタの管理を担う部分ですので、過剰に負荷がかからないようにデフォルトでtaintになるんですね~

taintの無効化

kubectl taint nodes <node> node-role.kubernetes.io/control-plane-

動作確認

1. テスト用のnamespaceとdeploymentの作成

pod間での通信ができるかどうか確認するために一時的なdeploymentを作成してみよう。
今回はevaluationネームスペースを作成してデプロイします。
以下のyamlをファイルに書き込んでkubectl apply -f <ファイル名>でデプロイしてみよう。

-- example-deploy.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: evaluation
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ubuntu-deployment
  namespace: evaluation
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ubuntu
  template:
    metadata:
      labels:
        app: ubuntu
    spec:
      containers:
      - name: ubuntu
        image: ubuntu:latest
        command: ["/bin/bash", "-c", "sleep infinity"]
        tty: true
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-target
  namespace: evaluation
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:stable-alpine

デプロイ

root@kubernetes-test:~# kubectl apply -f example-deploy.yaml
namespace/evaluation created
deployment.apps/ubuntu-deployment created
deployment.apps/nginx-target created

podへの接続&ネットワークテスト

pod間の通信が可能であるかの確認をするためには、まずIPアドレスの確認が必要です。
以下のコマンドでアドレスやpod名などの状態が確認ができます。

kubectl get pods -n evaluation -o wide

実行例

root@kubernetes-test:~# kubectl get pods -n evaluation -o wide
NAME                                 READY   STATUS    RESTARTS   AGE    IP           NODE              NOMINATED NODE   READINESS GATES
nginx-target-random        1/1     Running   0          5m3s   10.0.0.29    kubernetes-test   <none>           <none>
ubuntu-deployment-random   1/1     Running   0          5m3s   10.0.0.124   kubernetes-test   <none>           <none>

次にubuntuコンテナにシェルを作成し、操作可能な状態にしましょう。
pod名の部分は各自の環境に合わせて変更してください。

kubectl exec -n evaluation ubuntu-deployment-random --tty --stdin -- /bin/bash

実行したらシェルが取得できるので、apt updateを実行してcurl等好きなものを入れてください。

apt update -yqq; apt install curl -yqq

インストールが完了したら、nginxのpodにcurlをたたいてみましょう

root@ubuntu-deployment-76786b4fdf-6w55q:/# curl 10.0.0.29
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

これでpod間の通信が確認できました。

おまけ(service)

デプロイするたびにpodのIPは変化します。 デプロイのたびにIPを調べて変更するなんて馬鹿らしいので、kubernetesには名前解決する機能としてserviceがあります。
以下のyamlをファイルに書き込んで、kubectl apply -fでserviceを作成してみてください。

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: evaluation
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

再度ubuntuのpodでシェルを取得してnginx-serviceにcurlすると名前解決できていることが確認できます。

root@kubernetes-test:~# kubectl apply -f example-service.yaml
service/nginx-service created
root@kubernetes-test:~# kubectl exec -n evaluation ubuntu-deployment-76786b4fdf-6w55q --tty --stdin -- /bin/bash
root@ubuntu-deployment-76786b4fdf-6w55q:/# curl nginx-service
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
... 以下略

まとめ

Kubernetesのクラスタを構築する時にはCNI,CRI,そしてKubernetes本体があれば構築できることがわかりました。今後何かしらKubernetesのトラブルシューティングだったりを記事にしたいですね。

ここまで読んでくれてありがとうございます!

Discussion