《树莓派4B家庭服务器搭建指南》第十四期:使用树莓派4B搭建k8s集群
title: 《树莓派4B家庭服务器搭建指南》第十四期:使用树莓派4B搭建k8s集群
k8s是谷歌推出一款服务器集群管理工具, 开源免费, 功能强大, 可以创造一个人管理服务器集群的奇迹。
k8s 通用型极强,是一套标准的运维策略,只要程序部署到服务器,就要考虑程序稳定性的问题,而k8s的弹性扩容,以及多主机相互备份策略,即使部分服务器物理宕机,被黑客DDOS攻击,也能通过内置策略自动进行应对。
k8s由谷歌开源,而且谷歌自家也在用这套方案,我们能免费获得持续稳定的技术支持和版本迭代。
k8s是一套商业级的完整解决方案,如果想要踏入专业的运维领域, 获得一份糊口的运维工作, 也要熟悉k8s这套堪称业界标杆的工具。
这篇博客记录zhaoolee使用树莓派建立k8s集群的全过程,如果你对树莓派k8s集群感兴趣,这篇博客会给你很多帮助。
首先,将树莓派连接到同一个局域网环境下, 为了保证稳定性,最好将路由器与树莓派通过网线相连,为了避开乱七八糟的依赖包下载问题,路由器需要支持科学上网~
本文使用的三台树莓派4B均为8GB版本,镜像选的是Ubuntu20.04, 如果对树莓派刷镜像有疑问,可以点击往期 《树莓派4B家庭服务器搭建指南》刷Ubuntu Server 20.04,绑定公网域名,对公网提供http服务,SSH登录服务 https://www.v2fy.com/p/2021-10-01-pi-server-1633066843000/
本文安装的K8s版本为v1.23.1
首先三台树莓派运行的ubuntu20.04,安装网络工具包
sudo apt install net-tools -y
为三台树莓派设置固定的ip
可以在路由器Web端通过树莓派mac地址与ip进行绑定完成设置
也可以通过树莓派直接设置静态ip, 参考教程 为Ubuntu 20.04 设置静态IP简明教程(和把大象装冰箱一样简单)https://www.v2fy.com/p/2022-01-01-ip-1641016585000/
通过 hostnamectl 设置主机名
我的路由器为三台树莓派分别分配了192.168.50.10
, 192.168.50.20
, 192.168.50.30
, 后面的内容也会反复提到这几个ip,如果你的ip与我不同,请自行替换即可。
在ip为192.168.50.10
的 master主机执行
hostnamectl set-hostname master
在ip为192.168.50.20
的 node1主机执行
hostnamectl set-hostname node1
在ip为192.168.50.30
的 node2主机执行
hostnamectl set-hostname node2
设置完成后,可通过以下命令查看本机信息
hostnamectl status
如果你的shell终端显示主机名,则可以通过主机名进行方便的区分
修改host并创建别名
在三台树莓派的/etc/hosts
内添加以下配置
192.168.50.10 master
192.168.50.20 node1
192.168.50.30 node2
Ubuntu20.04 已经放弃的SELinux,所以关于SELinux的设置,我们无需处理
K8s V1.22版本开始已经支持使用swap,我们也无需关闭swap内存
为了保证master与node之间的通信,我们需要关闭树莓派防火墙
ufw,或称Uncomplicated Firewall,是iptables的一个接口,为不熟悉防火墙概念的初学者提供了易于使用的界面,同时支持IPv4和IPv6,广受欢迎。Ubuntu20.04 默认安装了防火墙管理工具ufw,我们可以在三台树莓派执行以下命令,关闭防火墙。
# 关闭防火墙
sudo ufw disable
# 检测防火墙状态
sudo ufw status
树莓派一般在内网,不容易遭受攻击,如果是外网的机器,建议还是只开放必要的端口
需要开放端口的参考资料:https://kubernetes.io/docs/reference/ports-and-protocols/
安装Docker
三台树莓派各自运行以下命令,完成Docker的安装
sudo apt update
sudo apt install \
apt-transport-https \
ca-certificates \
curl \
gnupg \
lsb-release -y
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install docker-ce=5:20.10.8~3-0~ubuntu-focal docker-ce-cli=5:20.10.9~3-0~ubuntu-focal containerd.io=1.4.11-1 -y
docker -v
安装k8s
- 在三台树莓派 安装 kubectl kubelet kubeadm
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubectl kubelet kubeadm
- 查看kubectl是否安装成功
kubectl version --client
- 查看kubelet是否安装成功
kubelet --version
- 查看kubeadm是否安装成功
kubeadm version
在三台树莓派 运行以下命令,保证kubelet和docker启动,并设置开机启动
sudo systemctl enable kubelet
sudo systemctl start kubelet
sudo systemctl enable docker
sudo systemctl start docker
修改docker 配置
sudo chmod 777 -R /opt/
cd /opt
# kubernetes 官方推荐 docker 等使用 systemd 作为 cgroupdriver,否则 kubelet 启动不了
cat <<EOF > daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"]
}
EOF
sudo mv daemon.json /etc/docker/
# 重启生效
sudo systemctl daemon-reload
sudo systemctl restart docker
修改树莓派的配置,并重启
sudo vim /boot/firmware/cmdline.txt
cgroup_enable=memory cgroup_memory=1
修改完成后,重启树莓派
reboot
在master节点初始化集群
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
注意这里要追加
--pod-network-cidr=10.244.0.0/16
参数
最后的token文本要好好保存起来,子节点加入master要用到
kubeadm join 192.168.50.10:6443 --token tn3*********9f7 --discovery-token-ca-cert-hash sha256:3862***46739303********94
- 将kubeadm授权文件复制到用户根目录,以便kubectl 可以有权限访问集群
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
最终授权文件的内容,如下图的格式
- 在master节点安装一个网络插件,方便node节点后续连接通信
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
- 安装插件后,等待各节点Ready
kuberctl get nodes
在node1和node2运行以下命令,将node1和node2加入到master节点
sudo kubeadm join 192.168.50.10:6443 --token tn3*********9f7 --discovery-token-ca-cert-hash sha256:3862***46739303********94
以上命令中的token参数,都由master节点,运行 sudo kubeadm init 时产生,如果忘记了可以通过在master节点运行sudo kubeadm token create --print-join-command
重新获取
- 在master节点运行kubectl get nodes 查看各节点状态,当所有节点Ready, 即大功告成!
安装Kuboard
mkdir ~/kuboard-data
sudo docker run -d --restart=unless-stopped --name=kuboard -p 30080:80/tcp -p 10081:10081/tcp -e KUBOARD_ENDPOINT="http://192.168.50.10:30080" -e KUBOARD_AGENT_SERVER_TCP_PORT="10081" -v ~/kuboard-data:/data eipwork/kuboard:v3
访问 http://192.168.50.10:30080 即可访问到Kuboard
登录用户名: admin
登录密码: Kuboard123
- 添加集群
- 选择.kubeconfig方式导入集群
- 获取 ~/.kube/config信息
cat ~/.kube/config
将~/.kube/config的文本信息贴入页面
导入成功
所有namespace和节点信息尽收眼底
创建service
apiVersion: apps/v1
kind: Deployment
metadata:
# 部署名字
name: pi-k8s-test
namespace: ingress-nginx
spec:
replicas: 2
# 用来查找关联的 Pod,所有标签都匹配才行
selector:
matchLabels:
app: pi-k8s-test
# 定义 Pod 相关数据
template:
metadata:
labels:
app: pi-k8s-test
spec:
# 定义容器,可以多个
containers:
- name: pi-k8s-test # 容器名字
image: zhaoolee/pi-k8s-test:001 # 镜像
---
apiVersion: v1
kind: Service
metadata:
name: pi-k8s-test
namespace: ingress-nginx
spec:
selector:
app: pi-k8s-test
type: NodePort
ports:
- port: 3000 # 本 Service 的端口
targetPort: 3000 # 容器端口
从上面的yaml文本中,可以看出,我们使用镜像zhaoolee/pi-k8s-test:001, 新建了两个pod(pod可以容纳N个镜像运行产生的容器),这两个pod会被k8s自动调度到不同的节点上,node1和node2各一个
而yaml文件的下半部分,则创建了一个服务service,这个服务是pod的父级,我们可以通过service暴露的3000端口来访问pod,service也就是一个原子化的服务,我们可以创建大量的service, 来应对不同的场景
但大量的service管理起来很麻烦,占用的端口也很杂乱,我们还需要一个类似Nginx的网关,来统一接收外部请求,然后通过在Nginx设置好的规则,将请求分发到对应的service, 这个类似Nginx的部分,在k8s中被称为ingress, 而ingress恰好有一个基于nginx开发的版本,被称为NGINX Ingress Controller,下面我将开始配置安装NGINX Ingress Controller
安装helm
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
这个helm可以方便我们方便的安装NGINX Ingress Controller, 以及后续白嫖很多别人现成的服务配置。
安装NGINX Ingress Controller
helm upgrade --install ingress-nginx ingress-nginx --repo https://kubernetes.github.io/ingress-nginx --namespace ingress-nginx --create-namespace
参考地址 https://kubernetes.github.io/ingress-nginx/deploy/#quick-start
与nginx类型,NGINX Ingress Controller需要配置规则才能按照我们的需求转发请求,下面我们配置一个简单规则。
为ingress添加规则
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress
namespace: ingress-nginx
spec:
ingressClassName: nginx
rules:
- http:
paths:
- backend:
service:
name: pi-k8s-test
port:
number: 3000
path: /
pathType: ImplementationSpecific
上面的配置文件,可以通过kuboard直接在页面上,通过从YAML创建出来,它配置的规则就是,把指向根路径/
的请求,统统发送到pi-k8s-test服务的3000端口。
如果报错Internal error occurred: failed calling webhook “validate.nginx.ingress.kubernetes.io, 则
kubectl get validatingwebhookconfigurations
kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission
虽然ingress也是个服务,但ingress这个服务比较特别,它需要获得和树莓派级别的ip才能运行(类似192.168.50.*
这种格式),ingress被称为loadbalancer类型的服务。
但k8s 本体不提供对 loadbalancer类型的支持,我们需要自己额外去安装一个名为metallb的开源软件,获得k8s对loadbalancer类型支持。如果我们不安装metallb,loadbalancer类型的服务,只能一直保持在pending的状态。
安装metallb
首先开启strictARP选项
kubectl edit configmap -n kube-system kube-proxy
输入以上命令后,会进入vim编辑器模式,我们将配置中的strictARP: false
改为 strictARP: true
strictARP: true
- 创建metallb专用的namespace
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.5/manifests/namespace.yaml
- 部署metallb
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.5/manifests/metallb.yaml
- 创建memberlist secret, 这个secret是用来加密speaker之间的通信
kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)"
- 通过kuboard 创建ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
namespace: metallb-system
name: config
data:
config: |
address-pools:
- name: default
protocol: layer2
addresses:
- 192.168.50.240-192.168.50.250
这里注意最后一行addresses配置,我树莓派上层的路由器是192.160.50.*
段,所以配置为192.168.50.240-192.168.50.250
请按照自己路由器的配置,按需更改。
- 查看LoadBalancer类型的ingress-nginx-controller
kubectl get svc -A
ingress-nginx-controller
被分配到的ip为192.168.50.240
我们在局域网的电脑中访问http://192.168.50.240
我们访问192.168.50.240,就相当于访问了ingress-nginx-controller, 而ingress-nginx-controller会把我们的请求,按照规则,转发到我们前面建立的service中,service自动将请求转发到两个Pod中进行分别处理,而多个Pod本身运行在不同的node节点上(不同树莓派上),即使某个node挂掉,也可对外稳定提供服务。
如果我们收到的请求量变大,我们通过增大pod数量,或增加更多树莓派(node节点)的方式,处理请求。
参考资料:https://www.bboy.app/2021/01/11/metallb%E9%83%A8%E7%BD%B2%E4%BD%BF%E7%94%A8/
如何快速变更镜像?
我们前面使用了zhaoolee/pi-k8s-test:001镜像,如果要变更到zhaoolee/pi-k8s-test:002镜像,只需打开kuboard,改镜像版本即可。
k8s集群会自动拉取镜像,完成更新
- 内容更新成功
将树莓派服务穿透到外网
通过前几步的准备,我们已经将 192.168.50.240 做为我们的k8s集群入口,接下来我们只需通过frp将 192.168.50.240 穿透到公网的k8s.v2fy.com, 即可实现外网访问树莓派集群提供的服务
-
最终效果展示
192.168.50.10负责运行master, 并不能访问我们的负载均衡ip 192.168.50.240, 而node1(192.168.50.20)节点和node2(192.168.50.20)节点所在的机器可以顺利访问负载均衡ip
我们选择在node1节点所在的树莓派上,开启frp客户端服务
frpc.ini
配置文件
[common]
server_addr = 120.76.136.220
server_port = 7000
token = '********'
log_file = './frpc.log'
[pi-k8s]
type = tcp
local_ip = 192.168.50.240
local_port = 80
remote_port = 9666
配置文件的作用是,将内网192.168.50.240:80
穿透到公网120.76.136.220:9666
- 将自己的域名,(比如k8s.v2fy.com) ,解析到公网服务器ip (比如120.76.136.220)
然后通过公网服务器Nginx,代理k8s.v2fy.com, 将指向k8s.v2fy.com 80端口和443端口的请求,全部转发到9666端口
Nginx参考配置文件 /etc/nginx/conf.d/k8s.v2fy.com.conf
upstream k8s_v2fy_com { server 127.0.0.1:9666; }
server {
server_name k8s.v2fy.com;
listen 80;
listen [::]:80;
rewrite ^(.*)$ https://$host$1 permanent;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name k8s.v2fy.com;
location / {
proxy_pass http://k8s_v2fy_com;
proxy_set_header Host $host:443;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
ssl_certificate "/etc/nginx/ssl/k8s.v2fy.com/fullchain.cer";
ssl_certificate_key "/etc/nginx/ssl/k8s.v2fy.com/k8s.v2fy.com.key";
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
- 如何获取自动续期的https证书?
安装证书完成后,记得重启Nginx
sudo nginx -t
sudo systemctl restart nginx
- 最后我们可以通过https://k8s.v2fy.com 访问到我们内网k8s的服务了
小结
如果你只是想学习k8s技术,而不是搭建集群,完全可以用minikube来学习, Ubuntu20.04试水k8s单机版minikube部署实录 https://www.v2fy.com/p/2021-07-26-k8s-1627292526000/
我从2022年元旦开始,便开始折腾树莓派裸机搭建k8s,时至发文,已有5天。k8s确实是诱人的技术,技术爱好者经过几天的学习,便能顺利搭建自己的集群,并跑起自建的服务。k8s集群设计的思想,也确实称得上极好的教材,通过层层抽象分离,让各种服务pod的调度变得明确,排查问题也变得简单,同时让众多服务的管理变得简单。
2022年, 投机者依然想着发各种币来割韭菜, 挖矿消耗了大量电力, 只是为了算一个无意义的字符串, 即使不懂计算机的人, 喊两句分布式, 就能成为一名合格的韭菜, 生生不息, 真正通过分布式管理服务器集群的k8s系统却无人问津, 毕竟提供稳定的系统产生的价值无法被大多数人理解, 著名艺术家孙宇晨老师拿着祖传100万到处炒热度, 蹭热点远比理解分布式系统的人来钱快, 但能提升生产力的k8s技术, 学得好, 不用反复横跳, 也能卖个好价钱, 即使是挖矿, 用k8s集群批量管理挖矿主机的人, 也能对那些开着N台Windows挖矿的人形成降维打击。
发表回复