はじめに
kubernetesの勉強のために好きに触れて、時には壊しても問題ない環境が欲しくないですか?
そんな夢のような環境が欲しい!と思って今回お手軽?に自宅で構築してみようと思いました。
家に使われてないラズパイありませんか?
我が家にはなぜか8個ありました。過去の浪費の賜物です!
その中でもスペックが高くて使えそうな以下4つのラズパイを使ってkubernetesクラスターを構築してみようと思います。
- RaspberryPi 4 ModelB 8GB x 3
- RaspberryPi 3 ModelB 1GB x 1
構築したい環境
使っていない1TBの外付けHDDもあったので、64GBのmicroSD、必要なLANケーブル、電源関係を購入して以下のような構成を構築していきます。microSDだと扱えるデータも限られるので1TBのHDDをPersistentVolumeとして使えればありがたいです。
構成図
各ラズパイと用途は以下のとおりです。固定IPも以下のように設定していきます。
ラズパイ(メモリ) | 用途 | IP |
---|---|---|
RaspberryPi 4B(8GB) | Masterノード | 192.168.1.31 |
RaspberryPi 4B(8GB) | Workerノード | 192.168.1.32 |
RaspberryPi 4B(8GB) | Workerノード | 192.168.1.33 |
RaspberryPi 3B(1GB) | NAS | 192.168.1.30 |
物理的な完成イメージ
電源とLANケーブルの2本だけが出てますが、完成したらこの箱の中にクラスターが構築されます。
中はこんな感じ。狭いですが排熱に気をつけつつ配置しています。発熱源は主にHDDと電源です。
ラズパイの基本設定
対象:全てのラズパイ 4台
OSセットアップ
以下よりmicroSDにOSをセットアップするツールをダウンロードしてください。
https://www.raspberrypi.com/software/
今回はUbuntu Server 20.04.5 LTS(64-bit)を使用します。
初期設定
OSのセットアップが終了したらそれぞれのラズパイにmicroSDを刺して起動します。この時、各ラズパイのIPを調べる必要があります。macだとbrewでインストールできるnmapを使ってます。以下のように起動前後でコマンドを実行して追加されたIPからラズパイを確認します。https://nmap.org
# nmap -sP 192.168.1.0/24
Starting Nmap 7.93 ( https://nmap.org ) at 2022-12-12 09:13 JST
Nmap scan report for 192.168.1.1
Host is up (0.020s latency).
Nmap scan report for 192.168.1.2
Host is up (0.019s latency).
:
新たに追加されたIPを確認してssh接続して初期パスワードを変更後に再度ssh接続します。
※ubuntuの初期パスワードはubuntu
# ssh ubuntu@192.168.1.XX
最新に更新する。
$ sudo apt update
$ sudo apt upgrade
ホスト名等変更する。
$ sudo hostnamectl set-hostname <HOSTNAME>
$ sudo timedatectl set-timezone Asia/Tokyo
IP固定化
まず 50-cloud-init.yaml
をコピーして、99-cloud-init.yaml
を作成する。
$ sudo cp /etc/netplan/50-cloud-init.yaml /etc/netplan/99-cloud-init.yaml
/etc/netplan/99-cloud-init.yamlのeth0を環境に合わせて変更する。
network:
ethernets:
eth0:
dhcp4: false
dhcp6: false
optional: true
addresses: [192.168.1.XX/24]
gateway4: 192.168.1.1
nameservers:
addresses: [192.168.1.1]
version: 2
ラズパイを再起動し、設定した固定IPでssh接続する。
$ sudo reboot
hostsの設定
/etc/hosts
に以下を設定する。
# kubernetes nodes
192.168.1.30 nas-01
192.168.1.31 master-01
192.168.1.32 worker-01
192.168.1.33 worker-02
kubernetesの共通セットアップ
対象:Masterノード、Workerノード用3台
IPv6無効化
公式ドキュメントよりIPv6/IPv4のデュアルスタックというのが出来るようですが今回は無効化します。
ip -6 a
でIPv6設定が表示されないことを確認する。
$ sudo vi /etc/sysctl.conf
<以下追記>
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.eth0.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
$ sudo sysctl -p
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.eth0.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
$ ip -6 a
iptablesがブリッジを通過するトラフィックを処理できるようにする
公式ドキュメントより
# br_netfilterモジュールがロードされていることを確認
$ sudo modprobe br_netfilter
$ lsmod | grep br_netfilter
br_netfilter 32768 0
bridge 323584 1 br_netfilter
$ cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
$ sysctl --system
iptablesがnftablesバックエンドを使用しないようにする
公式ドキュメントより
Linuxでは、カーネルのiptablesサブシステムの最新の代替品としてnftablesが利用できます。iptablesツールは互換性レイヤーとして機能し、iptablesのように動作しますが、実際にはnftablesを設定します。このnftablesバックエンドは現在のkubeadmパッケージと互換性がありません。(ファイアウォールルールが重複し、kube-proxyを破壊するためです。)
# レガシーバイナリがインストールされていることを確認してください
sudo apt-get install -y iptables arptables ebtables
# レガシーバージョンに切り替えてください。
sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
sudo update-alternatives --set arptables /usr/sbin/arptables-legacy
sudo update-alternatives --set ebtables /usr/sbin/ebtables-legacy
swapをoffにする
公式ドキュメントより
- Swapがオフであること。kubeletが正常に動作するためにはswapは必ずオフでなければなりません。
デフォルトでoffでした。環境によってonの場合はoffにしてください。
$ free
total used free shared buff/cache available
Mem: 7996680 793396 5748204 4232 1455080 6929472
Swap: 0 0 0
cgroupsの有効化
無効(右端の値が0)の場合は有効(右端の値が0)にしてください。
$ cat /proc/cgroups | grep memory
memory 0 104 0
$ sudo vi /boot/firmware/cmdline.txt
# 改行せず最後尾にスペースを開けて追加する
cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory
$ sudo reboot
$ cat /proc/cgroups | grep memory
memory 10 89 1
CRIランタイムとしてcontainerdをインストール
公式ドキュメントより
必要な設定の追加
手順通り実施する。
cat > /etc/modules-load.d/containerd.conf <<EOF
overlay
br_netfilter
EOF
modprobe overlay
modprobe br_netfilter
# 必要なカーネルパラメータの設定をします。これらの設定値は再起動後も永続化されます。
cat > /etc/sysctl.d/99-kubernetes-cri.conf <<EOF
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
sysctl --system
containerdのインストール
手順通り実施する。
注意:「## Dockerのaptリポジトリの追加」において、ラズパイなのでarch=amd64
をarch=arm64
にしてます。
# (containerdのインストール)
## リポジトリの設定
### HTTPS越しのリポジトリの使用をaptに許可するために、パッケージをインストール
apt-get update && apt-get install -y apt-transport-https ca-certificates curl software-properties-common
## Docker公式のGPG鍵を追加
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
## Dockerのaptリポジトリの追加
add-apt-repository \
"deb [arch=arm64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
## containerdのインストール
apt-get update && apt-get install -y containerd.io
# containerdの設定
mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
# containerdの再起動
systemctl restart containerd
kubeadm、kubelet、kubectlのインストール
公式ドキュメントより
手順通り実施する。
sudo apt-get update && sudo apt-get install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
Masterノードの設定
対象:Masterノード用1台
コントロールプレーンノードのkubeletによって使用されるcgroupドライバーの設定
公式ドキュメントより
手順通り実施する。
$ sudo vi /etc/default/kubelet
KUBELET_EXTRA_ARGS=--cgroup-driver=containerd #追加する
クラスターの作成
公式ドキュメントより
以下コマンドを実行してクラスターを作成します。
※環境に応じて--apiserver-advertise-address
は変更してください。
$ sudo kubeadm init --apiserver-advertise-address=192.168.1.31 --pod-network-cidr=10.244.0.0/16
最後に出てくるメッセージkubeadm join ~
は他のノードを追加する時に必要なのでコピーする。
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 192.168.1.31:6443 --token XXXXXXXXXXXXXXXX \
--discovery-token-ca-cert-hash sha256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
メッセージ中にある以下を実行する。
$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config
export KUBECONFIG=/etc/kubernetes/admin.conf
とあるが実施せず以下実行する。
※実施ているubuntuはroot userではないので。
$ echo 'export KUBECONFIG=$HOME/.kube/config' >> ~/.bashrc
$ source ~/.bashrc
CNIはFlannelを入れる
公式ドキュメントより
今回はCNIとしてFlannelを使用します。
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
ここまで来るとmasterノードでPodが起動してるのが確認できます。
※ステータスがRunningになるまで少し時間かかる場合あります。
$ kubectl get pod -A -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-flannel kube-flannel-ds-sj5wp 1/1 Running 0 2m21s 192.168.1.31 master-01 <none> <none>
kube-system coredns-787d4945fb-6wczc 1/1 Running 0 9m29s 10.244.0.2 master-01 <none> <none>
kube-system coredns-787d4945fb-rzk72 1/1 Running 0 9m29s 10.244.0.3 master-01 <none> <none>
kube-system etcd-master-01 1/1 Running 0 9m43s 192.168.1.31 master-01 <none> <none>
kube-system kube-apiserver-master-01 1/1 Running 0 9m41s 192.168.1.31 master-01 <none> <none>
kube-system kube-controller-manager-master-01 1/1 Running 0 9m39s 192.168.1.31 master-01 <none> <none>
kube-system kube-proxy-g8p6k 1/1 Running 0 9m29s 192.168.1.31 master-01 <none> <none>
kube-system kube-scheduler-master-01 1/1 Running 0 9m45s 192.168.1.31 master-01 <none> <none>
Workerノードの設定
対象:Workerノード用2台
クラスターにWorkerノードを追加します。
先程、クラスター作成時にコピーしたコマンドをWorkerノードで実行します。
$ sudo kubeadm join 192.168.1.31:6443 --token XXXXXXXXXXXXXXXX \
--discovery-token-ca-cert-hash sha256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.
Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
追加後はmasterノードでPodの起動状況が確認できます。
2台分が追加されてます。
~$ kubectl get pod -A -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-flannel kube-flannel-ds-sj5wp 1/1 Running 0 13m 192.168.1.31 master-01 <none> <none>
kube-flannel kube-flannel-ds-w75g6 1/1 Running 0 93s 192.168.1.33 worker-02 <none> <none>
kube-flannel kube-flannel-ds-zwz87 1/1 Running 0 8m22s 192.168.1.32 worker-01 <none> <none>
kube-system coredns-787d4945fb-6wczc 1/1 Running 0 20m 10.244.0.2 master-01 <none> <none>
kube-system coredns-787d4945fb-rzk72 1/1 Running 0 20m 10.244.0.3 master-01 <none> <none>
kube-system etcd-master-01 1/1 Running 0 20m 192.168.1.31 master-01 <none> <none>
kube-system kube-apiserver-master-01 1/1 Running 0 20m 192.168.1.31 master-01 <none> <none>
kube-system kube-controller-manager-master-01 1/1 Running 0 20m 192.168.1.31 master-01 <none> <none>
kube-system kube-proxy-g8p6k 1/1 Running 0 20m 192.168.1.31 master-01 <none> <none>
kube-system kube-proxy-pbdlk 1/1 Running 0 93s 192.168.1.33 worker-02 <none> <none>
kube-system kube-proxy-rxpcn 1/1 Running 0 8m22s 192.168.1.32 worker-01 <none> <none>
kube-system kube-scheduler-master-01 1/1 Running 0 20m 192.168.1.31 master-01 <none> <none>
追加したnodeにROLESのラベルがついてないのでつけます。
$ kubectl get node
NAME STATUS ROLES AGE VERSION
master-01 Ready control-plane 23m v1.26.0
worker-01 Ready <none> 11m v1.26.0
worker-02 Ready <none> 4m18s v1.26.0
$ kubectl label node worker-01 node-role.kubernetes.io/worker=worker
$ kubectl label node worker-02 node-role.kubernetes.io/worker=worker
$ kubectl get node
NAME STATUS ROLES AGE VERSION
master-01 Ready control-plane 29m v1.26.0
worker-01 Ready worker 17m v1.26.0
worker-02 Ready worker 10m v1.26.0
NASの構築
対象:NAS用1台
openmediavaultのインストール
今回はNAS構築用にUIから設定できるopenmediavaultを使用します。
公式ドキュメントより
手順書通り実施する。
Install the openmediavault keyring manually:
apt-get install --yes gnupg
wget -O "/etc/apt/trusted.gpg.d/openmediavault-archive-keyring.asc" https://packages.openmediavault.org/public/archive.key
apt-key add "/etc/apt/trusted.gpg.d/openmediavault-archive-keyring.asc"
Add the package repositories:
cat <<EOF >> /etc/apt/sources.list.d/openmediavault.list
deb https://packages.openmediavault.org/public shaitan main
# deb https://downloads.sourceforge.net/project/openmediavault/packages shaitan main
## Uncomment the following line to add software from the proposed repository.
# deb https://packages.openmediavault.org/public shaitan-proposed main
# deb https://downloads.sourceforge.net/project/openmediavault/packages shaitan-proposed main
## This software is not part of OpenMediaVault, but is offered by third-party
## developers as a service to OpenMediaVault users.
# deb https://packages.openmediavault.org/public shaitan partner
# deb https://downloads.sourceforge.net/project/openmediavault/packages shaitan partner
EOF
Install the openmediavault package:
export LANG=C.UTF-8
export DEBIAN_FRONTEND=noninteractive
export APT_LISTCHANGES_FRONTEND=none
apt-get update
apt-get --yes --auto-remove --show-upgraded \
--allow-downgrades --allow-change-held-packages \
--no-install-recommends \
--option DPkg::Options::="--force-confdef" \
--option DPkg::Options::="--force-confold" \
install openmediavault-keyring openmediavault
omv-confdbadm populate
openmediavaultにログイン
ブラウザよりNAS用ラズパイのIPにアクセスするとログインが表示されるので初期パスワードでログインします。
ユーザー名:admin、パスワード:openmediavault
※必要に応じてパスワードは変更してください。
ssh接続の有効化
インストール後にNAS用ラズパイへのssh接続が無効になるので有効にします。
HDDをext4フォーマット
フォーマット済のHDDをラズパイに接続して電源入った状態にしてください。
使用済HDDだったのでMacのDisk UtilityでexFATフォーマットしました。
パーティション作成します。
![Screenshot 2022-12-13 at 16.14.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173398/3c6c3bbb-0b44-30b6-e6b5-4d70fe2e1ba8.png)
$ sudo fdisk /dev/sda
Welcome to fdisk (util-linux 2.34).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Command (m for help): p
Disk /dev/sda: 931.53 GiB, 1000204886016 bytes, 1953525168 sectors
Disk model: External HDD
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 779AF008-0746-478D-9FA0-9AF8650064ED
Device Start End Sectors Size Type
/dev/sda1 40 409639 409600 200M EFI System
/dev/sda2 411648 1953523711 1953112064 931.3G Microsoft basic data
Command (m for help): d
Partition number (1,2, default 2):
Partition 2 has been deleted.
Command (m for help): g
Created a new GPT disklabel (GUID: AF19F8A0-B693-1740-BBD2-5C14480F685A).
Command (m for help): n
Partition number (1-128, default 1):
First sector (2048-1953525134, default 2048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-1953525134, default 1953525134): 1953525134
Created a new partition 1 of type 'Linux filesystem' and of size 931.5 GiB.
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
ext4でフォーマット
$ sudo mkfs.ext4 /dev/sda
mke2fs 1.45.5 (07-Jan-2020)
Found a gpt partition table in /dev/sda
Proceed anyway? (y,N) y
Creating filesystem with 244190646 4k blocks and 61054976 inodes
Filesystem UUID: e87a5965-da7d-41b3-98e3-d031c333a6e9
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968,
102400000, 214990848
Allocating group tables: done
Writing inode tables: done
Creating journal (262144 blocks): done
Writing superblocks and filesystem accounting information: done
共有フォルダ設定
ユーザーやグループに対して共有フォルダの権限を設定します。
※画面はユーザーに対して権限設定してます。
NAS用ラズパイからもHDDを確認
共有設定したHDDが確認できます。
$ df -hT
Filesystem Type Size Used Avail Use% Mounted on
/dev/sda ext4 916G 48K 870G 1% /srv/dev-disk-by-uuid-15e6566b-02d7-45be-9ad2-7d2a943d885a
クラスターからNASにアクセスできるようにする
Masterノードでnfs共有設定をする。
$ sudo apt-get install nfs-common
$ sudo mkdir /mnt/nas
$ sudo mount 192.168.1.30:share /mnt/nas
$ df -hT
Filesystem Type Size Used Avail Use% Mounted on
192.168.1.30:/share nfs4 916G 0 870G 0% /mnt/nas
クラスターからNASへアクセス確認する
Masterノードでファイルを作成して確認する。
$ touch /mnt/nas/test.txt
NASでファイルを確認する。
$ ls -l /srv/dev-disk-by-uuid-15e6566b-02d7-45be-9ad2-7d2a943d885a/share
total 0
-rw-rw-r-- 1 ubuntu users 0 Dec 13 17:02 test.txt
さいごに
壊したり再構築したり自由に出来る環境が出来上がりました。最低限で構築したので、現在品薄状態のラズパイの販売が再開したらさらにノードを追加したり行きたいと思います。これでしばらく遊べそうです。