自2021年,我开始运维一个日均PV 10万+的 Discuz! X论坛站点。接手后陆续发现一些问题难以通过传统方法解决,遂决定对其进行容器化改造。
1. 为什么要对 Discuz! X 进行容器化改造
1.1. 原部署方案为单机部署
Discuz! X 论坛的默认部署方式是单机部署,自然会出现一些单机部署会发生的问题:
- 单点故障:如果这台机器出现任何问题,会导致整个论坛处于不可用状态。包括 Nginx、PHP 进程出现问题,机器关机、重启等。
- 扩容困难:遇到搞活动时期,扩容需重启(使用的虚拟机为腾讯云CVM,可动态修改虚拟机配置,但需要重启,重启时间为数分钟)。而且一旦容量预估失败,活动期间调整容量几乎不可能。
1.2. PHP环境部署复杂
- 扩展安装困难:开发以来的很多扩展安装比较复杂,新增一个扩展往往要倒腾半天。例如 grpc 扩展,开发人员本地安装成功但我按照开发人员的方法无法安装成功;更让人崩溃的是在测试环境安装调试OK后再生产环境安装依然出现了问题。pcel 执行也有失败的概率。
- 扩展安装时间久:新增 PHP 扩展往往需要停服更新,往往安装方法既受限于网速,又受限于源码编译构建的速度。万一出现意料之外的情况需要增加停机时间。
1.3. 支持滚动升级
实现版本更新用户无感知
2. 各项关键问题的解决方案
2.1. PHP 环境安装使用 Docker 镜像
这边使用的基础镜像为:php:7.2-fpm
,为 PHP 官方发布的镜像。该镜像也能非常方便的安装 PHP 扩展。该项目也依赖了 composer,在 PHP 镜像中编译添加 composer 比较困难,比较简单的方法是,使用 COPY
命令从 composer 镜像中复制 composer 的二进制文件。示例的 Dockerfile
如下:
1 | FROM php:7.2-fpm |
2.2. NFS 解决 Discuz! X 负载均衡问题
Discuz! X 多机部署的一个问题就在于 Discuz! X 使用了本地缓存目录和本地存储目录。我这边的解决方案是:
本地存储目录(用户上传的图片等资源):存储至腾讯云COS,使用此方案需要部署 cos-ftp-server ,其 Dockerfile 如下:
1
2
3
4
5
6
7FROM python:2.7
COPY ./cos-ftp-server-V5-master.zip /
RUN mkdir /tmp/cos && pip install -i https://mirrors.tencent.com/pypi/simple/ cos-python-sdk-v5 pyftpdlib psutil && unzip cos-ftp-server-V5-master.zip && rm cos-ftp-server-V5-master.zip && cd cos-ftp-server-V5-master && python setup.py install
CMD cd cos-ftp-server-V5-master && python ftp_server.py需要注意的是,示例的 Dockerfile 中没有修改 cos-ftp-server 的配置文件
vsftpd.conf
,推荐在 k8s 中使用 configmap 替换此文件。缓存目录:使用腾讯云文件存储,其支持使用 NFS 协议挂载到容器。假设网站的根目录为
/www/src
,我们将在 yaml 中挂载 NFS 到/nfs/src
。pv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15apiVersion: v1
kind: PersistentVolume
metadata:
name: {{ .Release.Name }}
labels:
pv: {{ .Release.Name }}-pv
spec:
capacity:
storage: 150Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
nfs:
path: /
server: {{ .Values.nfs }}pvc
1
2
3
4
5
6
7
8
9
10
11
12
13
14kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: {{ .Release.Name }}
spec:
accessModes:
- ReadWriteMany
storageClassName: ""
resources:
requests:
storage: 150Gi
selector:
matchLabels:
pv: {{ .Release.Name }}-pvDeployment
1
2
3
4
5
6
7
8
9
10
11...
volumeMounts:
- mountPath: "/nfs"
name: {{ .Release.Name }}
...
volumes:
- name: {{ .Release.Name }}
persistentVolumeClaim:
claimName: {{ .Release.Name }}
readOnly: false
...
在 Dockerfile 中,软链接缓存目录(缓存目录众多,如下仅为示例)。
1
2
3
4
5...
ADD ./www/ /www/src
RUN ln -s /nfs/src/data /www/src/
...
3. 整体架构参考
graph TB client("用户") cos(腾讯云COS) mysql(MySQL) nfs(NFS) clb(腾讯云CLB) subgraph k8s subgraph bbs_pod nginx(Nginx) php(PHP) cos-ftp(cos-ftp) end subgraph redis_pod redis(Redis) end end client --> clb --> nginx --> php --> cos-ftp --> cos php --> redis php ---> mysql nginx --> nfs php ---> nfs
4. 交付部署流程优化
使用了 Docker k8s 部署 Discuz! X 后,可以借助腾讯蓝鲸蓝盾优化整个部署流程,实现全流程零运维。
graph TB a1(Git 触发流水线构建) --> a2(构建 Docker 镜像) --> a3(通过 helm 滚动更新测试环境) --> a4(通过 helm 滚动更新生产环境)