13
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ラズパイで遊べるkubernetesクラスター環境を構築してみる

Last updated at Posted at 2022-12-13

はじめに

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として使えればありがたいです。

構成図

Screenshot 2022-12-12 at 8.48.26.png

各ラズパイと用途は以下のとおりです。固定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本だけが出てますが、完成したらこの箱の中にクラスターが構築されます。
IMG_3587.jpg

中はこんな感じ。狭いですが排熱に気をつけつつ配置しています。発熱源は主にHDDと電源です。
IMG_3588.jpg

ラズパイの基本設定

対象:全てのラズパイ 4台

OSセットアップ

以下よりmicroSDにOSをセットアップするツールをダウンロードしてください。
https://www.raspberrypi.com/software/

今回はUbuntu Server 20.04.5 LTS(64-bit)を使用します。
Screenshot 2022-12-13 at 8.08.16.png

初期設定

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=amd64arch=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
※必要に応じてパスワードは変更してください。
Screenshot 2022-12-12 at 12.18.16.png

ssh接続の有効化

インストール後にNAS用ラズパイへのssh接続が無効になるので有効にします。
Screenshot 2022-12-12 at 12.29.19.png

Screenshot 2022-12-12 at 12.28.30.png

HDDをext4フォーマット

フォーマット済のHDDをラズパイに接続して電源入った状態にしてください。
使用済HDDだったのでMacのDisk UtilityでexFATフォーマットしました。
Screenshot 2022-12-11 at 18.39.03.png

デバイスが認識されてることを確認します。
Screenshot 2022-12-12 at 12.38.10.png

パーティション作成します。

![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

共有フォルダ設定

プラス+ > ▶マウント よりマウントします。
Screenshot 2022-12-13 at 16.15.11.png

共有フォルダ設定をします。
Screenshot 2022-12-13 at 16.21.05.png

NFSを有効にします。
Screenshot 2022-12-13 at 16.55.54.png

NFSでの共有設定をします。
Screenshot 2022-12-13 at 16.27.52.png

ユーザーやグループに対して共有フォルダの権限を設定します。
※画面はユーザーに対して権限設定してます。
Screenshot 2022-12-13 at 16.29.32.png

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

絶対パスを取得する。
Screenshot 2022-12-13 at 17.03.18.png

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

さいごに

壊したり再構築したり自由に出来る環境が出来上がりました。最低限で構築したので、現在品薄状態のラズパイの販売が再開したらさらにノードを追加したり行きたいと思います。これでしばらく遊べそうです。

13
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?