ラズパイ5でお家k8sを構築する

# はじめに

tosaken1116 Advent Calendar 2024 1日目担当の土佐犬です


最近raspberry pi 5を手に入れる機会があったので今回はそれを使ってお家k8sを構築するという話です


# 必要材料

- raspberry pi 5  何台でも
- LANケーブル ラズパイの数分
- 電源ケーブル ラズパイの数分
- ラズパイ用ケースタワー ラズパイの数に応じた大きさのもの
- 電源ハブ 電源ケーブル分のポートがあるもの
- LANハブ LANケーブル分のポートがあるもの
- SDカード

ざっとこんな感じです

私は以下を購入しました
- ラズパイ 3台
- LANケーブル 15cm*4 CAT 6A
- - https://amzn.asia/d/09cQEli
- 電源ケーブル type C*4
- - https://amzn.asia/d/4Z9rAoZ
- ラズパイ用ケースタワー
- - https://amzn.asia/d/c3BzAGV
- 電源ハブ
- - https://amzn.asia/d/9QCo2YV
- LANハブ
- - https://amzn.asia/d/9wV9qSU
- SDカード 32GB
- - https://amzn.asia/d/1KGBeOi

LANケーブルと電源ケーブルは長さがギリギリだったので15cm*2と30cm*2とかをお勧めします

電源に関してraspberry 5は5V 3Aの電源が必要ですが調べたところ専用アダプターしか出てこず使うコンセントをひとつにしたかったのでACアダプターからtype Cで給電しています

LANケーブルは今のところCAT 6Aを使っていますCAT7？8？知らんな

10Gbpsはロマンありますが今のところそれ以外のところがボトルネックなので買いませんでした

ラズパイケースタワーは6段のものを買いました

今後拡張する可能性と今家にあるraspberry4を乗せるようですね


# 組み立て

組み立てていきます

![IMG_6662.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3230849/09735b4f-e023-5f5f-a1e5-7ebf7f94e836.jpeg)


とは言ってもそこまで複雑なものはありません

スペーサーつけて

![IMG_6664.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3230849/abc96546-04cb-032f-26b0-c7600c53492d.jpeg)

ベースに乗せて

![IMG_6665.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3230849/ea5eb324-324c-86eb-f9d0-b72f0a24e93d.jpeg)

組み立てて完成

![IMG_6666.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3230849/808cbe3b-3a59-7c15-144e-caea2152078d.jpeg)


ちなみにここでヒートシンクを貼り忘れてたことに気づいたので1回バラしました


配線完了 

![IMG_6667.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3230849/ca4272ad-47c8-5aee-b13f-9aa20865ac85.jpeg)


一番上はラズパイ4です

この子の電源は隣のankerの 8 in 1のアダプターから来てます

まぁまぁ使いやすいのでお勧めです

https://amzn.asia/d/7sWoAcw



# ソフトウェアの方
## OS書き込み
ということで組み立てが終わったのでSDカードにOSを書き込んでいきます

OS書き込みはRaspberry Pi Imagerを使いました

https://www.raspberrypi.com/software/

ラズパイといったらこれですね


書き込んだOSは`Raspberry pi lite`にしました

`RancherOS`というDockerに特化したOSがあるそうですが今回は一旦これで

ここら辺スクショ撮ってませんでしたが、Raspberry Pi Imagerでデフォルトのユーザーとパスワードの設定ができるのでそこでしておきました


## IP固定

基本的に何もしなければパソコンというものは起動するたびにルーターからプライベートIPが割り振られます。(実際はリース期間というものがあり一定期間のうちは同一IPが割り振られるが恒久的ではない)

sshするときに毎回プライベートIPを探し出すのは面倒なのでプライベートIPを固定しちゃいます

プライベートIPを固定する方法は2種類あります
1. ルーターから固定する
2. `/etc/network/interfaces`を書き換える


今回は1の`ルーターから固定する`でエイヤ！しました


うちはBuffaloのルーターを使っているのでこれの管理画面に入り特定のMACアドレスに対し、特定のIPを割り振ることができました

1. まずは`arp -a`コマンドを使って同一ネットワーク内の端末に割り振られているIPに適当にsshを仕掛けていく
2. 当たったらラッキー そのIPを覚えておく
3. ルーターの管理画面からIPが設定してあるデバイスに対し固定するIPを設定する

## ssh接続確認 ・ 公開鍵認証

次にssh接続をしていきます

最初はOSを入れるときに指定したユーザー名とパスワードを用いて認証を行います

```
ssh <username>@<private-ip>
```

接続が確認できたら、ゲストマシン側(ラズパイじゃない方)で公開鍵を作ります

```
ssh-keygen -t rsa -b 4096 -f ./.ssh/<鍵の名前>
```

次に生成した公開鍵をラズパイ側にコピーします

```
ssh-copy-id -i ~/.ssh/<鍵の名前>.pub <username>@<private-ip>
```

一旦疎通確認をします

```
ssh -i ./.ssh/<鍵の名前> <username>@<private-ip>
```

接続が確認できたらsshの設定ファイルを書き換えてめんどくさいコマンドを省略します

```
sudo vim ~/.ssh/config
```

```config:~/.ssh/config
Host <接続名>
        HostName <接続先 private ip>
        User <username>
        Port <ssh port:デフォルト`22`>
        IdentityFile <sshキーの場所 さっきのコマンド通りだと`~/.ssh/<鍵の名前>`>
```

これで
```
ssh <接続名>
```
で接続できるようになりました


疎通確認ができたらラズパイ側のパスワード認証を閉じておきます

sshd_configをいじる
```
sudo vi /etc/ssh/sshd_config
```

この行を変える
```diff
# To disable tunneled clear text passwords, change to no here!
- #PasswordAuthentication yes
+ PasswordAuthentication no
```

sshdを再起動
```
systemctl restart sshd
```

これでパスワード認証は弾かれて公開鍵認証が通ればOKです



## dockerを入れていく

まずはdockerを入れます

これはk8sが管理するコンテナランタイムです

ここをみてぽちぽちしていくだけです

https://docs.docker.com/engine/install/debian/



ここで私はubuntu系のインストールページを見てやったためエラーが出ました

`E: The repository 'https://download.docker.com/linux/ubuntu bookworm Release' does not have a Release file.`

アーキテクチャはちゃんと見ようね！

raspberry os liteはdebian系みたいです


## kubernetesをインストールする

さていよいよkubernetesをインストールします

そもそもkubernetesとは何かって話ですがkubernetesとはコンテナ化されたアプリケーションをデプロイ、スケーリング管理するためのプラットフォームです。(私も調べた限りの内容なので間違えてたらすみません)

公式サイト:https://kubernetes.io/ja/

何が嬉しいのって話ですが、簡単にいうと
- コンテナのスコープを絞れる
- - 特定のコンテナの間だけ通信できるようにできたりする
- コンテナが落ちても自動で再起動する
- - 障害が起きても安心
- トラフィックに応じて自動でスケーリングされる
- - 急なトラフィック増加、減少にも柔軟に対応



※筆者はフロントエンド専門なのでインフラは初心者です。これから頑張ります


kubernetesを構築するにあたり次の3つのツールをインストールします

kubelet ノードの管理をするエージェント

kubeadm　クラスタのセットアップや管理を行う

kubectl クラスタを操作するCLI


ここで`ノード`、`クラスタ`という概念が出てきましたが


`ノード`とはポッドを動かすマシン

`クラスタ`とは複数のノードを管理する単位,概念(??)

`ポッド`とは1つ以上のコンテナをまとめた単位 最小デプロイ単位


ポッドはノードに内包され、ノードはクラスタに内包されるといった感じです


でとりあえずこれらのツールをインストールします


インストールにはこちらの公式サイトを参考にしました

https://kubernetes.io/ja/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#kubeadm-kubelet-kubectl%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB

全てのラズパイにkubeadmとkubectlとkubeletのインストールをした後マスターノードのみkubeadm initを実行します


```
sudo kubeadm init
```


まぁ大体一発でうまくいくことってないんですよね


```
[init] Using Kubernetes version: v1.31.3
[preflight] Running pre-flight checks
W1121 07:39:45.421312    3965 checks.go:1080] [preflight] WARNING: Couldn't create the interface used for talking to the container runtime: failed to create new CRI runtime service: validate service connection: validate CRI v1 runtime API for endpoint "unix:///var/run/containerd/containerd.sock": rpc error: code = Unimplemented desc = unknown service runtime.v1.RuntimeService
    [WARNING Swap]: swap is supported for cgroup v2 only. The kubelet must be properly configured to use swap. Please refer to https://kubernetes.io/docs/concepts/architecture/nodes/#swap-memory, or disable swap on the node
    [WARNING SystemVerification]: missing optional cgroups: hugetlb
error execution phase preflight: [preflight] Some fatal errors occurred:
    [ERROR FileContent--proc-sys-net-ipv4-ip_forward]: /proc/sys/net/ipv4/ip_forward contents are not set to 1
[preflight] If you know what you are doing, you can make a check non-fatal with --ignore-preflight-errors=...
To see the stack trace of this error execute with --v=5 or higher
```

以下のコマンドを実行して多少どうにかなりました

```
sudo containerd config default | sudo tee /etc/containerd/config.toml
sudo vim /etc/containerd/config.toml
```

```
SystemdCgroup = true
```


```
sudo systemctl restart containerd
```
```
sudo vim /etc/sysctl.conf
```

```
net.ipv4.ip_forward=1
```

```
sudo sysctl -p
```


あとはここを見逃していました

https://arc.net/l/quote/ejjevthi


どうやらswapなるものを切っておかなきゃいけないらしいです

```
sudo swapoff -a
```


なんやかんやあり


```
Your Kubernetes control-plane has initialized successfully!
```


やったぜ！`control-plane`を初期化できた！！！！！！！！！

`kubectl config view`を実行してみる


```
apiVersion: v1
clusters: null
contexts: null
current-context: ""
kind: Config
preferences: {}
users: null
```

configがないですね

本来だったらここで長々とconfigが出てくるはずなんですが出てきませんでした

デフォルトではこのコンフィグは`~/.kube/config`を読むようになっていますが、ファイルの存在も確認できました


設定コピーもし直したりしてみました

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

治りません！！！！！

全部ドカーン！！して最初からやり直しました。



やり直したあとkubectl config view

```
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://<private ip>:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: kubernetes-admin
  name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
  user:
    client-certificate-data: DATA+OMITTED
    client-key-data: DATA+OMITTED
```

うまくいってそうです


それじゃぁこれをマスターノードとしてワーカーノードとの接続をします


ワーカーノードとマスターノードの接続はとても簡単です

`kubeadm init`を実行した時のログに

```
kubeadm join <private ip>:6443 --token <token> 	--discovery-token-ca-cert-hash <hash>
```

これをワーカーノードで実行するだけでマスターノードに接続できます

簡単！！

```
kubectl get nodes
```

![imagewm.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3230849/c18148cd-1f26-6f29-dedb-a2a584239b5e.png)

繋がりました


でもまだ全部`NotReady`ですね


インフラ強強な後輩に土下座して(してません)聞いたところCNIが入ってないんじゃないかと言われました

CNIとはポッド間通信をするためのものです

ということでCNIプラグインを入れます

CNIプラグインの代表的なものにCalicoとFlannelというものがありますが今回はCalicoを入れました

```
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.0/manifests/calico.yaml
```


![imagecni.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3230849/3114a4cc-6fd5-0f62-ed4d-21599beb23fa.png)

やったぜ

無事kubernetesが動くようになりました


# なんか動かす
動くようになったからには動かしたいですよね


ということでみんな大好きnginxを動かします

デプロイの作成をします

```
kubectl create deployment nginx --image=nginx
```

デプロイとはポッドとその管理をするオブジェクトです

デプロイを作成することによってReplicaSetが作成されます。

ReplicaSetによりポッドの増減やポッドのアップデートをすることができます

実際に作られたデプロイとReplicaSetを見てみましょう


```
kubectl get deployment 
```
```
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   0/1     1            0           7s
```


```
 kubectl get replicaset
```

```
NAME               DESIRED   CURRENT   READY   AGE
nginx-676b6c5bbc   1         1         1       7s
```

deploymentとreplicasetがそれぞれ一つずつ生成されています。


deploymentがREADYになっていませんがちょっとするとREADYになります

```
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           11s
```

さてこれでデプロイが作れましたがこのままではアクセスすることができません。

アクセスできるようにするにはサービスというリソースが必要になります

サービスは作成したデプロイメントのpodを外部に公開するための機能です。

以下のコマンドを実行してnginx デプロイをサービスとして扱います


```
kubectl expose deployment nginx --type=NodePort --port=80
```

NodePortとはノードのポートを解放することで外部からポッドにアクセスできるようにするサービスの種類です。

ここでは80番ポートにアクセスできるようにしています


kubectl describeコマンドを使ってサービスの詳細を覗きます

```
kubectl describe svc nginx
```
```
Name:                     nginx
Namespace:                default
Labels:                   app=nginx
Annotations:              <none>
Selector:                 app=nginx
Type:                     NodePort
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.107.23.138
IPs:                      10.107.23.138
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30357/TCP
Endpoints:                172.16.204.206:80
Session Affinity:         None
External Traffic Policy:  Cluster
Internal Traffic Policy:  Cluster
Events:                   <none>
```

ここで
```
NodePort:                 <unset>  30357/TCP
```

とあるので
`http://<worker nodeのprivate ip>:30357`
にアクセスします


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3230849/f256de25-62c8-49d2-17b3-0ae5bf8a277a.png)
見慣れたnginxの画面が出てきました


このポートも指定できるらしいですが今回はとりあえず動かしてみたかっただけなので割愛します



# 終わりに

ということで無事にお家kubernetesの構築ができました！！！！！


残念ながら筆者の家は賃貸でポート開放ができないので外部に公開とかはできませんが、そのうち引っ越すのでそれまではkubernetesの勉強だったりをするのに使いたいと思います