メモ - RyuSA

技術的なメモ書きとか試してみたこと

おうちKubernetesを構築した話

f:id:RyuSA:20210516122353p:plain

Kubernetesの資格CKA/CKADを取得し、なにか自分にご褒美を与えたいな〜と思い……おうちKubernetesを構築することにしました!楽しみにしてたんだ!!

前日譚: ryusa.hatenablog.com

モチベーション 🦾

そもそもなんでおうちKubernetesなんて?と言う話から……

自分の仕事柄、職場のエンジニアの多くが自宅になにかしら機材を持ち込んで幸せになってる人が多いんですよね

先日も仕事の帰り道に数万する機材をポチって自宅に搬入したとか話を聞き、これはもはや一種の宗教じゃないのか とても羨ましい!ぜひ我が家にも!!と、ぼくも家に機材を搬入してみたいな〜と思ってました。 とはいえ、残念ながら自分は仕事で機材に触る機会も少なく、いきなり高価な機材に手を出すのは難易度が高すぎると感じていたので、まず簡単なKubernetesクラスターを家に置いておきたい欲求があったわけでした。

構築 - 物理編

まずは機材の調達から。

Raspberry Pi 4 8GB * 3 amzn.to

Raspberry Pi PoE Hat * 3 amzn.to

RaspberryPi 4 ラックケース amzn.to

LANケーブル * 3 amzn.to

TP-Link スイッチングハブ 5ポート PoE+ amzn.to

SDカードは適当に家に転がっていた32GBのものを利用しています。

先にネタばらししてしまうと、Raspberry Piのみでクラスターを構築した際にどうしてもコントロールプレーンが不安定になってしまったため、家に転がっていたノートPCをコントロールプレーンとして活用しています。

コントロールプレーン:DELL Inspiron13 7378 (Ubuntu Server化済み)

構築 - 論理編

一通り機材のインストールが完了した後、いよいよKubernetesクラスターの構築作業です。microk8sで構築してもいいかな〜とも思いましたが、やはりここはおうちクラスター、妥協はしたくありません。kubeadmでインストールをしました。

今回のクラスターでは、下記の構成で構築していきました。

  • OS:Ununtu20.04
  • Kubernetes: v1.21.0
  • コンテナランタイム:containerd 1.4.4
  • CNI:Calico v3.18.3

またStorageのprovisionerとしてNFSを利用したいので、コントロールプレーンにはNFSもインストールしておきます。

最終的な我が家のネットワークはこちら

┌──────────────┐
│ The Internet │
└──────────────┘
       ▲
       │
       │
       │

 Router
 192.168.0.0/16

       │
       │         ┌───────────────────────┐
       │         │ Home Network          │
       ├─────────┤ 192.168.1.0/24 (DHCP) │
       │         └───────────────────────┘
       │
       │         ┌────────────────────────────────────────────┐
       │         │ Kubernetes Cluster Network                 │
       │         │ 192.168.100.0/24                           │
       │         │                                            │
       │         │                                            │
       │         │     ┌──────────────────────────────┐       │
       │         │     │ Seagull Ship(Control Plane)  │       │
       │         │     │ 192.168.100.101              │       │
       │         │     └──────────────────────────────┘       │
       │         │                                            │
       │         │     ┌──────────────────────────────┐       │
       │         │     │ Seagull (Data Plane)         │       │
       │         │     │ 192.168.100.[1-3]            │       │
       │         │     └──────────────────────────────┘       │
       └─────────┤                                            │
                 │     ┌──────────────────────────────┐       │
                 │     │ MetalLB                      │       │
                 │     │ 192.168.100.[200-250]        │       │
                 │     └──────────────────────────────┘       │
                 │                                            │
                 └────────────────────────────────────────────┘

これに合わせてuser-dataなどに色々インストールしていきます。

Control Plane

適当に転がっているUSBメモリUbuntuイメージを焼き、ブートさせました。公式のKubernetesのインストール手順に従ってKubernetesをインストールしました。

kubernetes.io

/etc/netplan/99-manual.yamlIPアドレス周りの設定を記入して完了(諸事情によりWifiでコントロールプレーンの運用をしてみました、今のところ安定して動いてます)

network:
  version: 2
  renderer: NetworkManager
  wifis:
    wlp1s0:
      dhcp4: no
      dhcp6: no
      addresses: [192.168.100.101/24]
      gateway4: 192.168.0.1
      nameservers:
        addresses:
        - 192.168.0.1
      access-points:
        "YOUR_SSID":
          password: "YOUR_PASSWORD"

Data Plane

Raspberry Piにインストールする予定のSDカードにuser-dataを埋め込み全自動kubernetesインストールまで組み込みました。下記のようなuser-dataを作成し、/system-boot/配下に配置しておくとRaspberry Pi起動時に自動的にkubeadm/kubeletのインストールがされるようになります。

#cloud-config

# hostname
hostname: seagull01

# Japan
timezone: "Asia/Tokyo"

# Never allow to ssh using password
ssh_pwauth: false
# User "user"
users:
  - name: user
    gecos: I am user
    primary_group: user
    groups: [adm, audio, cdrom, dialout, dip, floppy, lxd, netdev, plugdev, sudo, video]
    shell: /bin/bash
    sudo: ALL=(ALL) NOPASSWD:ALL
    lock_passwd: true
    ssh_import_id:
      - gh:RyuSA

# Update packages
package_update: true
package_upgrade: true
packages:
  - apt-transport-https
  - ca-certificates
  - curl
  - gnupg
  - lsb-release
  - nfs-common # for nfs client

mounts:
  - [ tmpfs, /tmp, tmpfs, "defaults,size=256m", "0", "0" ]
  - [ tmpfs, /var/tmp, tmpfs, "defaults,size=256m", "0", "0" ]

write_files:
  # iptablesがブリッジを通過するトラフィックを処理できるようにする 
  - content: |
      net.bridge.bridge-nf-call-ip6tables = 1
      net.bridge.bridge-nf-call-iptables = 1
    owner: root:root
    path: /etc/sysctl.d/k8s.conf
    permissions: '0644'
  # containerdに必要な設定
  - content: |
      overlay
      br_netfilter
    owner: root:root
    path: /etc/modules-load.d/containerd.conf
    permissions: '0644'
  # 必要なカーネルパラメータ
  - content: |
      net.bridge.bridge-nf-call-iptables  = 1
      net.ipv4.ip_forward                 = 1
      net.bridge.bridge-nf-call-ip6tables = 1
    owner: root:root
    path: /etc/sysctl.d/99-kubernetes-cri.conf
    permissions: '0644'

runcmd:
  - sudo swapoff -a
  - sudo sysctl --system
  # install containerd
  - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
  - echo "deb [arch=arm64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  - sudo apt-get update
  - sudo apt-get install containerd.io
  - sudo mkdir -p /etc/containerd
  - containerd config default | sed -e '/containerd.runtimes.runc.options/a \ \ \ \ \ \ \ \ \ \ \  SystemdCgroup = true' | sudo tee /etc/containerd/config.toml
  - sudo systemctl restart containerd
  # install kubeadm
  - sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
  - echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
  - sudo apt-get update
  - sudo apt-get install -y kubelet kubeadm kubectl
  - sudo apt-mark hold kubelet kubeadm kubectl containerd.io

起動して30分程度放置すると完了しているので、再起動して各ノードでkubeadm joinコマンドを叩いてKubernetesクラスターに参加すればOKです。かんたん!

f:id:RyuSA:20210516134402p:plain
今日も元気に動いてます

不安定なクラスタ

実は一度Raspberry Piのみでクラスターを構築してみました。……が、かなり不安定になってしまいすぐコントロールプレーンが死んでしまう事態に。 原因としては、どうやらSDカードのI/Oスループットが遅すぎるせいでetcdの書き込みが遅れてしまいkube-apiserverが死んでしまう……ということっぽかったです。(詳細は不明)

そのため、急遽家に転がっていたDellのノートPCをUbuntu Serverにしてコントロールプレーンとして再起動することでクラスターを安定化させました。

おわりに

さて、これでKubernetesクラスターが出来上がりましたが……知ってる人は知っての通り、このままでこのクラスターはあまり美味しくありません。

  • 永続化ボリュームが自動で作成されない
    • provisioner/storageclassがない
    • なんらかの方法でボリュームを作成して使いたい人に渡してあげる必要がある
  • Serviceのtype: LoadBalancerが使えない
    • Kubernetesの外へアプリケーションの公開が面倒になる
  • Ingressが使えない

かなり美味しくないです。美味しくないので、加工してより美味しくするための加工作業を進めていきます。(書いたら↓に追加していきます)