k8s集群部署、以及简易搭建一个wordpress
k8s集群部署、以及简易搭建一个wordpress
此文属于个人瞎折腾笔记,正确性有待商议
本文安装详细参考此篇文章实战Kubernetes之快速部署 K8s 集群 v1.28.0-云社区-华为云
使用Docker、cri-dockerd 和 Kubernetes来搭建,并不是containerd和 Kubernetes
centos
安装前置
由于运行容器是用docker,那就要配置docker的镜像源
[root@k8s-master-01 k8s]# cat /etc/docker/daemon.json
{
"registry-mirrors": [
"https://docker.1ms.run",
"https://dockerhub.azk8s.cn",
"https://reg-mirror.qiniu.com",
"https://registry.docker-cn.com",
"http://hub-mirror.c.163.com",
"https://3laho3y3.mirror.aliyuncs.com",
"http://f1361db2.m.daocloud.io",
"https://mirror.ccs.tencentyun.com"
]
}
# 1、修改主机名(看你想不想,其实改名字出问题问ai也方便些)
hostnamectl set-hostname k8s-master-01
hostnamectl set-hostname k8s-node-01
hostnamectl set-hostname k8s-node-02
# 2、三台机器添加host解析
cat >> /etc/hosts << "EOF"
192.168.236.135 k8s-master-01 m1
192.168.236.134 k8s-node-01 n1
192.168.236.133 k8s-node-02 n2
EOF
# 关闭和禁用防火墙
systemctl stop firewalld
systemctl disable firewalld
# 关闭selinux,selinux 是 Linux 系统下的一个安全服务,需要关闭
setenforce 0 # 临时
最好永久,自行ai
# 关闭 Linux 的 swap 分区(必做环节)
swapoff -a # 临时
最好永久,自行ai
安装 cri-dockerd
cri-dockerd 用于为 Docker 提供一个能够支持 K8s 容器运行时标准的工具,从而能够让 Docker 作为 K8s 容器引擎。通过 wget 下载 cri-dockerd 安装包,然后通过 rpm 命令进行安装。
# 通过 wget 命令获取 cri-dockerd软件
wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.12/cri-dockerd-0.3.12-3.el7.x86_64.rpm
# 通过 rpm 命令执行安装包
rpm -ivh cri-dockerd-0.3.12-3.el7.x86_64.rpm
安装完成后修改配置文件(/usr/lib/systemd/system/cri-docker.service),在 “ExecStart=/usr/bin/cri-dockerd --container-runtime-endpoint fd://” 这一行增加 “–pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.9”。
# 打开 cri-docker.service 配置文件
nano /usr/lib/systemd/system/cri-docker.service
# 修改对应的配置项
ExecStart=/usr/bin/cri-dockerd --container-runtime-endpoint fd:// --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.9
配置文件修改后,重新加载配置并开启 cri-dockerd 服务。
# 加载配置并开启服务
systemctl daemon-reload
systemctl enable cri-docker && systemctl start cri-docker
编辑 “/etc/yum.repos.d/kubernetes.repo” 配置文件,添加阿里云的镜像库。(如果源炸了就ai,我换了太多个了,不清楚是哪个)
cat > /etc/yum.repos.d/kubernetes.repo << EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
安装 kubeadm、kubelet 和 kubectl
所有K8S服务器上都需要安装 kubeadm、kubelet 和 kubectl 这三个工具。
- kubeadm 用来初始化 K8s 集群;
- kubelet 是每个节点的 K8s 管理员;
- kubectl 是 K8s 的命令行交互工具。
这里装1.28,因为阿里云就的仓库最新就是这么新,1.30往后的那些我折腾不出来
sudo yum clean all
sudo yum makecache
sudo yum install -y kubelet-1.28.0 kubeadm-1.28.0 kubectl-1.28.0
# 开机启动 kubelet 服务
systemctl enable kubelet
Master 节点初始化 K8s
所有准备工作都完成了,于可以进行 K8s 的初始化了,只需要在 Master 节点上执行以下初始化命令。
kubeadm init \
--apiserver-advertise-address=192.168.236.135 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.28.0 \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16 \
--cri-socket=unix:///var/run/cri-dockerd.sock \
--ignore-preflight-errors=all
其中,在以上返回结果中有 3 条命令需要立即执行,这是用来设置 kubectl 工具的管理员权限,执行之后就可以在 Master 节点上通过终端窗口使用 kubectl 命令。
# 在 Master 节点上执行以下命令
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
worker节点加入k8s集群
master节点拿信息
[root@k8s-master-01 k8s]# kubeadm token create --print-join-command
kubeadm join 192.168.236.135:6443 --token ubi2qj.c55fm182snz74t73 --discovery-token-ca-cert-hash sha256:e94b1bb74a6c98031e764f13ae5f54b260d1141698ee2e2f691bd104d8d13309
K8s 初始化之后,就可以在其他 2 个工作节点上执行 “kubeadm join” 命令,因为我们使用了 cri-dockerd ,需要在命令加上 “–cri-socket=unix:///var/run/cri-dockerd.sock” 参数。
# 在两个工作节点上执行
kubeadm join 192.168.9.86:6443 --token xxxxxx \
--discovery-token-ca-cert-hash sha256:xxxxxx \
--cri-socket=unix:///var/run/cri-dockerd.sock
即是
kubeadm join 192.168.236.135:6443 \
--token ubi2qj.c55fm182snz74t73 \
--discovery-token-ca-cert-hash sha256:e94b1bb74a6c98031e764f13ae5f54b260d1141698ee2e2f691bd104d8d13309 \
--cri-socket unix:///var/run/cri-dockerd.sock
安装 K8s 网络插件
K8s 网络插件,也称为容器网络接口(CNI)插件,是实现 K8s 集群中容器间通信和网络连接的关键组件,否则 Pod 之间无法通信。Kubernetes 支持多种网络方案,这里我们使用 calico。
Calico 是通过执行一个 YAML 文件部署到 K8s 集群里的,所以我们首先需要通过 “wget” 命令下载这个 YAML 文件。
# 下载 Calico 插件部署文件
wget https://docs.projectcalico.org/manifests/calico.yaml
通过 vi 编辑器修改 “calico.yaml” 文件中的 “CALICO_IPV4POOL_CIDR” 参数,需要与前面 “kubeadm init” 命令中的 “–pod-network-cidr” 参数一样(10.244.0.0/16)。如果文件里的 “CALICO_IPV4POOL_CIDR” 参数前面有 “#”,表示被注释了,需要删除 “#”。
修改位置如下所示。(在 vi 中可以通过输入 “:set nu” 来查看行号,同时可以输入 “/CALICO_IPV4POOL_CIDR” 来快速定位到参数位置)
# 修改文件时注意格式对齐
4598 # The default IPv4 pool to create on startup if none exists. Pod IPs will be
4599 # chosen from this range. Changing this value after installation will have
4600 # no effect. This should fall within `--cluster-cidr`.
4601 - name: CALICO_IPV4POOL_CIDR
4602 value: "10.244.0.0/16"
4603 # Disable file logging so `kubectl logs` works.
4604 - name: CALICO_DISABLE_FILE_LOGGING
4605 value: "true"
最后,使用 “kubectl apply” 命令将 Calico 插件部署到集群里,部署 YAML 文件命令如下:
kubectl apply -f calico.yaml
Calico 部署会比较慢,大概等个几分钟,等待 Calico 部署完成后,再次通过命令 “kubectl get node” 查看节点状态,就可以看到所有节点已经准备就绪,此时集群正式搭建成功。
[root@k8s-master ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane 12h v1.28.0
k8s-worker1 Ready <none> 12h v1.28.0
k8s-worker2 Ready <none> 10h v1.28.0
搭建一个wordpress
首先需要你的本地有/home/eth/k8s/wp/data/wordpress、/home/eth/k8s/wp/data/wordpress这两个文件给k8s做pv使用,由于我是用我自己的目录,所以看起来就很丑了,可自行在yaml中替换
---
# 1. 创建命名空间
apiVersion: v1
kind: Namespace
metadata:
name: wordpress-namespace
---
# 2. 创建 PersistentVolume: MySQL
apiVersion: v1
kind: PersistentVolume
metadata:
name: mysql-pv
spec:
capacity:
storage: 20Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: "" # 显式设置为空,避免与默认 StorageClass 冲突
hostPath:
path: /home/eth/k8s/wp/data/mysql
type: DirectoryOrCreate
---
# 3. 创建 PersistentVolume: WordPress
apiVersion: v1
kind: PersistentVolume
metadata:
name: wp-pv
spec:
capacity:
storage: 20Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: "" # 显式设置为空
hostPath:
path: /home/eth/k8s/wp/data/wordpress
type: DirectoryOrCreate
---
# 4. 创建 PersistentVolumeClaim: MySQL(关键:禁用动态供应)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pv-claim
namespace: wordpress-namespace
spec:
storageClassName: "" # ⚠️ 关键:必须设置为空,否则会被 local-path 劫持
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
---
# 5. 创建 PersistentVolumeClaim: WordPress(同上)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: wp-pv-claim
namespace: wordpress-namespace
spec:
storageClassName: "" # ⚠️ 关键:禁用动态供应
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
---
# 6. 部署 MySQL
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress-mysql
namespace: wordpress-namespace
labels:
app: wordpress
tier: mysql
spec:
replicas: 1
selector:
matchLabels:
app: wordpress
tier: mysql
strategy:
type: Recreate # 确保 MySQL 停止后再启动 WordPress
template:
metadata:
labels:
app: wordpress
tier: mysql
spec:
containers:
- image: mysql:5.7
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "MySecureRootPass123!" # 🔐 请根据需要修改
- name: MYSQL_DATABASE
value: wordpress
- name: MYSQL_USER
value: wordpress
- name: MYSQL_PASSWORD
value: "MySecureDbPass123!" # 🔐 请修改
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-storage
persistentVolumeClaim:
claimName: mysql-pv-claim
---
# 7. MySQL 服务(Headless)
apiVersion: v1
kind: Service
metadata:
name: wordpress-mysql
namespace: wordpress-namespace
labels:
app: wordpress
tier: mysql
spec:
ports:
- port: 3306
targetPort: 3306
selector:
app: wordpress
tier: mysql
clusterIP: None # Headless Service,适合有状态应用
---
# 8. 部署 WordPress
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
namespace: wordpress-namespace
labels:
app: wordpress
tier: frontend
spec:
replicas: 1
selector:
matchLabels:
app: wordpress
tier: frontend
strategy:
type: Recreate
template:
metadata:
labels:
app: wordpress
tier: frontend
spec:
containers:
- image: wordpress:6.0-apache
name: wordpress
env:
- name: WORDPRESS_DB_HOST
value: wordpress-mysql
- name: WORDPRESS_DB_USER
value: wordpress
- name: WORDPRESS_DB_PASSWORD
value: "MySecureDbPass123!" # 必须与 MYSQL_PASSWORD 一致
- name: WORDPRESS_DB_NAME
value: wordpress
ports:
- containerPort: 80
name: http
volumeMounts:
- name: wordpress-storage
mountPath: /var/www/html
volumes:
- name: wordpress-storage
persistentVolumeClaim:
claimName: wp-pv-claim
---
# 9. WordPress 服务(NodePort,适合本地访问)
apiVersion: v1
kind: Service
metadata:
name: wordpress-service
namespace: wordpress-namespace
labels:
app: wordpress
tier: frontend
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 30080 # 可通过 http://<任意节点IP>:30080 访问
protocol: TCP
selector:
app: wordpress
tier: frontend
然后运行
kubectl apply -f wordpress-local-final.yaml
查看状态
# 查看命名空间
kubectl get ns | grep wordpress
# 查看 PVC(应为 Bound)
kubectl get pvc -n wordpress-namespace
# 查看 PV(应为 Bound)
kubectl get pv
# 查看 Pod(稍等 1-2 分钟,应变为 Running)
kubectl get pods -n wordpress-namespace -w
访问wp
http://<任意节点IP>:30080
多节点副本的一些个人踩坑
后面的不用跟着做,都是错
wp副本为2
由于我们只设置了wp、mysql的副本数量都为1 即replicas: 1,所以其实现在是单节点无保障的运行
也就是说node2和master节点损坏,都会导致wp服务出问题
[root@k8s-master-01 k8s]# kubectl get pods -n wordpress-namespace -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
wordpress-f99656877-grphx 1/1 Running 0 19m 10.244.44.193 k8s-node-02 <none> <none>
wordpress-mysql-5b4ddb96ff-j2sdv 1/1 Running 0 19m 10.244.44.194 k8s-node-02 <none> <none>
如果给wp副本添加数量为2,就可以有两个
[root@k8s-master-01 wp]# kubectl get pods -n wordpress-namespace -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
wordpress-f99656877-crblb 1/1 Running 0 28s 10.244.154.196 k8s-node-01 <none> <none>
wordpress-f99656877-grphx 1/1 Running 0 27m 10.244.44.193 k8s-node-02 <none> <none>
wordpress-mysql-5b4ddb96ff-j2sdv 1/1 Running 0 27m 10.244.44.194 k8s-node-02 <none> <none>
现在的情况中
- 在
k8s-node-01上运行的 Pod → 使用的是 node01 的/home/eth/k8s/wp/data/wordpress - 在
k8s-node-02上运行的 Pod → 使用的是 node02 的/home/eth/k8s/wp/data/wordpress - 两个目录完全独立、不共享
但是这样子做会有问题,问题不在共用一个mysql,主要是因为wp是一个有状态应用,比如他的头像和主题,都会上传到对应node的wp目录里
那么会发生什么?
假设用户上传一张头像图片:
- 请求被路由到
k8s-node-02上的 WordPress → 图片保存在 node02 的磁盘上 - 下次访问时,请求被路由到
k8s-node-01上的 WordPress → 它去 node01 的磁盘找图片 → 找不到!→ 404
解决方法
方案一:搭建一个 NFS 服务器,大火一起用
方案二:OSS
这种情况下无状态应用更适合来做副本
同时为什么mysql不能给副本数量为2?
因为 数据库(MySQL)是有状态的、写唯一的系统,不像 WordPress 前端可以无状态多副本。
如果你强行改成 replicas: 2 并使用当前的 hostPath + PVC 存储方案,会发生:
| 问题 | 后果 |
|---|---|
| ❌ 两个 MySQL 实例尝试写同一个数据目录 | 数据损坏、崩溃、启动失败 |
| ❌ 每个副本都独立启动自己的 MySQL 服务 | 主键冲突、数据不一致 |
| ❌ 没有主从复制机制 | 写操作无法同步 |
🚫 结果:数据库损坏,WordPress 无法连接,服务彻底瘫痪。
数据库副本方案有三个
方案一:使用 StatefulSet + 主从复制(配置很复杂)
方案二:使用云数据库(厂商就会帮你备份了,所以单点也无所谓)
方案三:使用 Kubernetes 原生数据库 Operator
杂类笔记
apply -f的时候kubectl怎么判断是新、旧配置
当你使用 kubectl apply 时,Kubernetes 会根据以下几点来决定是创建新资源还是更新现有资源:
- 资源类型:如 Deployment、Service 等。
- 资源名称:在 YAML 文件中定义的
metadata.name。 - 命名空间:如果 YAML 文件中指定了
metadata.namespace,则会在指定的命名空间内进行查找;如果没有指定,默认为default命名空间。
哪一步导致k8s通过cri-dockerd使用docker来拉取镜像
Master 节点和worker节点都加上的这两句导致的
--cri-socket=unix:///var/run/cri-dockerd.sock
命令速记
kubectl get ns
kubectl get pods -n wordpress-namespace -o wide
watch kubectl get pods -n wordpress-namespace
kubectl describe pods <pod-name> -n wordpress-namespace
#拿master节点信息
kubeadm token create --print-join-command

浙公网安备 33010602011771号