元ネタ
3日間クッキング【Kubernetes のラズペリーパイ包み “サイバーエージェント風”】
https://developers.cyberagent.co.jp/blog/archives/14721/
Raspberry PiでおうちKubernetes構築
https://qiita.com/go_vargo/items/d1271ab60f2bba375dcc
https://qiita.com/go_vargo/items/29f6d832ea0a289b4778
おうちKubernetesをOrange Piで構築する
https://www.tumblr.com/suzukiapple/182335667330/%E3%81%8A%E3%81%86%E3%81%A1kubernetes%E3%82%92orange-pi%E3%81%A7%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B
元ネタはもはや6年前ですが、kubernetesの練習用に手頃なクラスタが欲しかったので、Orange Piを使っておうちクラスタを構築しました。
以前はRaspberry Piも安かったので複数枚購入して物理的に冗長なクラスタを構築することも容易でしたが、今は1万円もするので、その辺の適当な小型PCを買うより高くついてしまいます。ロマンの要素が大きいのである程度費用はかかってもいいのですが、あまり高すぎるのも嫌なので、取れる選択肢の中では比較的安いOrange Pi Zero 2 (購入時の価格が1枚当たり3412円) を使うことにしました。サイズも小さいのでおうちクラスタ向きですが、上の記事で紹介されているような積層型ケースはこのサイズに合うものがなかったので、ケースから自作です。
材料
- 電子機器
- ケース
- ホームセンター購入
- アクリル板 厚さ2mm
- アクリルカッター
- アクリル板に穴を開けるための専用ビット M3
- なべ子ねじ M3x10mm
- monotaro購入
- 六角スペーサー M(mm): 3, L1(mm): 30, https://www.monotaro.com/p/8920/6381/ (1個72円x18)
- スペーサー 内径(Φmm): 約3.2, 外径(Φmm): 約6, 長さL(mm): 約3 (10個189円x2)
- ホームセンター購入
到着編
orange pi 到着。一応ヒートシンクを貼っておく。microSDになんらかのOSをコピーしてスロットに嵌めて電源を入れると起動。
とりあえず電源と有線でスイッチに繋いでみる。電源はtype C。最初はtype Cが3股に分かれているヒュドラみたいなケーブルを使ったが、変換先がtype Aで家にしょぼいアダプタしかなく電圧不足で不安定だったので、オーバーだが最大100Wでtype Cが3口あるアダプタを購入した(上の写真では1枚だけ別の電源に繋いでいる)。
物理編
ホームセンターとmonotaroで必要な材料を買い揃えて工作開始。やることは、1) アクリル板を同じサイズに5枚切り出す、2) 穴を開ける、3) 基盤をはめていくだけだが、DIY素人なのでわからないことだらけ。設計図はノートに書いていたが紛失した。スイッチの方が大きいのでそのサイズに合わせてアクリル板のサイズを決める。
まずアクリル板は紙が貼ってあるのでそこに線を引いて、アクリルカッターで何度も傷をつけていく。ある程度傷をつけたら力を入れてバキッと割る。
アクリル板専用ビットというのがあるので、電動ドリルにセットして狙いをつけて穴を開ける(写真なし)。慣れてきたら複数枚貫通もできるようになった。とりあえず1枚作って、基盤をはめてみる。緊張の一瞬。
ネジはM3の10mm、スペーサーは内径3.2mm、長さ3mmのやつでピッタリハマった。
穴あけの精度が低いのでガタガタだが、ちゃんと固定されている。
1枚できたので板を量産。板を連結させる部品は六角スペーサーで、M3 30mmを使用。スイッチもギリギリ入った。
自分の中ではすごく良くできたので、ここで満足して10ヶ月ほど放置してた。
論理編
OS
最初はArmbianをトライ
./compile.sh BOARD=orangepizero2 BRANCH=current RELEASE=jammy BUILD_MINIMAL=no BUILD_DESKTOP=no KERNEL_CONFIGURE=no COMPRESS_OUTPUTIMAGE=sha,img
こんな感じでビルドしてsdカードにコピーして転送して電源を入れてみたが起動せず。
次にOrange Pi OSを使ったら起動できた。この辺からダウンロードする。
$ uname -a Linux orangepi1 5.16.17-sun50iw9 #3.0.6 SMP Tue Aug 9 13:51:16 CST 2022 aarch64 aarch64 aarch64 GNU/Linux
最終的にk3sも問題なくインストールできたので、このまま。
hostnameなど諸々設定する。技適を通ってないらしいので無線はオフにしておく。
kubernetes
最初kubeadmでクラスタ構築したところスペックが足らずagentがまともに動いてくれない。
Orange Pi Zero 2 のスペックはCPU 4core、RAM 1GB
http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-Zero-2.html
kubeadmは1台あたり2GB以上のメモリ、2コア以上のCPU
https://kubernetes.io/ja/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#%E5%A7%8B%E3%82%81%E3%82%8B%E5%89%8D%E3%81%AB
kubeadmが要求するスペックには足らないので動くはずがなかった。
そこで、k3sに変更して構築。とはいえk3sでもメモリを50%使ってしまうので、その上でアプリを動かすのはちょっと厳しかったりする。
k3sの最小要求スペックはCPU 1core, RAM 512MB
https://docs.k3s.io/installation/requirements#hardware
https://docs.k3s.io/quick-start を見てインストール。
master
curl -sfL https://get.k3s.io | sh -`
トークンはmasterとしてインストールしたノードの/var/lib/rancher/k3s/server/node-tokenにあるのでそれを使ってworkerをクラスタに参加させる。
worker
curl -sfL https://get.k3s.io | K3S_URL=https://<master IP>:6443 K3S_TOKEN=<token> sh -`
masterはsystemctl status k3sでサービスがrunningであればOK。
root@orangepi0:~# systemctl status k3s ● k3s.service - Lightweight Kubernetes Loaded: loaded (/etc/systemd/system/k3s.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2024-02-16 04:57:51 UTC; 21h ago Docs: https://k3s.io Process: 1180 ExecStartPre=/bin/sh -xc ! /usr/bin/systemctl is-enabled --quiet nm-cloud-setup.service (code=exited, status=0/SUCCESS) Process: 1212 ExecStartPre=/sbin/modprobe br_netfilter (code=exited, status=0/SUCCESS) Process: 1227 ExecStartPre=/sbin/modprobe overlay (code=exited, status=0/SUCCESS) Main PID: 1242 (k3s-server) Tasks: 168 Memory: 574.5M CPU: 4h 42min 36.180s CGroup: /system.slice/k3s.service ├─ 1242 "/usr/local/bin/k3s server" ├─ 1549 containerd -c /var/lib/rancher/k3s/agent/etc/containerd/config.toml -a /run/k3s/containerd/containerd.sock --state /run/k3s/containerd --root /var/lib/rancher/k3s/agent/containerd ├─ 3189 /var/lib/rancher/k3s/data/4b147cafa965066cd68e04b4e3acce221078156a3b9ba635a653517ce459aa4d/bin/containerd-shim-runc-v2 -namespace k8s.io -id 6a9b2179460499f83fccf0e3e752da80df73dc4fd2008246d9f05d474223a5cf -address /run/> ├─ 3191 /var/lib/rancher/k3s/data/4b147cafa965066cd68e04b4e3acce221078156a3b9ba635a653517ce459aa4d/bin/containerd-shim-runc-v2 -namespace k8s.io -id 4b72dac5a3580db534217d7ad77e623207283182e7a724980927ce2ed54efcc6 -address /run/> ├─ 3192 /var/lib/rancher/k3s/data/4b147cafa965066cd68e04b4e3acce221078156a3b9ba635a653517ce459aa4d/bin/containerd-shim-runc-v2 -namespace k8s.io -id 983bd04163555f91a88d8a6622c93126984f8444fd5b56a8364ec45f487cdc2e -address /run/> ├─ 3214 /var/lib/rancher/k3s/data/4b147cafa965066cd68e04b4e3acce221078156a3b9ba635a653517ce459aa4d/bin/containerd-shim-runc-v2 -namespace k8s.io -id d742755983a44dc20df14c80b60b062d9086c9061ce32a47e811caa1b8d864e5 -address /run/> ├─ 3220 /var/lib/rancher/k3s/data/4b147cafa965066cd68e04b4e3acce221078156a3b9ba635a653517ce459aa4d/bin/containerd-shim-runc-v2 -namespace k8s.io -id 18db82abea3ef6c042d374ac6f533472015017e4bc982296934946ca04e7f614 -address /run/> ├─ 3284 /var/lib/rancher/k3s/data/4b147cafa965066cd68e04b4e3acce221078156a3b9ba635a653517ce459aa4d/bin/containerd-shim-runc-v2 -namespace k8s.io -id 3218418fb35f9e1baf79238d75c0b0287198ef34c24fe43c4ce6471ef676099e -address /run/> ├─29887 /var/lib/rancher/k3s/data/4b147cafa965066cd68e04b4e3acce221078156a3b9ba635a653517ce459aa4d/bin/containerd-shim-runc-v2 -namespace k8s.io -id 2ee4d3c1b05ec228d382a334e5843407714b52057bd835f575d2e5679fb15261 -address /run/> └─36552 /var/lib/rancher/k3s/data/4b147cafa965066cd68e04b4e3acce221078156a3b9ba635a653517ce459aa4d/bin/containerd-shim-runc-v2 -namespace k8s.io -id 38009dff653bc3f9de5f75b14f5d34a27192ae1f92518f44efcb6aeb19da0e5f -address /run/>
workerはsystemctl status k3s-agent
root@orangepi1:~# systemctl status k3s-agent ● k3s-agent.service - Lightweight Kubernetes Loaded: loaded (/etc/systemd/system/k3s-agent.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2024-02-16 04:58:08 UTC; 21h ago Docs: https://k3s.io Process: 1121 ExecStartPre=/bin/sh -xc ! /usr/bin/systemctl is-enabled --quiet nm-cloud-setup.service 2>/dev/null (code=exited, status=0/SUCCESS) Process: 1171 ExecStartPre=/sbin/modprobe br_netfilter (code=exited, status=0/SUCCESS) Process: 1173 ExecStartPre=/sbin/modprobe overlay (code=exited, status=0/SUCCESS) Main PID: 1176 (k3s-agent) Tasks: 108 Memory: 255.6M CPU: 2h 12min 59.043s CGroup: /system.slice/k3s-agent.service ├─ 1176 "/usr/local/bin/k3s agent" ├─ 1540 "containerd " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""> ├─ 2608 /var/lib/rancher/k3s/data/51f1454895fb5bca15f0e8fb5310ff90ba7fc1c3fc5a8c9d052f8570f3483527/bin/containerd-shim-runc-v2 -namespace k8s.io -id 972e5d21c2333155394ccdcc86c81e94175dc4ae4b625a0976acd938b51c7a6a -address /run/> ├─ 2610 /var/lib/rancher/k3s/data/51f1454895fb5bca15f0e8fb5310ff90ba7fc1c3fc5a8c9d052f8570f3483527/bin/containerd-shim-runc-v2 -namespace k8s.io -id a21f011d5021b372cfdfedc3b27bef9a726642e777f657ba2342df538f5e6a1d -address /run/> ├─ 2611 /var/lib/rancher/k3s/data/51f1454895fb5bca15f0e8fb5310ff90ba7fc1c3fc5a8c9d052f8570f3483527/bin/containerd-shim-runc-v2 -namespace k8s.io -id 8419a10fea3394caf90e961145507b4ea957f103e273109af9df4d3ef27140c5 -address /run/> ├─33392 /var/lib/rancher/k3s/data/51f1454895fb5bca15f0e8fb5310ff90ba7fc1c3fc5a8c9d052f8570f3483527/bin/containerd-shim-runc-v2 -namespace k8s.io -id 0d270807cbd8a1a8c534427a5629d6575f93bc1d0e9f3a46a1df787c300161a2 -address /run/> ├─33877 /var/lib/rancher/k3s/data/51f1454895fb5bca15f0e8fb5310ff90ba7fc1c3fc5a8c9d052f8570f3483527/bin/containerd-shim-runc-v2 -namespace k8s.io -id 19e1d88e105a164c04b5d0bf95330e95a8ab89d54f3d9a8bc5bffcbc58acef7c -address /run/> └─39262 /var/lib/rancher/k3s/data/51f1454895fb5bca15f0e8fb5310ff90ba7fc1c3fc5a8c9d052f8570f3483527/bin/containerd-shim-runc-v2 -namespace k8s.io -id 310059e2e512ecb45104a075ca5666c2deba423068006457305ffe3dfd6a6747 -address /run/>
nodeの確認。kubeconfig は https://docs.k3s.io/cluster-access をみる
kubectl get nodes NAME STATUS ROLES AGE VERSION orangepi1 Ready <none> 19d v1.28.5+k3s1 orangepi2 Ready <none> 19d v1.28.5+k3s1 orangepi0 Ready control-plane,master 279d v1.26.4+k3s1
用途
squidで広告ブロックしてみようかなーと思って、squidをデプロイ。
Dockerfile
FROM ubuntu:22.04 RUN apt-get update && apt-get install -y squid COPY entrypoint.sh /entrypoint.sh RUN chmod 755 /entrypoint.sh RUN mkdir -p /etc/squid/list COPY adaway.txt /etc/squid/list/adaway.txt ENTRYPOINT [ "/entrypoint.sh" ]
adaway.txtは適当に拾ってきたリスト。
entrypoint.sh
#!/bin/bash -e chown proxy:proxy /dev/stdout exec $(which squid) -NYCd 1
- 標準出力にログを出力するために、/dev/stdoutのownerの変更をしている
- imageはローカルでビルドしてdocker.ioにpush
--- apiVersion: apps/v1 kind: Deployment metadata: name: squid labels: app: squid spec: replicas: 2 selector: matchLabels: app: squid template: metadata: labels: app: squid spec: nodeSelector: role: worker containers: - name: squid image: <repo> imagePullPolicy: Always ports: - containerPort: 3128 protocol: TCP name: squid volumeMounts: - name: data mountPath: /var/spool/squid - name: squid-config mountPath: /etc/squid/squid.conf subPath: squid.conf volumes: - name: data emptyDir: {} - name: squid-config configMap: name: squid-config --- apiVersion: v1 kind: ConfigMap metadata: name: squid-config data: squid.conf: | acl block_domain dstdomain -n "/etc/squid/list/adaway.txt" http_access deny block_domain http_access allow all http_port 3128 logfile_rotate 0 cache_log stdio:/dev/stdout access_log stdio:/dev/stdout --- apiVersion: v1 kind: Service metadata: name: squid spec: type: LoadBalancer ports: - name: "http-port" protocol: "TCP" port: 3128 targetPort: squid selector: app: squid
k3sはServiceLBというロードバランサーを使ってノードの外部にサービスをexposeできる https://docs.k3s.io/networking#how-the-service-lb-works
ついでにfluent bitでログをS3に転送する。fluent bitは以下のvaluesを使ってhelmでインストールする。
env: - name: AWS_ACCESS_KEY_ID valueFrom: secretKeyRef: name: aws-key-secret key: aws-access-key-id - name: AWS_SECRET_ACCESS_KEY valueFrom: secretKeyRef: name: aws-key-secret key: aws-secret-access-key config: outputs: | [OUTPUT] Name s3 Match kube.var.log.containers.squid* region <region> bucket <bucket> s3_key_format /squid-logs/%Y/%m/%d/%Y-%m-%dT%H:%M:%SZ-$UUID.log
環境変数でaccess keyの設定と(secretは別途必要)、outputの設定だけ。<ノードのIP>:3128をproxyに指定して、広告ブロッカーの動作とログの転送が確認できた。