はじめに
tosaken1116 Advent Calendar 2024 1日目担当の土佐犬です
最近raspberry pi 5を手に入れる機会があったので今回はそれを使ってお家k8sを構築するという話です
必要材料
- raspberry pi 5 何台でも
- LANケーブル ラズパイの数分
- 電源ケーブル ラズパイの数分
- ラズパイ用ケースタワー ラズパイの数に応じた大きさのもの
- 電源ハブ 電源ケーブル分のポートがあるもの
- LANハブ LANケーブル分のポートがあるもの
- SDカード
ざっとこんな感じです
私は以下を購入しました
- ラズパイ 3台
- LANケーブル 15cm*4 CAT 6A
- 電源ケーブル type C*4
- ラズパイ用ケースタワー
- 電源ハブ
- LANハブ
- SDカード 32GB
LANケーブルと電源ケーブルは長さがギリギリだったので15cm2と30cm2とかをお勧めします
電源に関してraspberry 5は5V 3Aの電源が必要ですが調べたところ専用アダプターしか出てこず使うコンセントをひとつにしたかったのでACアダプターからtype Cで給電しています
LANケーブルは今のところCAT 6Aを使っていますCAT7?8?知らんな
10Gbpsはロマンありますが今のところそれ以外のところがボトルネックなので買いませんでした
ラズパイケースタワーは6段のものを買いました
今後拡張する可能性と今家にあるraspberry4を乗せるようですね
組み立て
組み立てていきます
とは言ってもそこまで複雑なものはありません
スペーサーつけて
ベースに乗せて
組み立てて完成
ちなみにここでヒートシンクを貼り忘れてたことに気づいたので1回バラしました
配線完了
一番上はラズパイ4です
この子の電源は隣のankerの 8 in 1のアダプターから来てます
まぁまぁ使いやすいのでお勧めです
ソフトウェアの方
OS書き込み
ということで組み立てが終わったのでSDカードにOSを書き込んでいきます
OS書き込みはRaspberry Pi Imagerを使いました
ラズパイといったらこれですね
書き込んだOSはRaspberry pi lite
にしました
RancherOS
というDockerに特化したOSがあるそうですが今回は一旦これで
ここら辺スクショ撮ってませんでしたが、Raspberry Pi Imagerでデフォルトのユーザーとパスワードの設定ができるのでそこでしておきました
IP固定
基本的に何もしなければパソコンというものは起動するたびにルーターからプライベートIPが割り振られます。(実際はリース期間というものがあり一定期間のうちは同一IPが割り振られるが恒久的ではない)
sshするときに毎回プライベートIPを探し出すのは面倒なのでプライベートIPを固定しちゃいます
プライベートIPを固定する方法は2種類あります
- ルーターから固定する
-
/etc/network/interfaces
を書き換える
今回は1のルーターから固定する
でエイヤ!しました
うちはBuffaloのルーターを使っているのでこれの管理画面に入り特定のMACアドレスに対し、特定のIPを割り振ることができました
- まずは
arp -a
コマンドを使って同一ネットワーク内の端末に割り振られているIPに適当にsshを仕掛けていく - 当たったらラッキー そのIPを覚えておく
- ルーターの管理画面から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
Host <接続名>
HostName <接続先 private ip>
User <username>
Port <ssh port:デフォルト`22`>
IdentityFile <sshキーの場所 さっきのコマンド通りだと`~/.ssh/<鍵の名前>`>
これで
ssh <接続名>
で接続できるようになりました
疎通確認ができたらラズパイ側のパスワード認証を閉じておきます
sshd_configをいじる
sudo vi /etc/ssh/sshd_config
この行を変える
# To disable tunneled clear text passwords, change to no here!
- #PasswordAuthentication yes
+ PasswordAuthentication no
sshdを再起動
systemctl restart sshd
これでパスワード認証は弾かれて公開鍵認証が通ればOKです
dockerを入れていく
まずはdockerを入れます
これはk8sが管理するコンテナランタイムです
ここをみてぽちぽちしていくだけです
ここで私は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つ以上のコンテナをまとめた単位 最小デプロイ単位
ポッドはノードに内包され、ノードはクラスタに内包されるといった感じです
でとりあえずこれらのツールをインストールします
インストールにはこちらの公式サイトを参考にしました
全てのラズパイに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
あとはここを見逃していました
どうやら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
繋がりました
でもまだ全部NotReady
ですね
インフラ強強な後輩に土下座して(してません)聞いたところCNIが入ってないんじゃないかと言われました
CNIとはポッド間通信をするためのものです
ということでCNIプラグインを入れます
CNIプラグインの代表的なものにCalicoとFlannelというものがありますが今回はCalicoを入れました
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.0/manifests/calico.yaml
やったぜ
無事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
にアクセスします
このポートも指定できるらしいですが今回はとりあえず動かしてみたかっただけなので割愛します
終わりに
ということで無事にお家kubernetesの構築ができました!!!!!
残念ながら筆者の家は賃貸でポート開放ができないので外部に公開とかはできませんが、そのうち引っ越すのでそれまではkubernetesの勉強だったりをするのに使いたいと思います