沉默和消失是为了更好的复出。
本篇博客旨在以k3s运行wordpress(残血高可用)的任务驱动下进行k8s集群入门。
基础环境为树莓派Raspberry Pi4B *3 +Raspbian(Lite) +Docker
示例为4G RAM*1 + 8G RAM*2
简单的铺垫和回顾。
我们为什么需要集群?针对我们的任务,搭建一个网站,我们可以说集群是一种大大提高网络吞吐量和稳定性的方式,也就是平常说的高可用,高并发。就计算机资源利用的方面,他,尤其是k8s架构,使跨服务器的调度和资源分配来构建产品成为可能。
首先可以看一下这个视频和示例对k8s进行初步了解。Kubernetes一小时入门课程 – 视频配套笔记 | GeekHour讲的很好,这里不提供笔记下载,希望多支持官方!
初步了解后我们就能开始了。因为树莓派的性能确实有些羸弱,我们选择k3s,并且不接入额外的数据库服务器。官网在这里K3s – Lightweight Kubernetes | K3s可以作为参考
0.准备工作
- 明确硬件分工
- 硬件准备
- 操作系统安装
- cmdline.txt参数修改
- 关闭交换空间
- 分配ip地址
I 首先我们明确系统分工。三台树莓派分别为4g0,8g0,8g1在我们的系统当中,4G RAM的树莓派作为Master节点,8g0和8g1作为Slave节点,其中8g1还负责NFS卷的承载,但是NFS服务不在k3s体系内,由人工控制。
II 然后是硬件的准备。笔者准备了五口千兆的交换机,用来扩展网络,路由器负责DHCP,三个ssd+硬盘盒做为三台设备的系统盘加储存。(本来想用PXE网络启动和专门的文件服务器,无奈设备数量和配置不足。)
III 操作系统安装不做赘述,最新的64位Lite就可以,这个没墙也可以找官网,记得扩展储存空间。
IV 安装操作系统并且启动后ssh链接,修改cmdline.txt。注意,请在树莓派完成启动后在修改,不要在烧录完成后在PC修改,因为官方的os第一次启动会自动修改该文件。所以在ssh中直接修改是最便捷和安全的方式。编辑cmdline
sudo nano /boot/firmware/cmdline.txt
在文件末添加
cgroup_memory=1 cgroup_enable=memory
然后我们需要关闭交换空间防止抖动。
sudo sed -ri 's/.swap./#&/' /etc/fstab
更新下软件包重启。
V 你需要给每台设备分配固定的IP地址,配置路由即可,不再赘述。
*以上操作需要对每个设备都进行
1.开始安装 k3s
I 安装Docker
因为ARM 平台的容器有点bug,可能下载的镜像架构(mysql点名批评)与设备不符,为了方便我导入镜像和在k3s体系外可视化部署,我们选择Docker。因此我们需要在每台设备都安装。执行脚本就行。
使用rancher的脚本,可以指定版本。本次采用24.0.4
https://docs.k3s.io/advanced?_highlight=docker#using-docker-as-the-container-runtime
curl https://releases.rancher.com/install-docker/24.0.4.sh | sh
PS:你可能在实践过程中需要重装docker。这是一些卸载技巧。
sudo docker stop $(sudo docker ps -aq) sudo docker rm $(sudo docker ps -aq) sudo docker rmi $(sudo docker images -q) sudo apt remove docker* sudo rm -rf /var/lib/docker sudo apt autoremove
执行完这些就干净了,重新安装就行。
II 安装K3s Master
官方很好,直接一键安装,国内记得加镜像源(INSTALL_K3S_MIRROR=cn)
curl -sfL https://get.k3s.io | sh -s - --docker
正常情况很快。服务启动不了就卸载重装。服务端一键卸载
/usr/local/bin/k3s-uninstall.sh
然后检查一下是不是已经启动
sudo kubectl get pods -A
因为pod会生成和修改,换句话说它自己也有安装过程,遇到error不用担心,等待一会,让它继续部署。如果都挂了才会考虑从docker开始重新安装。
III 安装K3s Agent或者叫slave
因为agent和master需要沟通验证,所以你需要获得一些额外的信息就是master的地址和K3S_TOKEN。在master执行,保存你的token
sudo cat /var/lib/rancher/k3s/server/node-token
你会发现一个4g4dfg4jh4hgkj4hjkh542::server:46ghd4hd4fhh4thsz这样的东西,保存好
在你的agent机安装好docker的前提下,执行该命令以部署agent并于server通讯。
curl -sfL https://get.k3s.io | K3S_URL="https://your_masterIP:6443" K3S_TOKEN="<your_token>" sh -s - --docker
没有报错就是没问题,不需要master机那种检查方式,agent全部安装好后看一看master有没有显示就好。
在master执行以下命令查看所有节点
sudo kubectl get node
agent没有role不必担心,在本项目中正常使用。
2.安装配置 portainer
I 配置docker使portainer可以管理到你想直接管理的节点
先登录你想用portainer直接管理的主机,没错,就算Master也可以
查找docker配置文件位置
sudo systemctl show --property=FragmentPath docker
修改,示例为/lib/systemd/system/docker.service
sudo nano /lib/systemd/system/docker.service
找到
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
在 -H 和 fd之间插入,变成
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H fd:// --containerd=/run/containerd/containerd.sock
保存,再重启变更
sudo systemctl daemon-reload sudo systemctl restart docker
等一会查看master的node和pod没有问题就可以下一步了
II 直接在master安装portainer就行
sudo kubectl apply -n portainer -f https://downloads.portainer.io/ce2-19/portainer.yaml
安装完成按照这个登录https://<your_master_IP>:30779,添加k3s就可以可视化管理了
docker添加可以选择环境,standalone,API ,<your_ip>:2375,就可以直接管理docker容器了
该操作有点危险,因为任何人都可以通过网络API无密码直接管理你的docker!切记不要让陌生人链接你的内网!路由要开防火墙!!!效果如下


3.安装配置 NFS
先介绍下使用NFS目的。主要是方便专门对文件进行定位和访问,自然也方便备份和管理了。
选择一台你想要的设备储存你的数据库和网页,但是注意要给每台设备都安装NFS的基本软件
sudo apt-get install nfs-common nfs-kernel-server -y
然后在那台你想让他作为储存的设备配置文件夹和共享和IP范围
sudo mkdir -p /shared/k3s/web sudo mkdir -p /shared/k3s/db sudo chmod 777 /shared/k3s/web sudo chmod 777 /shared/k3s/db sudo chmod 777 /shared/k3s
然后定义暴漏规则
sudo nano /etc/exports
末尾添加
/shared <your_ip_range_start_like_10.1.3.9>/<last_part_of_range_like_89>(rw,sync,no_root_squash,no_all_squash)
重启服务
sudo systemctl enable rpcbind sudo systemctl enable nfs-server sudo systemctl restart rpcbind sudo systemctl restart nfs-server
检查暴漏
sudo showmount -e
看到这个就说明NFS共享成功了
Export list for YOUR_NFS_HOST: /shared <your_ip_range_start_like_10.1.3.9>/<last_part_of_range_like_89>
接着检查其他主机能不能收到
sudo showmount -e YOUR_NFS_HOST
相似输出就没问题
4.安装配置储存卷并绑定
- 将NFS卷加入K3S(pv)
- 添加声明(pvc)使其可以被使用
在master机执行。
现在将开始大规模编写yaml文件进行配置。
主要使用几个命令,都能看出来啥意思。注意pvc的大小类型得和pv一样
sudo kubectl create -f xx.yaml sudo kubectl apply -f xx.yaml sudo kubectl apply -f ./your_yaml_dir sudo kubectl get pv,pvc sudo kubectl delete pv your_pv_name sudo kubectl delete pvc your_pvc_name
我们知道Mysql需要储存数据库文件到本地,wordpress需要储存网站根目录到本地。这也为什么我们共享了db和web两个目录,是方便处理。
我们先创建项目结构
wp
└──mystorage/
├──nfs-db.yaml
├──nfs-web.yaml
├──claim-db.yaml
└──claim-db.yaml
然后编辑配置
#nfs-db.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pvdb50g
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Recycle
nfs:
path: /shared/k3s/db
server: <NFS_HOST_IP>
storageClassName: manual
#nfs-web.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pvweb50g
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Recycle
nfs:
path: /shared/k3s/web
server: <NFS_HOST_IP>
storageClassName: manual
#claim-db.yaml
#be careful! the "storage" and "storageClassName" and "accessModes" must as the same as in nfs-db.yaml!
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: myclaim-db
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 50Gi
storageClassName: manual
volumeName: pvdb50g
#claim-web.yaml
#be careful! the "storage" and "storageClassName" and "accessModes" must as the same as in nfs-web.yaml!
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: myclaim-web
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 50Gi
storageClassName: manual
volumeName: pvweb50g
都编辑完成后先 sudo kubectl apply -f 那两个nfs-**.yaml, 再应用那两个claim-**.yaml,最后执行 sudo kubectl get pv,pvc 查看是否创建成功,是否绑定成功。如果哪一步失败请检查pv和pvc类型和位置是否有问题,如果未绑定成功未设置成手动会导致后续所有pod都会pending,请知悉。

5.安装Mysql和wordpress
你需要保证你的镜像是否能下载到,镜像标签是否正确。如果你需要适用于树莓派4b的mysql和wordpress的本地镜像,可以联系我!
感觉无需解释太多,具体请看开篇视频,另外注意secret.yaml的作用以及base64编码,最后注意数据安全。这里直接贴了。
wp
├──mystorage/
| ├──nfs-db.yaml
| ├──nfs-web.yaml
| ├──claim-db.yaml
| └──claim-db.yaml
├──mysql/
| ├──configmap.yaml
| ├──secret.yaml
| ├──service.yaml
| └──statefulset.yaml
└──wordpress/
├──deployment.yaml
└──service.yaml
然后分别cd到mysql和wordpress执行 sudo kubectl apply -f ./ 进行部署就ok了
#mysql/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-config
data:
my.cnf: |
[mysqld]
max_connections = 200
#mysql/secret.yaml apiVersion: v1 kind: Secret metadata: name: mysql-secret type: Opaque data: username: <YOUR_USER_NAME_IN_BASE64> password: <YOUR_USER_PASSWORD_IN_BASE64>
#mysql/service
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
ports:
- port: 3306
selector:
app: mysql
#mysql/statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql/mysql-server:latest
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
- name: MYSQL_DATABASE
value: wordpress
- name: MYSQL_USER
valueFrom:
secretKeyRef:
name: mysql-secret
key: username
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-persistent-storage
persistentVolumeClaim:
claimName: myclaim-db
#wordpress/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
spec:
replicas: 2
selector:
matchLabels:
app: wordpress
template:
metadata:
labels:
app: wordpress
spec:
containers:
- name: wordpress
image: wordpress:latest
env:
- name: WORDPRESS_DB_HOST
value: mysql
- name: WORDPRESS_DB_NAME
value: wordpress
- name: WORDPRESS_DB_USER
valueFrom:
secretKeyRef:
name: mysql-secret
key: username
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
ports:
- containerPort: 80
name: wordpress
volumeMounts:
# name must match the volume name below
- name: wordpress-persistent-storage
# mount path within the container
mountPath: /var/www/html
volumes:
- name: wordpress-persistent-storage
persistentVolumeClaim:
claimName: myclaim-web
#wordpress/service.yaml
apiVersion: v1
kind: Service
metadata:
name: wordpress-service
spec:
type: NodePort
selector:
app: wordpress
ports:
- port: 80
targetPort: 80
nodePort: 30080
至此部署已经完成,wordpress已经暴漏在master主机的30080接口(注意接口范围),后续可以添加一些HAproxy 或者nginx进行负载均衡。
——————————————————
一些碎碎念
sudo kubectl describe pod <pod-name>很实用
你可以将wordpress设置为多份而不需要担心数据同步问题
你可以通过nfs直接管理mysql和word press的文件,很方便,设置NFS的ip范围和路由ip池范围有助于阻止不法分子直接访问你的文件。当然,你也可以讲ip范围设置成*,但这是非常危险的。
根据本配置,在k3s内网中mysql的host name就是mysql
没有指出“k3s内网“的情况下,“内网”指你给树莓派物理机所在网段
还有一些错误和不足,大家积极留言指出和补充
另外既然能看到这里,感谢你能完整阅读这篇博文,希望这篇博文能解决你的问题!!
——————————————————
”升华“一下
其实树莓派集群这个想法主要是我无意买了两台树莓派,一个网站另一个vpn和浇花。得益于树莓派这种性能说高不高说低不低的”鸡肋“,我萌生了一个想法:怎样让他们一起工作呢?我就想到了超算这种东西,然后网上冲浪,分布式,云计算,虚拟化,并行计算,docker,k8s,MPI集群这些概念非常吸引人,然后发现树莓派产品价格大跌,回归正常,本着再买一个能让其他两个物( 死 )尽( 得 )其( 其 )用( 所 )的想法便开始了这些架构方面的探索。
虽然大部分是运维相关(有点低端)但是收获也是挺多的。首先是一些概念的。记得以前听大佬说过,现代的计算机解决问题的一大方法就是打包和抽象,一层一层越来越高级。从本博文的实验来看,一个k8s,就涉及到了,扩展,回收,储存(nfs服务器),打包(docker本身),调度编排(pod的调度),网络(k8s虚拟的网络,内部的网络),权限(docker和k8s权限组),各种抽象(容器,进程,主机,储存,网络),局部性原理。这个集群,何尝不是一台完整的计算机?硬盘,处理器,总线,内存一个不缺。当看到管理面板把所有的cpu和内存甚至储存一起算,就感觉很有意思,我还自嘲说头一次打这么富裕的仗。
另外就是动手和选配件硬件计算开销这些方面,也真的很有意思,算是从头到尾自己的project。就是有点浪费树莓派的gpio口,哈哈。
最后我大概会在这上面部署自己的应用?然后再加一套MPI平台?慢慢来吧。
————————————
本文主要借鉴以下文章并进行整合,最后得出数据安全和可定位还有多副本的wordpress站点。
搭建你的 K3s 环境 — 部署 WordPress · 三令五申 (yelsew.net)
WordPress Application Clustering Using Kubernetes with HAProxy and Keepalived | Severalnines
K3s – Lightweight Kubernetes | K3s
kubernetes – Why do pods remain in ‘pending’ status? – Stack Overflow
Fixing – Cannot bind to requested volume: storageClasseName does not match | Jhooq
容器服务 Pod 一直处于 Pending 状态-故障处理-文档中心-腾讯云 (tencent.com)
在Debian上部署NFS服务【详细步骤】_debain 安装配置nfs服务和挂载 es集群备份-CSDN博客
使用portainer远程连接docker_portainer 连接远程-CSDN博客
示例:使用持久卷部署 WordPress 和 MySQL | Kubernetes
容器服务 Pod 一直处于 Pending 状态-故障处理-文档中心-腾讯云 (tencent.com)
win10 挂载NFS(网络文件夹)_windows 挂载 nfs-CSDN博客
技术干货|Docker和 Containerd 的区别,看这一篇就够了 – 知乎 (zhihu.com)
Linux 查看端口占用情况 | 菜鸟教程 (runoob.com)
视频(你可能需要穿过firewall)
Views: 297
