最近工作中接到一个将 PHP 老项目迁移至腾讯云 K8S 集群中的需求,因之前是部署在一台宝塔服务器中无法做到可控,遂将项目迁移到现有腾讯云 K8S 集群中与 Go 项目一同运行。

该项目使用 ThinkPHP 6 框架进行搭建开发,需要的运行环境为 Nginx + PHP-FPM ,遂考虑使用 CentOS 7 搭建一套 LNMP 环境来部署的方案。

首先将运行的基镜像搭建起来,从 DockerHub 中拉取版本为 7.9.2009 的 CentOS 镜像:

docker pull centos:7.9.2009

拉取完直接运行,设置 80 端口映射到外部,并挂载项目目录

docker run -it --name phpweb -p 80:80 -v /data/phpweb:/home/wwwroot --privileged -u root --entrypoint /bin/bash centos:7.9.2009

进入到容器内部,首先安装 LNMP 环境,这里使用 LNMP一键安装包 中的一键安装脚本去进行搭建(已省去 yum 源更新并安装相应工具的操作)

cd ~
wget http://soft.vpser.net/lnmp/lnmp1.9.tar.gz -cO lnmp1.9.tar.gz && tar zxf lnmp1.9.tar.gz && cd lnmp1.9 && ./install.sh lnmp

接着直接选择不安装 MySQL,PHP 版本及不安装内存优化,等待直接安装完毕后配置站点 vhost (伪静态)

lnmp vhost add

按提示的步骤进行操作,配置站点域名、执行目录、日志目录、ThinkPHP 兼容、PATHINFO、域名证书(上 K8S 可不配)等;
站点搭建的准备工作做好了之后,接着将容器打包为镜像并推送到仓库中(如果是私有仓库还需使用登录授权命令):

docker commit -a "fantasticbin" -m "项目运行环境基镜像" ContainerID phpweb:v1
docker tag ImageId fantasticbin/job:phpweb
docker push fantasticbin/job:phpweb

到这一步基镜像就搭建好了。
然后需要在项目中写入 Dockerfile 进行构建准备工作

FROM fantasticbin/job:phpweb

ENV TZ Asia/Shanghai

COPY ./ /home/wwwroot/php-project

RUN ln -fs /usr/share/zoneinfo/${TZ} /etc/localtime \
    && echo ${TZ} > /etc/timezone \
    && chown -R www:www /home/wwwroot/php-project

CMD ["lnmp start"]

因公司环境构建流水线使用的腾讯云 CODING,也是基于 Jenkins 进行部署的,所以可将部署脚本通过 Jenkinsfile 进行配置:

pipeline {
  agent any
  stages {
    stage('代码检出') {
      steps {
        checkout([$class: 'GitSCM',
        branches: [[name: GIT_BUILD_REF]],
        userRemoteConfigs: [[
          url: GIT_REPO_URL,
          credentialsId: CREDENTIALS_ID
        ]]])
      }
    }

    stage('写入配置') {
      steps {
        writeFile(file: '.env', text: '''APP_DEBUG = true

[APP]
DEFAULT_TIMEZONE = Asia/Shanghai

[DATABASE]
HOSTNAME = 172.17.0.2
DATABASE = project
USERNAME = root
PASSWORD = xxxxxx
HOSTPORT = 3306
DEBUG = true

[LANG]
default_lang = zh-cn

      }
    }

    stage('拉取镜像') {
      steps {
        script {
          docker.withRegistry("https://${DOCKER_REGISTRY_HOSTNAME}", "${DOCKER_REGISTRY_CREDENTIAL}") {
            docker.image("fantasticbin/job:phpweb").pull()
          }
        }

      }
    }

    stage('构建镜像') {
      steps {
        sh "docker build -t ${DOCKER_REPOSITORY_NAME}:${DOCKER_IMAGE_NAME} ."
      }
    }

    stage('推送镜像') {
      steps {
        script {
          docker.withRegistry("https://${DOCKER_REGISTRY_HOSTNAME}", "${DOCKER_REGISTRY_CREDENTIAL}") {
            docker.image("${DOCKER_REPOSITORY_NAME}:${DOCKER_IMAGE_NAME}").push()
          }
        }

      }
    }

  }
  environment {
    DOCKER_REGISTRY_HOSTNAME = "${TCR_REGISTRY_HOSTNAME}"
    DOCKER_REGISTRY_CREDENTIAL = "${TCR_REGISTRY_CREDENTIAL}"
    DOCKER_REPOSITORY_NAME = "${TCR_NAMESPACE_NAME}/${TCR_REPOSITORY_NAME}"
    DOCKER_IMAGE_NAME = "${TCR_IMAGE_NAME}"
    DATE = sh(returnStdout: true, script: 'date +%y.%m.%d-%H.%M.%S').trim()
  }
}

注意配置相应的环境变量,最后运行该构建计划成功之后,正式环境的镜像就会推送到指定的镜像仓库中。
最后一步则进入腾讯云 TKE 中配置 K8S 的集群工作负载(Deployment),使用刚刚推送的镜像进行部署运行。

需要注意的是,运行命令需要设置成:/bin/bash,运行参数分别设置为(必须设置成两项):-c、tail -F /dev/null (因 Pod 启动时需要监听 PID 为 1 的常驻进程,故用这种方式进行处理),生命周期启动后执行分别设置为(必须设置成三项):/bin/sh、-c、lnmp start

然后将 80 端口映射出来,同时指定好镜像访问凭证,以及配置好服务与路由 Service、Ingress ,将域名指向服务中,即可完成正式环境的搭建