K8s部署带SSL的WordPress博客

K8s实战|用Secret+ConfigMap部署带SSL的WordPress博客,MySQL与WordPress全流程拆解

摘要:本文基于 Kubernetes 原生资源(Secret、ConfigMap、Pod)完成一套带 HTTPS 加密的 WordPress 博客部署,涵盖 MySQL 凭据脱敏存储、自定义 SSL 镜像构建、自签证书注入、Apache vhost 配置挂载等核心环节,全程可复现。


一、实验架构总览

整个 Blog 应用由两个 Pod 组成:

组件 镜像 作用 关键配置来源
MySQL hub.laoma.cloud/library/mysql:latest 数据库服务 Secret mysql(root 密码、业务库账号密码)
WordPress hub.laoma.cloud/library/wordpress:ssl(自定义构建) Web 博客 Secret mysql(连库凭据)+ Secret www-tls(SSL证书)+ ConfigMap blog-config(Apache vhost)

数据流向:浏览器 → WordPress Pod(443/HTTPS) → MySQL Pod(3306)。


二、部署 MySQL:凭据全部走 Secret

2.1 为什么要用 Secret?

MySQL 镜像启动时需要传入 root 密码、业务账号、业务密码、业务库名四组敏感信息。如果直接写在 Pod 的 yaml 明文里,谁都能 kubectl get pod -o yaml 看到,存在泄露风险。用 Secret 统一存放,Pod 通过 secretKeyRef 引用,配置文件里只出现 key 名,不出现真实值。

2.2 创建 Secret

先准备一个 env 文件,把四组变量写进去:

bash 复制代码
# 编写环境变量文件
[root@master30 configure]# vim mysql-env.yaml
MYSQL_ROOT_PASSWORD=123
MYSQL_USER=blog
MYSQL_PASSWORD=123
MYSQL_DATABASE=blog

注意:这个文件虽然叫 .yaml,但内容其实是 KEY=VALUE 格式,配合 --from-env-file 使用。

用 kubectl create secret 一键生成:

bash 复制代码
# 基于 env 文件创建 generic 类型 Secret
[root@master30 configure]# kubectl create secret generic mysql --from-env-file=./mysql-env.yaml
secret/mysql created

# 验证 Secret 已生成,DATA 为 4 说明有 4 个键值对
[root@master30 configure]# kubectl get secrets
NAME    TYPE     DATA   AGE
mysql   Opaque   4      6s

2.3 编写 MySQL Pod

bash 复制代码
[root@master30 configure]# vim pod-mysql.yaml
yaml 复制代码
---
apiVersion: v1
kind: Pod
metadata:
  name: mysql
  labels:
    name: mysql
spec:
  containers:
  - image: hub.laoma.cloud/library/mysql:latest
    imagePullPolicy: IfNotPresent
    name: mysql
    ports:
    - containerPort: 3306
      name: mysql
    env:
    - name: MYSQL_ROOT_PASSWORD
      valueFrom:
        secretKeyRef:
          name: mysql
          key: MYSQL_ROOT_PASSWORD
    - name: MYSQL_USER
      valueFrom:
        secretKeyRef:
          name: mysql
          key: MYSQL_USER
    - name: MYSQL_PASSWORD
      valueFrom:
        secretKeyRef:
          name: mysql
          key: MYSQL_PASSWORD
    - name: MYSQL_DATABASE
      valueFrom:
        secretKeyRef:
          name: mysql
          key: MYSQL_DATABASE

逐行要点说明:

  • imagePullPolicy: IfNotPresent:节点本地有镜像就不拉,省带宽。
  • 四个 env 全部通过 valueFrom.secretKeyRef 引用 Secret mysql 里对应的 key,yaml 里看不到真实密码。
  • MYSQL_DATABASE=blog 这个环境变量的作用是:MySQL 容器首次初始化时自动创建名为 blog 的数据库。
  • MYSQL_USER=blog + MYSQL_PASSWORD=123:自动创建业务账号 blog,并自动授予 blog 库的全部权限。

2.4 启动并验证 MySQL

bash 复制代码
# 应用 Pod
[root@master30 configure]# kubectl apply -f pod-mysql.yaml

# 查看 Pod 状态和分配到的 IP
[root@master30 configure]# kubectl get pods mysql -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP             NODE                   NOMINATED NODE   READINESS GATES
mysql   1/1     Running   0          25s   10.224.19.2   worker31.laoma.cloud   <none>           <none>

记下 MySQL Pod 的 IP:10.224.19.2(后面 WordPress 要连这个地址)。

用 mysql 客户端验证业务账号能正常登录并看到自动创建的 blog 库:

bash 复制代码
# 用 blog 账号远程连接 MySQL Pod,查看数据库列表
[root@master30 configure]# mysql -u blog -p123 -h 10.224.19.2 -e 'show databases;'
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------------------+
| Database           |
+--------------------+
| blog               |
| information_schema |
| performance_schema |
+--------------------+

看到 blog 库说明 MySQL 初始化成功,业务账号权限正常。

⚠️ 小提示:命令行里直接 -p123 会有 Warning,生产环境建议用 -p 回车后交互输入,或用 ~/.my.cnf 配置。


三、构建带 SSL 支持的 WordPress 镜像

3.1 为什么要自己构建?

官方 wordpress 镜像基于 Apache,但默认没有开启 SSL 模块 (mod_ssl)。如果直接用官方镜像挂载 443 端口,Apache 会因为找不到 SSLEngine 指令对应的模块而启动失败。所以需要在官方镜像基础上启用 ssl、headers、rewrite 三个模块。

3.2 编写 Dockerfile

bash 复制代码
[root@hub ~]# docker pull hub.laoma.cloud/library/wordpress:latest
[root@hub ~]# vim Dockerfile
dockerfile 复制代码
FROM hub.laoma.cloud/library/wordpress
RUN a2enmod ssl && a2enmod headers && a2enmod rewrite
EXPOSE 80 443

逐行解释:

  • FROM:基于公司 Harbor 里的官方 wordpress 镜像。
  • a2enmod ssl:开启 Apache SSL 模块(HTTPS 必备)。
  • a2enmod headers:开启 HTTP 头控制模块(后续做安全头、跳转常用)。
  • a2enmod rewrite:开启 URL 重写模块(WordPress 固定链接、伪静态必备)。
  • EXPOSE 80 443:声明两个端口,80 跑 HTTP,443 跑 HTTPS。

3.3 构建并推送私有仓库

bash 复制代码
# 构建镜像,打上 ssl 标签
[root@hub ~]# docker build -t hub.laoma.cloud/library/wordpress:ssl .

# 登录hub
[root@hub ~]# docker login hub.laoma.cloud -uadmin 

# 推送到 Harbor 私有仓库,供 K8s 节点拉取
[root@hub ~]# docker push hub.laoma.cloud/library/wordpress:ssl

四、准备 SSL 证书

4.1 生成自签证书(三步走)

实验环境用自签证书即可,生产环境建议用 Let's Encrypt 或商业 CA。

bash 复制代码
# 第 1 步:生成 2048 位 RSA 私钥
[root@master30 configure]# openssl genrsa -out www.key 2048

# 第 2 步:生成证书签名请求(CSR)
# -subj 里 CN 必须填网站域名,浏览器校验时会用到
[root@master30 configure]# openssl req -new -key www.key -out www.csr \
  -subj "/C=CN/ST=JS/L=NJ/O=LM/OU=DEVOPS/CN=www.laoma.cloud/emailAddress=admin@laoma.cloud"

# 第 3 步:用私钥自签名,生成有效期 10 年(3650 天)的证书
[root@master30 configure]# openssl x509 -req -days 3650 -in www.csr -signkey www.key -out www.crt

4.2 把证书存成 TLS 类型 Secret

K8s 专门提供了 kubernetes.io/tls 类型的 Secret 来存证书,一条命令搞定:

bash 复制代码
# 创建 TLS Secret,--cert 指向 crt,--key 指向 key
[root@master30 configure]# kubectl create secret tls www-tls --cert=./www.crt --key=./www.key
secret/www-tls created

# 验证:TYPE 为 kubernetes.io/tls,DATA 为 2(一个 crt 一个 key)
[root@master30 configure]# kubectl get secrets www-tls
NAME      TYPE                DATA   AGE
www-tls   kubernetes.io/tls   2      6s

💡 这种 tls 类型的 Secret 挂载到容器后,会自动生成 tls.crt 和 tls.key 两个文件,路径正好对应 Apache 配置里写的 /etc/ssl/certs/。


五、用 ConfigMap 提供 Apache vhost 配置

5.1 编写 SSL 虚拟主机配置

bash 复制代码
[root@master30 configure]# vim wp-ssl.conf
apache 复制代码
<VirtualHost *:443>
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    SSLEngine on
    # 注意证书位置:Secret 挂载后默认文件名就是 tls.crt / tls.key
    SSLCertificateFile      /etc/ssl/certs/tls.crt
    SSLCertificateKeyFile   /etc/ssl/certs/tls.key

    <FilesMatch "\.(?:cgi|shtml|phtml|php)$">
        SSLOptions +StdEnvVars
    </FilesMatch>

    <Directory /usr/lib/cgi-bin>
        SSLOptions +StdEnvVars
    </Directory>
</VirtualHost>

关键点:

  • SSLEngine on:开启 SSL。
  • 证书路径 /etc/ssl/certs/tls.crt 和 tls.key:后面我们把 www-tls 这个 Secret 挂载到 /etc/ssl/certs,Secret 里的两个 key 会自动落成这两个文件名,路径完全对上。
  • SSLOptions +StdEnvVars:让 PHP 能通过 $_SERVER['HTTPS'] 感知到当前是 HTTPS 访问,WordPress 才能正确生成 https 的链接。

5.2 创建 ConfigMap

bash 复制代码
# 用 --from-file 把整个 conf 文件挂成 ConfigMap
[root@master30 configure]# kubectl create cm blog-config --from-file=wp-ssl.conf

# 验证
[root@master30 configure]# kubectl get cm blog-config
NAME          DATA   AGE
blog-config   1      7s

💡 ConfigMap 挂载到 /etc/apache2/sites-enabled 目录后,文件名 wp-ssl.conf 会成为该目录下的一个配置文件,Apache 启动时自动加载。


六、部署 WordPress Pod

6.1 编写 Pod 定义

bash 复制代码
[root@master30 configure]# vim pod-blog.yaml
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: blog
  labels:
    run: blog
spec:
  containers:
  - image: hub.laoma.cloud/library/wordpress:ssl
    imagePullPolicy: IfNotPresent
    name: wordpress
    env:
    - name: WORDPRESS_DB_USER
      valueFrom:
        secretKeyRef:
          name: mysql
          key: MYSQL_USER
    - name: WORDPRESS_DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: mysql
          key: MYSQL_PASSWORD
    - name: WORDPRESS_DB_NAME
      valueFrom:
        secretKeyRef:
          name: mysql
          key: MYSQL_DATABASE
    - name: WORDPRESS_DB_HOST
      value: 10.224.19.2
    ports:
    - containerPort: 80
      name: http
      protocol: TCP
    - containerPort: 443
      name: https
      protocol: TCP
    volumeMounts:
    - name: blog-config
      mountPath: "/etc/apache2/sites-enabled"
    - name: www-tls
      mountPath: "/etc/ssl/certs"
  volumes:
  - name: blog-config
    configMap:
      name: blog-config
  - name: www-tls
    secret:
      secretName: www-tls

配置逻辑拆解:

配置项 来源 作用
WORDPRESS_DB_USER Secret mysql → MYSQL_USER WordPress 连库用户名(blog)
WORDPRESS_DB_PASSWORD Secret mysql → MYSQL_PASSWORD WordPress 连库密码(123)
WORDPRESS_DB_NAME Secret mysql → MYSQL_DATABASE WordPress 使用的库名(blog)
WORDPRESS_DB_HOST 写死 10.224.19.2 MySQL Pod 的 Cluster IP(实验阶段直接写 IP,生产建议用 Service)
blog-config 卷 ConfigMap 挂载 Apache SSL vhost 配置到 sites-enabled
www-tls 卷 Secret(tls) 挂载证书和私钥到 /etc/ssl/certs

6.2 启动并查看状态

bash 复制代码
[root@master30 configure]# kubectl apply -f pod-blog.yaml

# 两个 Pod 都 Running 即正常
[root@master30 configure]# kubectl get pods
NAME    READY   STATUS    RESTARTS   AGE
blog    1/1     Running   0          3s
mysql   1/1     Running   0          10m

七、访问博客站点

Pod IP 是集群内部地址,外部无法直接访问。用 kubectl port-forward 把 Pod 的 443 端口转发到 master 节点的 8443 端口:

bash 复制代码
# --address 指定监听地址,把 Pod 443 映射到本机 8443
[root@master30 configure]# kubectl port-forward pod/blog --address 10.1.8.30 8443:443
Forwarding from 10.1.8.30:8443 -> 443

然后浏览器访问:

复制代码
https://10.1.8.30:8443/

因为是自签证书,浏览器会提示"您的连接不是私密连接",点"高级 → 继续前往"即可。看到 WordPress 安装向导页面就说明全链路打通了。


八、踩坑总结

  1. 官方 wordpress 镜像没有 mod_ssl :直接挂 443 会报 Invalid command 'SSLEngine',必须自己 a2enmod ssl 构建镜像。
  2. 证书路径要对得上 :tls 类型 Secret 挂载后文件名固定为 tls.crt 和 tls.key,Apache 配置里写的路径必须和挂载点拼起来一致。
  3. WORDPRESS_DB_HOST 不能写 localhost:WordPress 和 MySQL 是两个独立 Pod,必须写 MySQL Pod 的 IP(或 Service 名)。
  4. ConfigMap 挂载会覆盖原目录 :把 blog-config 挂到 /etc/apache2/sites-enabled 后,原目录里的 000-default.conf 会被隐藏。如果发现 80 端口不响应,就是这个原因------本文我们只跑 443,所以不影响。
  5. Secret 更新不会自动滚动到 Pod:Secret/ConfigMap 修改后,已运行的 Pod 里的挂载文件不会实时更新,需要重建 Pod(生产环境建议用 Reloader 或滚动重启)。

九、整体流程图

复制代码
浏览器
  │  https://10.1.8.30:8443
  ▼
kubectl port-forward (master:8443 → blog:443)
  │
  ▼
blog Pod (wordpress:ssl)
  ├── /etc/apache2/sites-enabled ← ConfigMap blog-config (wp-ssl.conf)
  ├── /etc/ssl/certs            ← Secret www-tls (tls.crt + tls.key)
  └── env                       ← Secret mysql (连库三件套)
          │  TCP 3306
          ▼
mysql Pod (mysql:latest)
  └── env ← Secret mysql (root密码 + blog账号 + blog库)

十、写在最后

这套实验把 K8s 里三个最常用的资源串了起来:Secret 管敏感凭据、ConfigMap 管配置文件、Pod 负责编排容器。掌握这个模式后,以后部署任何有状态应用(不只是 WordPress),思路都是一样的:

  • 敏感信息 → Secret
  • 普通配置文件 → ConfigMap
  • 应用镜像里缺的模块 → 自己 Dockerfile 构建
  • 证书 → tls 类型 Secret
相关推荐
mengge.cloud3 小时前
1022小白入门教程(番外筑基)— nerdctl 容器基本功 + K8s 资源编写
linux·网络·云原生·容器·kubernetes·云计算·k8s
March.s3 小时前
Kubernetes 控制器深度指南:从 ReplicaSet 到 DaemonSet
云原生·容器·kubernetes
你看我名字4 小时前
Kubernetes HPA 自动扩缩容详解:指标、策略、资源与常见故障
云原生·容器·kubernetes
zxanz11 天前
SSL 证书该怎么申请?操作复杂吗?
网络·网络协议·ssl
Lysander.Jovian1 天前
Node 和 Cluster部署
kubernetes
m0_617493941 天前
昇腾 NPU Docker 部署实战:解决 stub library 报错并实现模型正常加载
运维·docker·容器
科学熊1 天前
深入浅出 Kubernetes介绍
kubernetes
xixiaoyunya1 天前
Docker 常用命令与实战:从入门到部署一个简单应用
docker·容器·eureka
flytalei1 天前
GitOps 实战:基于 Argo CD 的 Kubernetes 应用版本回滚
云原生·容器·kubernetes