K8s 中部署WordPress 博客

文章目录

  • [K8s 中部署 LNMP 架构 WordPress 博客(命令与配置逐条详解)](#K8s 中部署 LNMP 架构 WordPress 博客(命令与配置逐条详解))
    • 项目需求
    • 博客站点架构
    • [步骤 1:创建命名空间](#步骤 1:创建命名空间)
    • [步骤 2:部署 NFS 服务器](#步骤 2:部署 NFS 服务器)
      • [2.1 部署 NFS 服务(NFS 服务器节点操作)](#2.1 部署 NFS 服务(NFS 服务器节点操作))
      • [2.2 部署 NFS 客户端(所有 K8s 节点操作)](#2.2 部署 NFS 客户端(所有 K8s 节点操作))
    • [步骤 3:部署 NFS Provisioner](#步骤 3:部署 NFS Provisioner)
      • [3.1 创建 RBAC 权限](#3.1 创建 RBAC 权限)
      • [3.2 部署 NFS Provisioner 应用](#3.2 部署 NFS Provisioner 应用)
      • [3.3 创建 NFS StorageClass](#3.3 创建 NFS StorageClass)
    • [步骤 4:部署 MySQL](#步骤 4:部署 MySQL)
      • [4.1 创建 Secret](#4.1 创建 Secret)
      • [4.2 创建 Service](#4.2 创建 Service)
      • [4.3 部署 MySQL(StatefulSet)](#4.3 部署 MySQL(StatefulSet))
    • [步骤 5:部署 PHP](#步骤 5:部署 PHP)
      • [5.1 创建 PVC](#5.1 创建 PVC)
      • [5.2 创建 Service(PHP)](#5.2 创建 Service(PHP))
      • [5.3 部署 PHP(Deployment)](#5.3 部署 PHP(Deployment))
    • [步骤 6:部署 Nginx](#步骤 6:部署 Nginx)
      • [6.1 创建 Nginx 配置(ConfigMap)](#6.1 创建 Nginx 配置(ConfigMap))
      • [6.2 创建 Nginx 证书(openssl 自签名证书)](#6.2 创建 Nginx 证书(openssl 自签名证书))
      • [6.3 创建 Service(Nginx)](#6.3 创建 Service(Nginx))
      • [6.4 部署 Nginx(Deployment)](#6.4 部署 Nginx(Deployment))
      • [6.5 部署 WordPress 代码](#6.5 部署 WordPress 代码)
    • [步骤 7:部署 LoadBalancer(MetalLB)](#步骤 7:部署 LoadBalancer(MetalLB))
    • [步骤 8:部署 Ingress](#步骤 8:部署 Ingress)
    • [步骤 9:初始化站点](#步骤 9:初始化站点)
    • 部署小结

K8s 中部署 LNMP 架构 WordPress 博客(命令与配置逐条详解)

项目需求

在 K8s 的 wordpress 命名空间中部署 LNMP 架构 WordPress 博客,具体需求如下:

  1. 部署 NFS 服务器,提供共享目录 /wordpress
  2. 部署 NFS 动态卷制备(NFS Provisioner),存储类型(StorageClass)为 wordpress
  3. 部署 MySQL 应用:
    • 使用 StatefulSet 部署,基于 mysql:5.7 镜像,副本数 1 个
    • 存储由 NFS 动态卷制备提供
    • 使用 Secret 存储 MySQL 用户 root 密码、WordPress 应用用户名 wordpress、密码 liujn@123、数据库 wordpress
    • 额外配置一个 Service,用于暴露 MySQL 应用
  4. 部署 PHP 应用:
    • 使用 Deployment 部署,基于 php:7.2-fpm 镜像,副本数 2 个
    • 使用 Service(ClusterIP 类型)暴露
  5. 部署 WordPress 应用:
    • 使用 Deployment 部署,基于 nginx:1.24 镜像,副本数 2 个
    • 存储由 NFS 动态卷制备提供
    • 使用 Ingress 暴露,域名 blog.liujn.cloud
    • 使用 ConfigMap 存储 Nginx 配置文件,使用 Secret 存储 Nginx 服务 TLS 自签名证书和私钥
  6. 部署 Metrics Server 监控 WordPress 相关资源
  7. 针对 PHP 和 WordPress 应用,配置 HPA 规则,最小 2 个 Pod,最大 5 个 Pod

博客站点架构

#mermaid-svg-gfqkWwxGFbCiahEZ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-gfqkWwxGFbCiahEZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gfqkWwxGFbCiahEZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gfqkWwxGFbCiahEZ .error-icon{fill:#552222;}#mermaid-svg-gfqkWwxGFbCiahEZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gfqkWwxGFbCiahEZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gfqkWwxGFbCiahEZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gfqkWwxGFbCiahEZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gfqkWwxGFbCiahEZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gfqkWwxGFbCiahEZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gfqkWwxGFbCiahEZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gfqkWwxGFbCiahEZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gfqkWwxGFbCiahEZ .marker.cross{stroke:#333333;}#mermaid-svg-gfqkWwxGFbCiahEZ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gfqkWwxGFbCiahEZ p{margin:0;}#mermaid-svg-gfqkWwxGFbCiahEZ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-gfqkWwxGFbCiahEZ .cluster-label text{fill:#333;}#mermaid-svg-gfqkWwxGFbCiahEZ .cluster-label span{color:#333;}#mermaid-svg-gfqkWwxGFbCiahEZ .cluster-label span p{background-color:transparent;}#mermaid-svg-gfqkWwxGFbCiahEZ .label text,#mermaid-svg-gfqkWwxGFbCiahEZ span{fill:#333;color:#333;}#mermaid-svg-gfqkWwxGFbCiahEZ .node rect,#mermaid-svg-gfqkWwxGFbCiahEZ .node circle,#mermaid-svg-gfqkWwxGFbCiahEZ .node ellipse,#mermaid-svg-gfqkWwxGFbCiahEZ .node polygon,#mermaid-svg-gfqkWwxGFbCiahEZ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-gfqkWwxGFbCiahEZ .rough-node .label text,#mermaid-svg-gfqkWwxGFbCiahEZ .node .label text,#mermaid-svg-gfqkWwxGFbCiahEZ .image-shape .label,#mermaid-svg-gfqkWwxGFbCiahEZ .icon-shape .label{text-anchor:middle;}#mermaid-svg-gfqkWwxGFbCiahEZ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-gfqkWwxGFbCiahEZ .rough-node .label,#mermaid-svg-gfqkWwxGFbCiahEZ .node .label,#mermaid-svg-gfqkWwxGFbCiahEZ .image-shape .label,#mermaid-svg-gfqkWwxGFbCiahEZ .icon-shape .label{text-align:center;}#mermaid-svg-gfqkWwxGFbCiahEZ .node.clickable{cursor:pointer;}#mermaid-svg-gfqkWwxGFbCiahEZ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-gfqkWwxGFbCiahEZ .arrowheadPath{fill:#333333;}#mermaid-svg-gfqkWwxGFbCiahEZ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-gfqkWwxGFbCiahEZ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-gfqkWwxGFbCiahEZ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gfqkWwxGFbCiahEZ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-gfqkWwxGFbCiahEZ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gfqkWwxGFbCiahEZ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-gfqkWwxGFbCiahEZ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-gfqkWwxGFbCiahEZ .cluster text{fill:#333;}#mermaid-svg-gfqkWwxGFbCiahEZ .cluster span{color:#333;}#mermaid-svg-gfqkWwxGFbCiahEZ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-gfqkWwxGFbCiahEZ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-gfqkWwxGFbCiahEZ rect.text{fill:none;stroke-width:0;}#mermaid-svg-gfqkWwxGFbCiahEZ .icon-shape,#mermaid-svg-gfqkWwxGFbCiahEZ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gfqkWwxGFbCiahEZ .icon-shape p,#mermaid-svg-gfqkWwxGFbCiahEZ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-gfqkWwxGFbCiahEZ .icon-shape .label rect,#mermaid-svg-gfqkWwxGFbCiahEZ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gfqkWwxGFbCiahEZ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-gfqkWwxGFbCiahEZ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-gfqkWwxGFbCiahEZ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} NFS服务器10.1.8.30 /wordpress
动态卷制备
PVC-mysql
PVC-wordpress
Secret: mysql存储专用账号密码
Statefulset: mysql副本数:1
Deployment: php副本数:2
Deployment: nginx副本数:2
Service: mysql 类型:ClusterIP
Service: php 类型:ClusterIP
Service: nginx 类型:ClusterIP
Ingress: blog.liujn.cloud
ConfigMap: nginx-config
Secret: nginx-tls

架构解读 :NFS 服务器提供共享目录 → NFS Provisioner 实现动态卷制备(PV)→ 检测到 PVC 请求后自动创建 PV 并绑定 → MySQL(StatefulSet)、PHP(Deployment)、Nginx(Deployment)分别挂载存储;外部请求经 Ingress(blog.liujn.cloud)→ Nginx Service → Nginx Pod,并由 Nginx 反向代理 PHP 解析 PHP 文件,PHP 再连接 MySQL 读写数据,形成完整 LNMP 请求链路。


步骤 1:创建命名空间

原始命令:

bash 复制代码
root@master30:~/wordpress# kubectl create ns wordpress
root@master30:~/wordpress# kubectl config set-context --current --namespace wordpress

命令详解:

  1. kubectl create ns wordpress

    • 用途 :创建一个名为 wordpress 的 Kubernetes 命名空间(Namespace),用于隔离本次部署的所有资源。
    • 参数含义nsnamespace 的缩写;wordpress 是要创建的命名空间名称。
    • 预期作用:创建成功后,后续的 MySQL、PHP、Nginx、PVC、Ingress 等对象都会集中放到这个命名空间里,互不干扰、便于统一管理。
  2. kubectl config set-context --current --namespace wordpress

    • 用途 :把当前使用的 K8s 上下文(context)默认命名空间修改为 wordpress,等价于给所有后续 kubectl 命令"烙上"默认命名空间。
    • 参数含义--current 表示只修改当前正在使用的上下文;--namespace wordpress 指定新的默认命名空间。
    • 预期作用 :以后执行 kubectl get pods 等命令时,无需再手动加 -n wordpress,默认就会查这个命名空间内的资源,大幅减少命令输入量。

步骤 2:部署 NFS 服务器

2.1 部署 NFS 服务(NFS 服务器节点操作)

原始命令:

bash 复制代码
## 安装 NFS 服务
root@master30:~/wordpress# apt install -y nfs-kernel-server

## 创建共享目录
root@master30:~/wordpress# mkdir -p -m 777 /wordpress

## 配置 NFS 共享(地址已改为10.1.8.30,允许所有节点访问)
root@master30:~/wordpress# echo "/wordpress *(rw,sync,no_root_squash,no_all_squash)" >> /etc/exports

## 启动服务
root@master30:~/wordpress# systemctl restart nfs-server

## 验证共享
root@master30:~/wordpress# showmount -e localhost
Export list for localhost:
/wordpress  *

命令详解:

  1. apt install -y nfs-kernel-server

    • 用途:在 NFS 服务器节点上安装内核级 NFS 服务端软件。
    • 参数含义-y 表示自动应答"yes",跳过安装过程中的确认提示,实现无人值守安装。
    • 预期作用:安装完成后系统就具备了对外提供 NFS 网络共享的能力。
  2. mkdir -p -m 777 /wordpress

    • 用途 :创建 /wordpress 目录,作为 NFS 对外共享的根目录。
    • 参数含义-p 表示递归创建父目录(父目录不存在时自动创建,已存在也不报错);-m 777 设置目录权限为 rwxrwxrwx,即所有用户均可读、写、执行。
    • 预期作用:后续 MySQL 数据、WordPress 代码都会落在这个目录里,宽权限保证 K8s 中不同用户身份的 Pod 都能读写。
  3. echo "/wordpress *(rw,sync,no_root_squash,no_all_squash)" >> /etc/exports

    • 用途 :把共享目录的导出规则追加写入 NFS 配置文件 /etc/exports
    • 参数含义/wordpress 是要共享的目录;* 表示允许所有主机访问;rw 表示读写权限;sync 表示同步写入(数据先落盘再返回,保证一致性);no_root_squash 表示客户端的 root 用户保持 root 权限(不建议生产使用,此处为实验简化);no_all_squash 表示不把所有用户都映射为匿名用户(nobody);>> 是追加重定向,不会覆盖文件原有内容。
    • 预期作用 :该规则写入后,NFS 服务重启即生效,集群任意节点都能把 /wordpress 挂载为自己的存储目录。
  4. systemctl restart nfs-server

    • 用途 :重启 NFS 服务,使 /etc/exports 中新增的导出规则生效。
    • 参数含义systemctl 用于管理系统服务,restart 表示先停止再启动 nfs-server 服务。
    • 预期作用 :重启后 NFS 服务开始对外公布 /wordpress 共享。
  5. showmount -e localhost

    • 用途:在本机查看 NFS 服务端当前导出的共享列表,验证共享是否配置成功。
    • 参数含义showmount 是查询 NFS 导出信息的工具;-e 表示显示导出列表(exports);localhost 指定要查询的目标主机(此处为 NFS 服务器本机)。
    • 预期作用 :输出显示 /wordpress *,表示共享目录已正确导出并允许所有主机访问。

2.2 部署 NFS 客户端(所有 K8s 节点操作)

原始命令:

bash 复制代码
root@worker31-32:~# apt install -y nfs-common

## 验证共享
root@worker31-32:~# showmount -e master30
Export list for master30:
/wordpress  *

命令详解:

  1. apt install -y nfs-common

    • 用途:在所有 K8s 节点(Worker 节点)上安装 NFS 客户端工具集。
    • 参数含义-y 自动确认安装;nfs-common 是 NFS 客户端软件,包含挂载、查询 NFS 共享所需的基础工具。
    • 预期作用:安装后各节点即可挂载 NFS 服务器导出的目录,这是后续 PV 挂载到 Pod 的前提。
  2. showmount -e master30

    • 用途 :从客户端节点查询 NFS 服务器(主机名 master30)上导出的共享列表。
    • 参数含义-e 显示导出列表;master30 是 NFS 服务器的 IP/hostname。
    • 预期作用 :输出 /wordpress *,确认客户端能够正常访问 NFS 服务器,网络与 NFS 服务均已就绪。

步骤 3:部署 NFS Provisioner

NFS 原生没有内置的动态存储制备器(Provisioner),因此这里自定义一个外部分配器(External Provisioner)来监听 PVC 请求并自动创建 NFS 上的目录作为 PV。

原始命令:

bash 复制代码
# 部署 NFS provisioner到命名空间:kube-storage
root@master30:~/wordpress# kubectl create ns kube-storage

命令详解:

  1. kubectl create ns kube-storage
    • 用途 :创建一个名为 kube-storage 的命名空间,专门用来存放 NFS Provisioner 及其相关资源,与业务命名空间 wordpress 隔离。
    • 参数含义nsnamespace 缩写;kube-storage 为命名空间名称。
    • 预期作用:Provisional 相关的 ServiceAccount、RBAC、Deployment、StorageClass 都集中在此命名空间内管理。

3.1 创建 RBAC 权限

原始清单(nfs-rbac.yaml):

yaml 复制代码
root@master30:~/wordpress# cat > nfs-rbac.yaml <<'EOF'
apiVersion: v1  # API 版本:ServiceAccount 属于核心 v1 组
kind: ServiceAccount  # 对象类型:ServiceAccount,为 Pod 提供集群内身份
metadata:
  name: nfs-client-provisioner  # 服务账号名称
  namespace: kube-storage  # 归属命名空间
---
apiVersion: rbac.authorization.k8s.io/v1  # RBAC 授权 API 版本
kind: ClusterRole  # 对象类型:集群级角色,定义一整套权限规则
metadata:
  name: nfs-client-provisioner-runner  # 角色名
rules:
  - apiGroups: [""]  # 规则针对的 API 组:[""] 表示核心组(v1)
    resources: ["persistentvolumes"]  # 授权操作的资源类型:PV(持久卷)
    verbs: ["get", "list", "watch", "create", "delete"]  # 允许的动作:制备器需要创建/删除 PV
  - apiGroups: [""]  # 核心组
    resources: ["persistentvolumeclaims"]  # 资源类型:PVC
    verbs: ["get", "list", "watch", "update"]  # 需监听 PVC 并更新其状态
  - apiGroups: ["storage.k8s.io"]  # 存储 API 组
    resources: ["storageclasses"]  # 资源类型:StorageClass
    verbs: ["get", "list", "watch"]  # 需读取 SC 配置信息
  - apiGroups: [""]  # 核心组
    resources: ["events"]  # 资源类型:集群事件
    verbs: ["create", "update", "patch"]  # 用于将事件写入集群
  - apiGroups: [""]  # 核心组
    resources: ["endpoints"]  # 资源类型:端点
    verbs: ["get", "list", "watch", "create", "update", "patch"]  # 维护 PV 关联的端点信息
---
apiVersion: rbac.authorization.k8s.io/v1  # RBAC 授权 API 版本
kind: ClusterRoleBinding  # 对象类型:集群级角色绑定,把角色授予指定对象(跨命名空间生效)
metadata:
  name: run-nfs-client-provisioner  # 绑定名称
subjects:
  - kind: ServiceAccount  # 被授者身份类型
    name: nfs-client-provisioner  # 被授者名称,即上面创建的 ServiceAccount
    namespace: kube-storage  # 被授者所在命名空间
roleRef:
  kind: ClusterRole  # 绑定的角色类型
  name: nfs-client-provisioner-runner  # 绑定的角色名,引用上面定义的 ClusterRole
  apiGroup: rbac.authorization.k8s.io  # 角色所属 API 组
EOF

root@master30:~/wordpress# kubectl apply -f nfs-rbac.yaml

命令详解:

  1. cat > nfs-rbac.yaml <<'EOF' ... EOF

    • 用途 :在终端中把 EOF 之间的多行内容写入文件 nfs-rbac.yaml> 是覆盖写)。
    • 参数含义<<'EOF' 是 here-document 语法,'EOF' 加引号表示内容里不做变量展开(保证 $ 等特殊字符原样写入);cat 接力把标准输入写入文件。
    • 预期作用:生成包含 ServiceAccount、ClusterRole、ClusterRoleBinding 三个对象的 YAML 文件。
  2. kubectl apply -f nfs-rbac.yaml

    • 用途:声明式创建/更新该文件定义的所有资源对象。
    • 参数含义apply 会根据清单文件把资源"应用"到集群,重复执行会比对差异做增量更新;-f 指定清单文件路径。
    • 预期作用:创建 NFS Provisioner 的运行身份与权限。

3.2 部署 NFS Provisioner 应用

原始清单(nfs-provisioner.yaml):

yaml 复制代码
root@master30:~/wordpress# cat > nfs-provisioner.yaml <<'EOF'
apiVersion: apps/v1  # API 版本:Deployment 属于 apps 组的 v1(稳定版)
kind: Deployment  # 对象类型:Deployment,无状态工作负载控制器,负责维持 Pod 副本数
metadata:
  name: nfs-client-provisioner  # Deployment 名称
  namespace: kube-storage  # 归属命名空间
spec:  # 期望状态定义
  replicas: 1  # 期望副本数 1 个(Provisioner 只需一个实例)
  strategy:  # 更新策略
    type: Recreate  # 先删旧再建新,适合有状态、不可并发的组件,避免新旧实例同时操作 NFS
  selector:  # 选择器:Deployment 通过它管理自己的 Pod
    matchLabels:
      app: nfs-client-provisioner  # 匹配 Pod 标签
  template:  # Pod 模板
    metadata:
      labels:
        app: nfs-client-provisioner  # Pod 标签,需与 selector 一致
    spec:
      serviceAccountName: nfs-client-provisioner  # 以该 ServiceAccount 身份运行(即 3.1 授权的账号)
      volumes:  # 声明卷
      - name: nfs-client-root  # 卷名:nfs-client-root
        nfs:  # 卷类型为 NFS
          server: 10.1.8.30  # 同上 NFS 服务器 IP
          path: /wordpress  # 核心:共享路径同步改为 /wordpress
      containers:  # 容器定义
      - name: nfs-client-provisioner  # 容器名
        image: registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2  # 官方子目录外置制备器镜像
        volumeMounts:  # 卷挂载
        - name: nfs-client-root  # 挂载上面声明的 NFS 卷
          mountPath: /persistentvolumes  # 挂载到容器内路径,制备器在此路径下创建子目录充当 PV
        env:  # 环境变量
        - name: PROVISIONER_NAME  # 制备器唯一标识名
          value: fuseim.pri/ifs  # 必须和 StorageClass 中的 provisioner 完全一致
        - name: NFS_SERVER  # 传给制备器的 NFS 服务器地址
          value: 10.1.8.30  # 替换为你的 NFS 服务器 IP
        - name: NFS_PATH  # 传给制备器的共享根路径
          value: /wordpress  # 核心:共享路径改为 /wordpress
EOF

#  部署 NFS Provisioner 应用
root@master30:~/wordpress# kubectl apply -f nfs-provisioner.yaml

# 查看 NFS Provisioner 应用
root@master30:~/wordpress# kubectl get deployments.apps -n kube-storage 
NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
nfs-client-provisioner   1/1     1            1           1m

命令详解:

  1. cat > nfs-provisioner.yaml <<'EOF' ... EOF ------ 同上,用 here-document 生成 Deployment 清单文件。
  2. kubectl apply -f nfs-provisioner.yaml ------ 声明式创建 NFS Provisioner 的 Deployment。
  3. kubectl get deployments.apps -n kube-storage
    • 用途 :查看 kube-storage 命名空间下的 Deployment 状态。
    • 参数含义deployments.apps 指定资源类型;-n 指定命名空间。
    • 预期作用 :输出 nfs-client-provisioner 1/1 ... 表示副本数要求 1 个、就绪 1 个,部署成功。

3.3 创建 NFS StorageClass

原始清单(wordpress-StorageClass.yaml):

yaml 复制代码
root@master30:~/wordpress# cat > wordpress-StorageClass.yaml <<'EOF'
apiVersion: storage.k8s.io/v1  # API 版本:StorageClass 属于 storage.k8s.io 组的 v1
kind: StorageClass  # 对象类型:定义一类相同特性的动态存储
metadata:
  name: wordpress  # SC 名称,PVC 通过 storageClassName 引用它
  namespace: kube-storage  # 归属命名空间(SC 实际是集群级资源,此处标归属便于管理)
provisioner: fuseim.pri/ifs  # 指定由哪个动态制备器创建 PV,必须和 Provisioner 名称(PROVISIONER_NAME)一致
parameters:
  onDelete: retain  # 制备器级参数:删除 PVC 时保留 NFS 上的数据(不删除底层目录)
  archiveOnDelete: "false"  # 制备器级参数:删除 PVC 时不归档(归档会重命名为 archived- 前缀,这里关闭)
# 按需设置回收策略
#reclaimPolicy: Retain  # 如需保留数据可改用 Retain,此处默认注释掉
reclaimPolicy: Delete  # 回收策略:删除 PVC 后同时删除对应的 PV
allowVolumeExpansion: true  # 允许后续在线扩容 PV 容量
volumeBindingMode: Immediate  # 卷绑定模式:PVC 创建后立即绑定 PV(延迟绑定对应 WaitForFirstConsumer)
EOF

# 创建 StorageClass
root@master30:~/wordpress# kubectl apply -f wordpress-StorageClass.yaml
root@master30:~/wordpress# kubectl get sc
NAME        PROVISIONER      RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
wordpress   fuseim.pri/ifs   Delete          Immediate           true                   11s

命令详解:

  1. cat > wordpress-StorageClass.yaml <<'EOF' ... EOF ------ here-document 生成 StorageClass 清单。
  2. kubectl apply -f wordpress-StorageClass.yaml ------ 创建名为 wordpress 的 StorageClass。
  3. kubectl get sc
    • 用途 :查看集群中所有 StorageClass(scstorageclass 缩写)。
    • 参数含义:无附加参数时展示全部 SC 的摘要表。
    • 预期作用 :输出显示 wordpress 的 PROVISIONER 为 fuseim.pri/ifs、回收策略 Delete、绑定模式 Immediate、支持扩容 true,配置已生效。

步骤 4:部署 MySQL

4.1 创建 Secret

用 Kubernetes Secret 存储 MySQL root 密码、WordPress 专用用户及密码、数据库名,替代明文配置,提升安全性。

这里定义:

  • MySQL root 密码:Root@123(可按需修改)
  • WordPress 专用数据库用户:wordpress
  • WordPress 专用用户密码:Wordpress@123(可按需修改)
  • WordPress 专用数据库:wordpress

原始命令:

bash 复制代码
# 创建 Secret 存储数据库敏感信息(base64编码,避免明文)
root@master30:~/wordpress# kubectl create secret generic mysql \
  --namespace wordpress \
  --from-literal=mysql-root-password=Root@123 \
  --from-literal=wordpress-db-user=wordpress \
  --from-literal=wordpress-db-password=Wordpress@123

# 验证 Secret
root@master30:~/wordpress# kubectl get secrets 
NAME    TYPE     DATA   AGE
mysql   Opaque   3      10s

命令详解:

  1. kubectl create secret generic mysql

    • 用途 :创建一个名为 mysql 的通用类型(generic/Opaque)Secret,存放键值对形式的敏感数据。
    • 参数含义secret 资源类型;generic 表示通用 Secret(非 TLS、非 Registry 凭证);mysql 为 Secret 名称。
    • --namespace wordpress:把 Secret 创建在 wordpress 命名空间。
    • --from-literal=键=值:直接在命令行指定一个键值条目(literal 字面量),K8s 内部以 base64 编码存储。
    • 预期作用 :创建后 Secret 中包含 3 个键:mysql-root-passwordwordpress-db-userwordpress-db-password\ 为行继续符,把一条长命令拆成多行书写。
  2. kubectl get secrets

    • 用途:列出当前默认命名空间(wordpress)下的 Secret。
    • 参数含义 :无参数,展示所有 Secret 摘要;secretssecret 等价,get 支持复数。
    • 预期作用 :输出 mysql / Opaque / 3,表示 Secret 类型为 Opaque、含 3 条数据,创建成功。

4.2 创建 Service

创建两个 Service:mysql-headless(无头服务,为 StatefulSet 管理的 Pod 提供固定网络标识)、mysql(普通 ClusterIP 服务,为 Pod 提供负载均衡入口)。

原始清单(mysql-service.yaml):

yaml 复制代码
root@master30:~/wordpress# cat > mysql-service.yaml <<'EOF'
apiVersion: v1  # API 版本:Service 属于核心 v1 组
kind: Service  # 对象类型:服务,为 Pod 提供稳定访问入口
metadata:
  name: mysql-headless  # 服务名
  namespace: wordpress  # 命名空间
spec:
  type: ClusterIP  # 服务类型:仅集群内部可达的虚拟 IP
  selector:
    app: mysql  ## 匹配 StatefulSet 管理的 Pod 标签
  clusterIP: None  ## 无头服务,ClusterIP 设为 None(不分配集群 IP,DNS 按 服务名.命名空间.svc.cluster.local 解析出所有后端 Pod IP,供 StatefulSet 稳定网络标识使用)
  ports:
  - port: 3306  # 服务对外端口(集群内访问的端口)
    targetPort: 3306  # 转发到 Pod 容器的目标端口
    name: mysql-port  ## 端口名称,便于识别
---
apiVersion: v1  # API 版本
kind: Service  # 对象类型:服务
metadata:
  name: mysql  # 服务名
  namespace: wordpress  # 命名空间
spec:
  type: ClusterIP  # 服务类型:集群内部访问
  selector:
    app: mysql  ## 匹配 StatefulSet 管理的 Pod 标签
  ports:
  - port: 3306  # 服务对外端口
    targetPort: 3306  # 转发到容器内端口
    name: mysql-port  ## 端口名称,便于识别
EOF
# 创建服务
root@master30:~/wordpress# kubectl apply -f mysql-service.yaml

# 没有 CLUSTER-IP 
root@master30:~/wordpress# kubectl get svc
NAME             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
mysql            ClusterIP   10.110.201.224   <none>        3306/TCP   4s
mysql-headless   ClusterIP   None             <none>        3306/TCP   4s

命令详解:

  1. cat > mysql-service.yaml <<'EOF' ... EOF ------ here-document 生成含两个 Service 的清单(--- 分隔多个对象)。
  2. kubectl apply -f mysql-service.yaml ------ 一次性创建 mysql-headlessmysql 两个 Service。
  3. kubectl get svc
    • 用途 :查看当前命名空间所有 Service(svc 为缩写)。
    • 参数含义:无参数默认查看当前 context 命名空间。
    • 预期作用mysql 有 ClusterIP 10.110.201.224mysql-headless 的 CLUSTER-IP 为 None(无头,无固定集群 IP,DNS 直接返回 Pod IP 列表)。

为什么 MySQL 需要无头服务 :StatefulSet 要求提供 serviceName,无头服务为每个 Pod 提供稳定的 DNS 名称(如 mysql-0.mysql-headless.wordpress.svc.cluster.local),保证有状态应用的有序、可识别访问。

4.3 部署 MySQL(StatefulSet)

原始清单(mysql-statefulset.yaml):

yaml 复制代码
root@master30:~/wordpress# vim mysql-statefulset.yaml

apiVersion: apps/v1  # API 版本:StatefulSet 属于 apps 组的 v1
kind: StatefulSet  # 对象类型:有状态工作负载控制器,保证 Pod 有序、稳定,配合 PVC 模板持久化数据
metadata:
  name: mysql  # 名称
  namespace: wordpress  # 命名空间
spec:
  serviceName: mysql-headless  # 必须指向关联的无头服务,用于给每个 Pod 分配稳定网络标识
  replicas: 1  # 副本数 1(MySQL 单实例,避免多副本数据冲突)
  selector:
    matchLabels:
      app: mysql  # 选择器:管理带 app=mysql 标签的 Pod
  template:
    metadata:
      labels:
        app: mysql  # Pod 标签,与 selector 及 Service selector 一致
    spec:
      containers:
      - name: mysql  # 容器名
        image: mysql:5.7  # 镜像
        ports:
        - containerPort: 3306  # 容器监听端口(MySQL 默认端口)
          name: mysql  # 端口名称,便于标识
        env:  # 环境变量(镜像约定)
        - name: MYSQL_ROOT_PASSWORD  # 镜像约定环境变量:MySQL root 密码
          valueFrom:  # 值来源:从 Secret 中取
            secretKeyRef:
              name: mysql  # 引用的 Secret 名
              key: mysql-root-password  # 取的键:将 Secret 中的该键注入为 root 密码
        - name: MYSQL_USER  # 镜像约定环境变量:创建的应用专用用户
          valueFrom:
            secretKeyRef:
              name: mysql  # Secret 名
              key: wordpress-db-user  # 取的键:wordpress 用户名
        - name: MYSQL_PASSWORD  # 镜像约定环境变量:该用户密码
          valueFrom:
            secretKeyRef:
              name: mysql  # Secret 名
              key: wordpress-db-password  # 取的键:wordpress 用户密码
        - name: MYSQL_DATABASE  # 镜像约定环境变量:自动创建的数据库名
          value: "wordpress"  # 直接写死库名 wordpress
        volumeMounts:
        - name: mysql-data  ## 挂载存储卷,名称与 volumeClaimTemplates 一致
          mountPath: /var/lib/mysql  ## MySQL 数据存储路径,数据落盘到该路径实现持久化
  volumeClaimTemplates:  ## PVC 模板,StatefulSet 专属,为每个 Pod 自动生成一个独立 PVC
  - metadata:
      name: mysql-data  # PVC 名称前缀,最终 PVC 名为 mysql-data-mysql-0
    spec:
      accessModes: [ "ReadWriteOnce" ]  # 访问模式 RWO:单节点读写(MySQL 单副本适用)
      storageClassName: "wordpress"  ## 指定引用哪个 StorageClass,触发 NFS 动态制备
      resources:
        requests:
          storage: 10Gi  ## 申请容量,需与底层 PV 容量匹配

命令详解:

  1. vim mysql-statefulset.yaml ------ 使用 vim 编辑器手动创建/编辑 StatefulSet 清单文件(编辑后需 kubectl apply 生效)。
  2. kubectl apply -f mysql-statefulset.yaml ------ 创建 StatefulSet mysql
  3. kubectl get statefulsets.apps ------ 查看 StatefulSet 状态,输出 mysql 1/1 ... 表示期望 1 个副本且就绪 1 个(apps 后缀显式指定 API 组)。
  4. kubectl get pods ------ 查看 Pod,输出 mysql-0 Running,StatefulSet 创建的 Pod 名带有序号后缀(mysql-0)。
  5. kubectl get pvc
    • 用途:查看 PVC 绑定状态。
    • 参数含义:无参数查看当前命名空间所有 PVC。
    • 预期作用 :输出 mysql-data-mysql-0 Bound ... 10Gi RWO wordpress,表示由 volumeClaimTemplates 自动生成的 PVC(名称 = 模板名 + Pod 名)已由 NFS 动态制备成功绑定,容量 10Gi,访问模式 RWO,存储类 wordpress

验证数据库:

bash 复制代码
root@master30:~/wordpress# apt install -y mysql-client
root@master30:~/wordpress# mysql -uwordpress -pWordpress@123 -h 10.110.201.224 -e 'show databases;'
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------------------+
| Database           |
+--------------------+
| information_schema |
| wordpress          |
+--------------------+

命令详解:

  1. apt install -y mysql-client ------ 在 master 节点安装 MySQL 客户端,用于远程连接验证数据库。
  2. mysql -uwordpress -pWordpress@123 -h 10.110.201.224 -e 'show databases;'
    • 用途 :使用 wordpress 用户连接集群内 MySQL Service(ClusterIP 10.110.201.224)并列出数据库。
    • 参数含义-uwordpress 指定用户名;-pWordpress@123 指定密码(-p 后直接拼接,注意命令行明文密码会有安全告警);-h 指定主机;-e 在非交互模式执行单条 SQL。
    • 预期作用 :输出显示 information_schemawordpress 两个库,说明 MySQL 正常启动、专用用户与数据库均创建成功。

步骤 5:部署 PHP

5.1 创建 PVC

PHP 和 Nginx 使用同一份共享存储(存放 WordPress 代码与上传文件),这里手动创建一个名为 wordpress 的 PVC,采用 RWX(多节点读写)访问模式。

原始清单(wordpress-pvc.yaml):

yaml 复制代码
root@master30:~/wordpress# vim wordpress-pvc.yaml

apiVersion: v1  # API 版本:PVC 属于核心 v1 组
kind: PersistentVolumeClaim  # 对象类型:存储请求对象(声明式),申请一块 PV 供 Pod 使用
metadata:
  name: wordpress  # PVC 名称,Deployment 通过 claimName 引用
  namespace: wordpress  # 命名空间(引用它的 Pod 须在同一命名空间)
spec:
  accessModes:
    - ReadWriteMany  # 访问模式 RWX:允许多个节点/多个 Pod 同时读写,PHP 与 Nginx 跨副本共享同一存储的必要条件
  resources:
    requests:
      storage: 10Gi  # 申请容量 10Gi
  storageClassName: wordpress  # 指定使用 wordpress StorageClass,触发 NFS 动态制备自动创建 PV

命令详解:

  1. vim wordpress-pvc.yaml ------ 用 vim 编辑 PVC 清单文件。
  2. kubectl apply -f wordpress-pvc.yaml ------ 创建 PVC wordpress
  3. kubectl get pvc wordpress
    • 用途 :单独查看名为 wordpress 的 PVC 状态。
    • 参数含义pvc 类型 + PVC 名称。
    • 预期作用 :输出 wordpress Bound pvc-... 10Gi RWX wordpress,STATUS 为 Bound 表示已成功绑定动态创建的 PV。

5.2 创建 Service(PHP)

原始清单(php-service.yaml):

yaml 复制代码
root@master30:~/wordpress# vim php-service.yaml

---
apiVersion: v1  # API 版本:Service 属于核心 v1 组
kind: Service  # 对象类型:服务
metadata:
  name: php  # 服务名,Nginx 通过 php.wordpress.svc.cluster.local 访问
  namespace: wordpress  # 命名空间
spec:
  type: ClusterIP  # 服务类型:集群内访问的虚拟 IP 服务
  selector:
    app: php  # 选择带 app=php 标签的 PHP Pod 作为后端
  ports:
  - port: 9000  # 服务端口 9000(PHP-FPM 默认监听端口)
    targetPort: 9000  # 转发到容器内 9000 端口
bash 复制代码
root@master30:~/wordpress# kubectl apply -f php-service.yaml
root@master30:~/wordpress# kubectl get svc php
NAME   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
php    ClusterIP   10.104.30.180   <none>        9000/TCP   21s

命令详解:

  1. vim php-service.yaml ------ 编辑 PHP Service 清单。
  2. kubectl apply -f php-service.yaml ------ 创建 Service php
  3. kubectl get svc php ------ 查看指定服务,输出 php ClusterIP 10.104.30.180 ... 9000/TCP,服务就绪。

5.3 部署 PHP(Deployment)

提示 :镜像为 php:7.2-fpm-mysql(含 mysqli 扩展的定制镜像),需找老师获取或自行构建。

原始清单(php-deploy.yaml):

yaml 复制代码
root@master30:~/wordpress# vim php-deploy.yaml

apiVersion: apps/v1  # API 版本:Deployment 属于 apps 组的 v1
kind: Deployment  # 对象类型:Deployment 控制器,负责滚动更新与副本保障
metadata:
  name: php  # Deployment 名称
  namespace: wordpress  # 命名空间
spec:
  replicas: 2  # 副本数 2,提供 PHP 高可用
  selector:
    matchLabels:
      app: php  # 选择器:管理 app=php 的 Pod
  template:
    metadata:
      labels:
        app: php  # Pod 标签,与 Service/Deployment selector 一致
    spec:
      containers:
      - name: php  # 容器名
        image: php:7.2-fpm-mysql  # 镜像(含 mysqli 扩展的定制版)
        ports:
        - containerPort: 9000  # PHP-FPM 监听 9000,等待 Nginx fastcgi 转发
        volumeMounts:
        - name: wordpress-data  # 挂载卷名
          mountPath: /usr/share/nginx/html  ## PHP 网站根目录(与 Nginx 的 root 目录一致,共享同一存储)
      volumes:
      - name: wordpress-data  # 声明卷
        persistentVolumeClaim:
          claimName: wordpress  # 引用上面创建的 PVC,实现 PHP 与 Nginx 共享代码目录
bash 复制代码
root@master30:~/wordpress# kubectl apply -f php-deploy.yaml

## 验证
root@master30:~/wordpress# kubectl get deploy php
NAME   READY   UP-TO-DATE   AVAILABLE   AGE
php    2/2     2            0           49s

命令详解:

  1. vim php-deploy.yaml ------ 编辑 PHP Deployment 清单。
  2. kubectl apply -f php-deploy.yaml ------ 创建 Deployment php
  3. kubectl get deploy php
    • 用途:查看 PHP 部署状态。
    • 参数含义deploydeployment 缩写。
    • 预期作用 :输出 php 2/2 2 0,表示期望/就绪副本均为 2(AVAILABLE 列的 0 为瞬时采样,以 READY 为准)。

步骤 6:部署 Nginx

6.1 创建 Nginx 配置(ConfigMap)

原始清单(nginx-configmap.yaml):

yaml 复制代码
root@master30:~/wordpress# vim nginx-configmap.yaml

apiVersion: v1  # API 版本:ConfigMap 属于核心 v1 组
kind: ConfigMap  # 对象类型:用于保存非敏感的文本配置
metadata:
  name: nginx  # ConfigMap 名称
  namespace: wordpress  # 指定wordpress命名空间
data:
  nginx.conf: |  # 键名 nginx.conf;| 为 YAML 块标量符号,其后缩进内容按原样多行文本保存
    worker_processes auto;  # 工作进程数设为自动(按 CPU 核数自动生成),提高并发处理能力
    events {
        worker_connections 1024;  # 每个工作进程最多同时保持 1024 个连接
    }
    http {
        include       /etc/nginx/mime.types;  # 引入 MIME 类型映射文件,让浏览器正确识别文件类型
        default_type  application/octet-stream;  # 未匹配到 MIME 类型时返回默认二进制流类型
        sendfile        on;  # 开启高效文件传输(zero-copy),提升静态文件响应速度
        keepalive_timeout  65;  # 长连接超时 65 秒,减少频繁建连开销

        # Wordpress 站点配置
        server {
            listen 80;  # 监听 HTTP 80 端口
            listen 443 ssl;  # 监听 HTTPS 443 端口并启用 SSL
            server_name localhost;  # 虚拟主机名(生产应替换为实际域名,如 blog.liujn.cloud)

            # TLS 配置
            ssl_certificate /etc/nginx/tls/tls.crt;  # TLS 证书路径(由 Secret 挂载而来)
            ssl_certificate_key /etc/nginx/tls/tls.key;  # TLS 证书私钥路径

            # 网站根目录
            root /usr/share/nginx/html;  # 网站根目录(与 PHP 共用同一存储中的 WordPress 代码)
            index index.php index.html;  # 默认首页优先找 index.php,其次 index.html

            # PHP 转发配置(指向wordpress命名空间的PHP Service)
            location ~ \.php$ {  # 正则匹配以 .php 结尾的请求,交给 PHP-FPM 处理
                fastcgi_pass php.wordpress.svc.cluster.local:9000;  # 跨命名空间访问,把 PHP 请求转发到 PHP Service 9000 端口,格式:服务名.命名空间.svc.cluster.local
                fastcgi_index index.php;  # 指定 fastcgi 默认索引页
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;  # 拼出 PHP 脚本真实物理路径传给 PHP-FPM($document_root=根目录,$fastcgi_script_name=请求的脚本名)
                include fastcgi_params;  # 引入 fastcgi 标准参数文件(含请求头、URI 等常见参数)
            }

            # 静态资源缓存
            location ~* \.(jpg|jpeg|png|gif|css|js)$ {  # ~* 忽略大小写匹配图片/CSS/JS 等静态资源
                expires 30d;  # 静态资源客户端缓存 30 天
                add_header Cache-Control "public, max-age=2592000";  # 额外添加缓存响应头,max-age 2592000 秒 = 30 天,允许公共缓存
            }
        }
    }
bash 复制代码
root@master30:~/wordpress# kubectl apply -f nginx-configmap.yaml
root@master30:~/wordpress# kubectl get cm nginx
NAME    DATA   AGE
nginx   1      27s

命令详解:

  1. vim nginx-configmap.yaml ------ 编辑 ConfigMap 清单。
  2. kubectl apply -f nginx-configmap.yaml ------ 创建 ConfigMap nginx
  3. kubectl get cm nginx
    • 用途 :查看 ConfigMap 是否创建成功(cmconfigmap 缩写)。
    • 参数含义nginx 为名称。
    • 预期作用 :输出 nginx 1 27s,表示该 ConfigMap 含 1 条数据(即 nginx.conf)。

6.2 创建 Nginx 证书(openssl 自签名证书)

原始命令:

bash 复制代码
## 生成自签名证书(替换域名)
root@master30:~/wordpress# openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout tls.key -out tls.crt \
  -subj "/CN=wordpress.liujn.cloud/O=wordpress"

## 创建 Secret 存储证书
root@master30:~/wordpress# kubectl create secret tls nginx-tls \
--namespace wordpress \
--cert=tls.crt \
--key=tls.key

root@master30:~/wordpress# kubectl get secret nginx-tls
NAME               TYPE                DATA   AGE
nginx-tls   kubernetes.io/tls   2      2s

命令详解:

  1. openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=wordpress.liujn.cloud/O=wordpress"

    • 用途 :一次性生成自签名 SSL 证书(tls.crt)及其私钥(tls.key)。
    • 参数含义
      • req:openssl 的证书请求/生成子命令;
      • -x509:直接输出自签名 X.509 证书(而非仅 CSR 请求);
      • -nodesno DES,不加密私钥文件,使 Nginx 启动时无需输入密码即可读取;
      • -days 365:证书有效期 365 天;
      • -newkey rsa:2048:同时生成新的 2048 位 RSA 密钥;
      • -keyout tls.key:私钥输出文件;
      • -out tls.crt:证书输出文件;
      • -subj:免交互指定证书主体,/CN=wordpress.liujn.cloud 为通用名(域名),/O=wordpress 为组织名。
    • 预期作用 :当前目录生成 tls.keytls.crt 两个文件,供 Nginx/Ingress 启用 HTTPS。
  2. kubectl create secret tls nginx-tls --namespace wordpress --cert=tls.crt --key=tls.key

    • 用途:创建 TLS 类型 Secret,把证书与私钥上传到集群供 Pod 使用。
    • 参数含义secret tls 指定专门存储证书的 Secret 类型;nginx-tls 为名称;--cert 指定证书文件;--key 指定私钥文件。
    • 预期作用 :集群内生成 kubernetes.io/tls 类型 Secret,含 2 条数据(tls.crt、tls.key)。
  3. kubectl get secret nginx-tls

    • 用途:查看 TLS Secret。
    • 参数含义nginx-tls 为 Secret 名称。
    • 预期作用 :输出 nginx-tls kubernetes.io/tls 2,确认证书 Secret 创建成功。

关于自签名证书提示 :生产环境应使用 CA 签发的受信证书;自签名证书浏览器会提示不受信任,需手动信任或使用 -k(curl 忽略证书校验)。

6.3 创建 Service(Nginx)

原始清单(nginx-service.yaml):

yaml 复制代码
root@master30:~/wordpress# vim nginx-service.yaml

---
apiVersion: v1  # API 版本:Service 属于核心 v1 组
kind: Service  # 对象类型:服务
metadata:
  name: nginx  # 服务名
  namespace: wordpress  # 命名空间
spec:
  type: ClusterIP  # 服务类型:集群内部访问
  selector:
    app: nginx  # 选择 app=nginx 的 Pod 作为后端
  ports:
  - port: 80  # 服务对外端口 80
    targetPort: 80  # 转发到容器 80 端口
    name: http  # 端口命名 http,便于识别
  - port: 443  # 服务对外端口 443
    targetPort: 443  # 转发到容器 443 端口
    name: https  # 端口命名 https
bash 复制代码
root@master30:~/wordpress# kubectl apply -f nginx-service.yaml
root@master30:~/wordpress# kubectl get svc nginx 
NAME    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
nginx   ClusterIP   10.100.41.121   <none>        80/TCP,443/TCP   4s

命令详解:

  1. vim nginx-service.yaml ------ 编辑 Nginx Service 清单。
  2. kubectl apply -f nginx-service.yaml ------ 创建 Service nginx
  3. kubectl get svc nginx ------ 查看服务,输出 nginx ClusterIP 10.100.41.121 ... 80/TCP,443/TCP,同时暴露 80 与 443 端口。

6.4 部署 Nginx(Deployment)

原始清单(nginx-deploy.yaml):

yaml 复制代码
root@master30:~/wordpress# vim nginx-deploy.yaml

apiVersion: apps/v1  # API 版本:Deployment 属于 apps 组的 v1
kind: Deployment  # 对象类型:Deployment 控制器
metadata:
  name: nginx  # Deployment 名称
  namespace: wordpress  # 命名空间
spec:
  replicas: 2  # 副本数 2,为 Nginx/入口提供高可用
  selector:
    matchLabels:
      app: nginx  # 选择器:管理 app=nginx 的 Pod
  template:
    metadata:
      labels:
        app: nginx  # Pod 标签
    spec:
      containers:
      - name: nginx  # 容器名
        image: nginx:1.24  # 镜像
        ports:
        - containerPort: 80  # 暴露容器 80(HTTP)端口
        - containerPort: 443  # 暴露容器 443(HTTPS)端口
        volumeMounts:
        - name: nginx  # 挂载 ConfigMap 卷
          mountPath: /etc/nginx/nginx.conf  ## 把配置作为单个文件挂载到主配置文件路径(整文件替换)
          subPath: nginx.conf  # 只挂载 ConfigMap 中的 nginx.conf 这一个 key,避免覆盖 /etc/nginx 目录下其他文件
        - name: tls-cert  # 挂载证书 Secret 卷
          mountPath: /etc/nginx/tls  ## 证书挂载目录(与 nginx.conf 中 ssl_certificate 路径对应)
          readOnly: true  # 证书目录只读,保障安全
        - name: wordpress-data  # 挂载共享存储卷
          mountPath: /usr/share/nginx/html  ## WordPress 代码根目录(与 PHP 共享同一 PVC)
      volumes:
      - name: nginx  # 卷名
        configMap:
          name: nginx  # 卷类型为 ConfigMap,引用名为 nginx 的 ConfigMap
      - name: tls-cert  # 卷名
        secret:
          secretName: nginx-tls  # 卷类型为 Secret,引用 nginx-tls
      - name: wordpress-data  # 卷名
        persistentVolumeClaim:
          claimName: wordpress  # 卷类型为 PVC,引用 wordpress 共享存储
bash 复制代码
root@master30:~/wordpress# kubectl apply -f nginx-deploy.yaml
root@master30:~/wordpress# kubectl get deploy nginx
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   2/2     2            0           53s

命令详解:

  1. vim nginx-deploy.yaml ------ 编辑 Nginx Deployment 清单。
  2. kubectl apply -f nginx-deploy.yaml ------ 创建 Deployment nginx
  3. kubectl get deploy nginx ------ 查看 Nginx 部署,输出 nginx 2/2 表示 2 个副本全部就绪。

测试 Nginx:

bash 复制代码
# 查看物理位置名称
root@master30:~/wordpress# kubectl get pvc
NAME                 STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
mysql-data-mysql-0   Bound    pvc-c40fcf08-0f68-481f-b266-29b03eca925b   10Gi       RWO            wordpress      <unset>                 15m
wordpress            Bound    pvc-c62430f7-2518-4ba3-99c7-2466853a1526   10Gi       RWX            wordpress      <unset>                 10m

# 存储服务器准备测试页面
root@master30:~/wordpress# echo Hello World From Nginx > /wordpress/wordpress-wordpress-pvc-c62430f7-2518-4ba3-99c7-2466853a1526/index.html
root@master30:~/wordpress# echo "<?php phpinfo(); ?>" > /wordpress/wordpress-wordpress-pvc-c62430f7-2518-4ba3-99c7-2466853a1526/phpinfo.php

root@master30:~/wordpress# kubectl get svc nginx 
NAME    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
nginx   ClusterIP   10.100.41.121   <none>        80/TCP,443/TCP   3m40s

# http 站点
root@master30:~/wordpress# curl http://10.100.41.121/index.html
Hello World From Nginx
root@master30:~/wordpress# curl https://10.100.41.121/index.html -k 
Hello World From Nginx

# https 站点
root@master30:~/wordpress# curl http://10.100.41.121/phpinfo.php -s|grep -o 'PHP Version 7.2'
PHP Version 7.2
root@master30:~/wordpress# curl https://10.100.41.121/phpinfo.php -sk|grep -o 'PHP Version 7.2'
PHP Version 7.2

命令详解:

  1. echo Hello World From Nginx > /wordpress/wordpress-wordpress-pvc-c62430f7-2518-4ba3-99c7-2466853a1526/index.html

    • 用途 :在 NFS 共享目录里写入测试首页 index.html(该目录名即 PVC wordpress 在 NFS 上对应的物理子目录,格式为 命名空间-PVC名-PVC UID)。
    • 参数含义echo 输出字符串;> 重定向覆盖写入文件。
    • 预期作用:文件落到共享存储,PHP/Nginx Pod 都能看到,用于验证存储链路。
  2. echo "<?php phpinfo(); ?>" > .../phpinfo.php

    • 用途:写入一个测试 PHP 文件,输出 PHP 版本信息,用于验证 PHP-FPM 转发链路。
    • 参数含义<?php phpinfo(); ?> 是 PHP 内建函数,输出当前 PHP 配置与版本信息。
    • 预期作用:可通过 curl 验证 Nginx→PHP-FPM 链路是否打通。
  3. curl http://10.100.41.121/index.html

    • 用途 :通过 Nginx Service 的 ClusterIP(HTTP)请求 index.html
    • 参数含义curl 发起 HTTP 请求;10.100.41.121 为 Service ClusterIP。
    • 预期作用 :返回 Hello World From Nginx,说明 HTTP 请求链路与共享存储挂载正常。
  4. curl https://10.100.41.121/index.html -k

    • 用途:通过 HTTPS 请求同上内容。
    • 参数含义-k 忽略自签名证书校验(否则 curl 会因证书不受信而报错)。
    • 预期作用 :同样返回 Hello World From Nginx,说明 443/TLS 链路正常。
  5. curl http://10.100.41.121/phpinfo.php -s | grep -o 'PHP Version 7.2'

    • 用途:请求 PHP 测试页并从输出中提取 PHP 版本信息。
    • 参数含义-s 静默模式(不显示进度条/错误);grep -o 只输出匹配到的部分字符串;'PHP Version 7.2' 为匹配内容。
    • 预期作用 :返回 PHP Version 7.2,证明 HTTP 下 Nginx→PHP-FPM 转发成功。
  6. curl https://10.100.41.121/phpinfo.php -sk | grep -o 'PHP Version 7.2'

    • 用途:HTTPS 场景同 5 验证。
    • 参数含义-s 静默;-k 忽略证书校验。
    • 预期作用 :返回 PHP Version 7.2,HTTPS 下 PHP 解析亦正常。

6.5 部署 WordPress 代码

原始命令:

bash 复制代码
## 进入 NFS 服务器(IP:10.1.8.30),下载 Wordpress 源码
root@master30:~/wordpress# unzip wordpress-4.9.4-zh_CN.zip 
root@master30:~/wordpress# cp -a wordpress/* /wordpress/wordpress-wordpress-pvc-c62430f7-2518-4ba3-99c7-2466853a1526/

## 修改配置文件(连接 MySQL)
root@master30:~/wordpress# cp /wordpress/wordpress-wordpress-pvc-c62430f7-2518-4ba3-99c7-2466853a1526/wp-config{-sample,}.php 

## 配置数据库信息
root@master30:~/wordpress# vim /wordpress/wordpress-wordpress-pvc-c62430f7-2518-4ba3-99c7-2466853a1526/wp-config.php
/** WordPress数据库的名称 */
define('DB_NAME', 'wordpress');

/** MySQL数据库用户名 */
define('DB_USER', 'wordpress');

/** MySQL数据库密码 */
define('DB_PASSWORD', 'Wordpress@123');

/** MySQL主机 */
define('DB_HOST', 'mysql');

命令详解:

  1. unzip wordpress-4.9.4-zh_CN.zip

    • 用途:解压 WordPress 中文版源码压缩包。
    • 参数含义unzip 为解压命令;wordpress-4.9.4-zh_CN.zip 为已下载到当前目录的 WordPress 4.9.4 中文语言包压缩文件。
    • 预期作用 :解压出 wordpress 目录,内含完整博客程序源码。
  2. cp -a wordpress/* /wordpress/wordpress-wordpress-pvc-.../

    • 用途:把解压出的 WordPress 全部源码复制到 NFS 上的 PVC 物理目录(PHP/Nginx 共享挂载)。
    • 参数含义cp -a 递归复制并保留文件权限、时间戳等属性;* 通配所有文件与子目录;目标路径即 6.4 中 echo 写入测试文件所在的物理目录。
    • 预期作用:PHP/Nginx Pod 通过挂载即可直接读取 WordPress 代码。
  3. cp /wordpress/.../wp-config{-sample,}.php

    • 用途 :把示例配置文件 wp-config-sample.php 复制为 wp-config.php(大括号展开 {a,b} 等价于两个路径参数:wp-config-sample.php wp-config.php)。
    • 参数含义cp 复制;源文件为 wp-config-sample.php,目标为 wp-config.php
    • 预期作用:生成 WordPress 实际使用的数据库配置文件,供下一步编辑。
  4. vim .../wp-config.php ------ 编辑 WordPress 数据库配置,把 DB_NAME/DB_USER/DB_PASSWORD/DB_HOST 改为实际值:

    • define('DB_NAME', 'wordpress'); ------ 数据库名,对应 MySQL 里创建的 wordpress 库(4.3 中的 MYSQL_DATABASE)。
    • define('DB_USER', 'wordpress'); ------ 数据库用户名,对应 4.1 Secret 中的 wordpress-db-user
    • define('DB_PASSWORD', 'Wordpress@123'); ------ 数据库密码,对应 Secret 中的 wordpress-db-password
    • define('DB_HOST', 'mysql'); ------ 数据库主机,写 Service 名 mysql(同命名空间内 K8s DNS 自动解析到 MySQL Service 的 ClusterIP)。

步骤 7:部署 LoadBalancer(MetalLB)

裸金属/自建 K8s 集群没有云厂商的负载均衡器,使用 MetalLB 提供"LoadBalancer 类型 Service"的外部 IP 分配能力,为后续 Ingress Controller 提供外部入口地址。

原始命令:

bash 复制代码
root@master30:~/wordpress# tar -xf metallb-0.14.8.tar.gz
root@master30:~/wordpress# kubectl apply -f metallb-0.14.8/config/manifests/metallb-native.yaml

# 等待着所有pod正常运行再进行下一步
root@master30:~/wordpress# kubectl get all -n metallb-system 
NAME                              READY   STATUS    RESTARTS   AGE
pod/controller-786f9df989-98bjh   1/1     Running   0          85s
pod/speaker-gthhx                 1/1     Running   0          85s
pod/speaker-jwj25                 1/1     Running   0          85s
pod/speaker-s5zvq                 1/1     Running   0          85s

# 配置地址池
root@master30:~/wordpress# cat << 'EOF' > ippool.yaml
apiVersion: metallb.io/v1beta1  # MetalLB 自定义资源 API 版本
kind: IPAddressPool  # 资源类型:IP 地址池,MetalLB 从这里取 IP 分配给 LoadBalancer Service
metadata:
  name: first-pool  # 地址池名
  namespace: metallb-system  # 命名空间
spec:
  addresses:
  - 10.1.8.40-10.1.8.80  # 可分配的 IP 段,从 10.1.8.40 到 10.1.8.80(与集群节点同网段,确保路由可达)
EOF
root@master30:~/wordpress# kubectl apply -f ippool.yaml

# 配置 lay2
root@master30:~/wordpress# cat << 'EOF' > L2.yaml
apiVersion: metallb.io/v1beta1  # MetalLB 自定义资源 API 版本
kind: L2Advertisement  # 资源类型:二层通告,MetalLB 通过 ARP 在二层广播来宣告 VIP
metadata:
  name: example  # 通告名
  namespace: metallb-system  # 命名空间
EOF
root@master30:~/wordpress# kubectl apply -f L2.yaml

命令详解:

  1. tar -xf metallb-0.14.8.tar.gz

    • 用途:解压 MetalLB 0.14.8 版本源码/资源包。
    • 参数含义tar 归档工具;-xf 表示解压(-x extract,-f 指定归档文件)。
    • 预期作用 :解压出包含 config/manifests/metallb-native.yaml 等文件的目录。
  2. kubectl apply -f metallb-0.14.8/config/manifests/metallb-native.yaml

    • 用途:应用 MetalLB 官方原生清单(CRD、Controller、Speaker 等)。
    • 参数含义apply -f 声明式应用清单文件。
    • 预期作用 :在 metallb-system 命名空间部署 MetalLB 全部组件。
  3. kubectl get all -n metallb-system

    • 用途:查看 MetalLB 命名空间下所有资源状态。
    • 参数含义get all 列出常见资源(Pod 等);-n 指定命名空间。
    • 预期作用:输出显示 1 个 controller 与 3 个 speaker(每个节点一个)均 Running,MetalLB 正常工作后再进行下一步。
  4. cat << 'EOF' > ippool.yaml ... EOF

    • 用途 :生成 MetalLB 地址池清单 ippool.yaml<<'EOF' 无变量展开)。
    • 预期作用 :定义可对外分配的 IP 地址范围。字段含义见上方 YAML 内 # 注释。
  5. kubectl apply -f ippool.yaml ------ 应用地址池。

  6. cat << 'EOF' > L2.yaml ... EOF ------ 生成 L2 通告清单 L2.yaml。字段含义见上方 YAML 内 # 注释。

  7. kubectl apply -f L2.yaml ------ 应用二层通告配置。至此 MetalLB 配置完成,可按 L2 模式对外分配地址。


步骤 8:部署 Ingress

Nginx Ingress Controller 是集群的南北向流量入口:外部请求 → Ingress(域名规则) → Nginx Service → Nginx Pod;同时配合 MetalLB 拿到外部 IP。

原始命令:

bash 复制代码
root@master30:~/wordpress# tar -xf ingress-nginx-controller-v1.11.2.tar.gz
root@master30:~/wordpress# kubectl apply -f ingress-nginx-controller-v1.11.2/deploy/static/provider/cloud/deploy.yaml
root@master30:~/wordpress# kubectl get svc -n ingress-nginx 
NAME                                         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
service/ingress-nginx-controller             LoadBalancer   10.107.255.83   10.1.8.40     80:30973/TCP,443:32344/TCP   14s
service/ingress-nginx-controller-admission   ClusterIP      10.106.37.158   <none>        443/TCP                      8m15s

root@master30:~/wordpress# cat > blog-ingress.yaml <<'EOF'
apiVersion: networking.k8s.io/v1  # API 版本:Ingress 属于 networking.k8s.io 组的 v1(稳定版 API)
kind: Ingress  # 资源类型:HTTP/S 层(七层)路由规则,把外部请求按域名/路径转发到集群内 Service
metadata:
  name: blog  # Ingress 名称
  namespace: wordpress  # 命名空间
  annotations:  # 注解:给 Ingress Controller 的附加指令
    nginx.ingress.kubernetes.io/ssl-passthrough: "true"  # SSL 透传:Ingress 不解密,直接把 TLS 流量原样转发给后端(后端 Nginx Pod 自己完成 TLS 终止,依赖 6.2 的证书)
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"  # 声明后端协议为 HTTPS:Ingress 以 HTTPS 方式连接后端 Service 的 443 端口
spec:
  ingressClassName: nginx  # 指定由哪个 Ingress Controller 处理(这里是 Nginx Ingress Controller)
  rules:
  - host: blog.liujn.cloud  # 域名规则,访问该域名时命中此规则(客户端需配置 DNS 解析)
    http:
      paths:
      - path: /  # 匹配的 URL 路径,/ 匹配全部路径
        pathType: Prefix  # 路径匹配类型:前缀匹配(以 / 为前缀的请求均命中)
        backend:
          service: 
            name: nginx  # 转发目标后端 Service 名 nginx
            port: 
              number: 443  # 转发到后端 Service 的 443 端口(对应 nginx-service 里的 https 端口)
EOF
root@master30:~/wordpress# kubectl apply -f blog-ingress.yaml
root@master30:~/wordpress# kubectl describe ingress blog
Name:             blog
Labels:           <none>
Namespace:        wordpress
Address:          
Ingress Class:    nginx
Default backend:  <default>
Rules:
  Host              Path  Backends
  ----              ----  --------
  blog.liujn.cloud  
                    /   nginx:443 (10.224.113.140:443,10.224.19.12:443)
Annotations:        nginx.ingress.kubernetes.io/backend-protocol: HTTPS
                    nginx.ingress.kubernetes.io/ssl-passthrough: true
Events:
  Type    Reason  Age   From                      Message
  ----    ------  ----  ----                      -------
  Normal  Sync    6s    nginx-ingress-controller  Scheduled for sync

命令详解:

  1. tar -xf ingress-nginx-controller-v1.11.2.tar.gz

    • 用途:解压 Nginx Ingress Controller v1.11.2 资源包。
    • 参数含义tar -xf 解压指定归档。
    • 预期作用 :解压出含 deploy/static/provider/cloud/deploy.yaml 的部署清单。
  2. kubectl apply -f ingress-nginx-controller-v1.11.2/deploy/static/provider/cloud/deploy.yaml

    • 用途:部署 Nginx Ingress Controller(cloud provider 清单,配合 MetalLB 获取外部 IP)。
    • 参数含义apply -f 应用清单;路径选择 provider/cloud 版本以支持 LoadBalancer 类型。
    • 预期作用 :在 ingress-nginx 命名空间部署 controller 及配套服务。
  3. kubectl get svc -n ingress-nginx

    • 用途:查看 Ingress Controller 的服务状态。
    • 参数含义svc 服务类型;-n 命名空间。
    • 预期作用 :输出显示 ingress-nginx-controller 类型为 LoadBalancerEXTERNAL-IP 为 10.1.8.40 (由 MetalLB 从 10.1.8.40-10.1.8.80 池分配),80:30973/TCP,443:32344/TCP 表示外部 80/443 映射到节点的 30973/32344 端口。
  4. cat > blog-ingress.yaml <<'EOF' ... EOF ------ 用 here-document 生成 Ingress 规则清单,各字段含义见上方 YAML 内 # 注释。

  5. kubectl apply -f blog-ingress.yaml ------ 创建 Ingress blog

  6. kubectl describe ingress blog

    • 用途:查看 Ingress 的详细配置、后端与事件。
    • 参数含义describe 显示详请。
    • 预期作用 :输出显示规则 blog.liujn.cloud / → nginx:443(后端为两个 Nginx Pod 的 443 端口,10.224.x.x 为 Pod IP),Annotations 已生效,事件显示已同步。

步骤 9:初始化站点

Windows 访问需提前配置域名解析(如将 blog.liujn.cloud 解析到 MetalLB 分配的外部 IP 10.1.8.40)。

访问 https://blog.liujn.cloud,进入 WordPress 博客站点页面:

点击 现在安装,继续:

后续过程省略(按提示完成站点标题、管理员账号、邮箱即可进入后台)。


部署小结

至此,已完整部署一套基于 K8s 的 LNMP 架构 WordPress 博客,核心链路总结如下:

  1. 存储层 :NFS 服务器(/wordpress 共享目录)→ NFS Provisioner 监听 PVC → StorageClass wordpress 动态创建 PV;
  2. 数据层:MySQL 以 StatefulSet 部署,数据经 PVC(RWO)持久化到 NFS,账号密码通过 Secret 注入;
  3. 应用层:PHP-FPM(Deployment ×2)与 Nginx(Deployment ×2)共享同一 PVC(RWX),PHP 代码与站点文件统一存储;
  4. 入口层 :Ingress(blog.liujn.cloud)→ Nginx Service → Nginx Pod,Nginx 经 fastcgi_pass 转发 PHP 请求至 PHP Service → PHP-FPM 容器,PHP 再连接 MySQL 完成数据读写;
  5. 安全:Nginx 的 TLS 证书/私钥以 Secret 保存,配置以 ConfigMap 保存,数据库密码以 Secret 保存;
  6. 扩展能力:MetalLB 为入口提供外部 IP,Ingress Controller 统一北向流量,后续可按项目需求 6、7 追加 Metrics Server 与 HPA(最小 2、最大 5 副本),实现基于 CPU/内存指标的自动扩缩容。

注意事项

  • 自签名证书仅为实验用途,生产环境建议使用 Let's Encrypt 等受信证书,并在 Ingress 层配置证书校验;
  • NFS 共享权限使用了 no_root_squash,生产环境应改回 root_squash 并细化访问白名单;
  • MySQL 仅单副本,生产建议配合备份/从库方案;
  • ssl-passthrough + Nginx Pod 自身终止 TLS 是本例采用的方式(适合自签名证书场景),也可改为由 Ingress Controller 统一终止 TLS 以便复用证书管理能力。

K8s 部署 LNMP 架构的文章到此结束。

相关推荐
汪碧康2 小时前
xkube-v4.3版本的安全性进行了增强
docker·云原生·容器·kubernetes·xkube
EterNity_TiMe_2 小时前
Pascal Editor 本地部署实战:Bun 启动 WebGPU 3D 编辑器,再解决公网访问报错
人工智能·docker·ai·容器·cpolar
AugustSkys6 小时前
从 Docker 到 Containerd:Kubernetes 时代容器运行时完全指南
docker·容器·kubernetes·containerd
莫陌尛.10 小时前
Docker MySQL 删表卡死、执行超时(MDL锁阻塞)问题复盘与根治方案
mysql·docker·容器
天天喝旺仔11 小时前
Go 并发编程:Goroutine 与 Channel 实战
云原生·性能优化·架构·go
阿里云云原生16 小时前
记录一次排障范式的升级:当 AI 拥有“业务字典”,我们如何定义可信的数据查询?
云原生
正仪17 小时前
kubernetes中list-watch机制
云原生·容器·kubernetes
cui_hao_nan18 小时前
从零搭建 Kubernetes 集群:Ubuntu + kubeadm 完整实战
ubuntu·容器·kubernetes
fb_1234519 小时前
Docker入门-第3章-容器镜像深度解析
运维·docker·容器