Discuz! X 容器化改造指南

550 阅读3分钟

自2021年,我开始运维一个日均PV 10万+的 Discuz! X论坛站点。接手后陆续发现一些问题难以通过传统方法解决,遂决定对其进行容器化改造。

blog.bluice.xyz/2022-07-18_…

1. 为什么要对 Discuz! X 进行容器化改造

1.1. 原部署方案为单机部署

Discuz! X 论坛的默认部署方式是单机部署,自然会出现一些单机部署会发生的问题:

  1. 单点故障:如果这台机器出现任何问题,会导致整个论坛处于不可用状态。包括 Nginx、PHP 进程出现问题,机器关机、重启等。
  2. 扩容困难:遇到搞活动时期,扩容需重启(使用的虚拟机为腾讯云CVM,可动态修改虚拟机配置,但需要重启,重启时间为数分钟)。而且一旦容量预估失败,活动期间调整容量几乎不可能。

1.2. PHP环境部署复杂

  1. **扩展安装困难:**开发以来的很多扩展安装比较复杂,新增一个扩展往往要倒腾半天。例如 grpc 扩展,开发人员本地安装成功但我按照开发人员的方法无法安装成功;更让人崩溃的是在测试环境安装调试OK后再生产环境安装依然出现了问题。pcel 执行也有失败的概率。
  2. 扩展安装时间久:新增 PHP 扩展往往需要停服更新,往往安装方法既受限于网速,又受限于源码编译构建的速度。万一出现意料之外的情况需要增加停机时间。

1.3. 支持滚动升级

实现版本更新用户无感知

2. 各项关键问题的解决方案

2.1. PHP 环境安装使用 Docker 镜像

这边使用的基础镜像为:php:7.2-fpm,为 PHP 官方发布的镜像。该镜像也能非常方便的安装 PHP 扩展。该项目也依赖了 composer,在 PHP 镜像中编译添加 composer 比较困难,比较简单的方法是,使用 COPY 命令从 composer 镜像中复制 composer 的二进制文件。示例的 Dockerfile 如下:

FROM php:7.2-fpm

COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer

RUN apt update \
  && apt install -y libfreetype6-dev libjpeg62-turbo-dev libmagickwand-dev libpng-dev libwebp-dev libxpm-dev libz-dev libzstd-dev \ 
  && pecl install grpc \
  && pecl install protobuf \
  && pecl install redis \
  && docker-php-ext-enable grpc \
  && docker-php-ext-install pdo \
  && docker-php-ext-install pdo_mysql

2.2. NFS 解决 Discuz! X 负载均衡问题

Discuz! X 多机部署的一个问题就在于 Discuz! X 使用了本地缓存目录和本地存储目录。我这边的解决方案是:

  • 本地存储目录(用户上传的图片等资源):存储至腾讯云COS,使用此方案需要部署 cos-ftp-server ,其 Dockerfile 如下:

    FROM 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

      apiVersion: 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

        kind: PersistentVolumeClaim
        apiVersion: v1
        metadata:
          name: {{ .Release.Name }}
        spec:
          accessModes:
            - ReadWriteMany
          storageClassName: ""
          resources:
            requests:
              storage: 150Gi
          selector:
            matchLabels:
              pv: {{ .Release.Name }}-pv
        
      • Deployment

        ...
                volumeMounts:
                - mountPath: "/nfs"
                  name: {{ .Release.Name }}
        ...
              volumes:
                - name: {{ .Release.Name }}
                  persistentVolumeClaim:
                    claimName: {{ .Release.Name }}
                    readOnly: false
        ...
        

      在 Dockerfile 中,软链接缓存目录(缓存目录众多,如下仅为示例)。

      ...
      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 滚动更新生产环境)