持续集成的自动化部署

功能介绍

持续集成执行了代码规范检查、单元测试、打包等多个步骤之后,最后一步是自动化部署。常见的部署触发规则如下:

  • 推送到 develop/master 分支:自动部署到开发/测试服务器;
  • 推送新标签(tag):使用标签作为版本号,自动打包,自动/手动部署到生产服务器;

常见的部署方式有:

  • K8s 集群:CI 生成 Docker 镜像,上传到 Docker 仓库(CODING 制品库),kubectl 操作服务器拉取镜像;
  • Linux Docker 服务器:CI 生成 Docker 镜像,上传到 Docker 仓库(CODING 制品库),SSH 操作服务器拉取镜像;
  • Linux Web 服务器:CI 生成压缩包,SCP 上传到服务器,SSH 解压;
  • 虚拟主机(PHP 空间):CI 生成压缩包,FTP 上传到服务器,HTTP 解压;

部署到 K8s 集群

  1. CI 构建 Docker 镜像并上传到仓库(CODING 制品库),参考文档:《上传 Docker 类型制品》
  2. 创建一个 K8s 集群,获得 .kube/config,录入 CODING,实现远程管理,参考文档:《在持续集成中使用凭据》
  3. 使用 kubectl 在 K8s 中创建密钥:Docker 仓库的用户名密码;
  4. kubectl 修改 K8s deployment:指定 Docker 镜像链接和密钥;
node {
    checkout([
        $class: 'GitSCM',
        branches: [[name: env.GIT_BUILD_REF]],
        userRemoteConfigs: [[url: env.GIT_REPO_URL, credentialsId: env.CREDENTIALS_ID]]
    ])
    stage('构建 Docker 并上传到制品库') {
        if(GIT_LOCAL_BRANCH != 'master') {
            echo '此分支无需构建 Docker'
            return
        }
        dockerServer = 'codes-farm-docker.pkg.coding.net'
        imageName = "${dockerServer}/laravel-demo/laravel-docker/laravel-demo:latest"
        docker.build(imageName)
        docker.withRegistry("https://${dockerServer}", CODING_ARTIFACTS_CREDENTIALS_ID) {
            docker.image(imageName).push()
        }
    }
    stage('部署到 K8s 集群') {
        dockerUser = ""
        dockerPassword = ""
        withCredentials([usernamePassword(credentialsId: env.CODING_ARTIFACTS_CREDENTIALS_ID, usernameVariable: 'DOCKER_USER', passwordVariable: 'DOCKER_PASSWORD')]) {
            dockerUser = DOCKER_USER
            dockerPassword = DOCKER_PASSWORD
        }
        withKubeConfig([credentialsId: 'f67bacc5-ae02-4fc4-a814-ed2df4da9ab9', serverUrl: K8S_SERVER_URL]) {
            sh(script: "kubectl create secret docker-registry coding --docker-server=${dockerServer} --docker-username=${dockerUser} --docker-password=${dockerPassword} --docker-email=sinkcup@qq.com", returnStatus: true)
            sh "kubectl patch deployment web --patch '{\"spec\": {\"template\": {\"spec\": {\"containers\": [{\"name\": \"web\", \"image\": \"${imageName}\"}], \"imagePullSecrets\": [{\"name\": \"coding\"}]}}}}'"
        }
    }
}

部署到 Linux Docker 服务器

  1. 创建一个私钥放在 CODING,把公钥放在服务器的 .ssh/authorized_keys,实现 SSH 信任,参考文档:《在持续集成中使用凭据》
  2. CI 上传 Docker 镜像到仓库(CODING 制品库),参考文档:《上传 Docker 类型制品》
  3. CI 执行 SSH 登录服务器,拉取 Docker 镜像;
def remote = [:]
remote.name = 'web-server'
remote.allowAnyHosts = true
remote.host = 'example.com'
remote.user = 'root'

dockerUser = ""
dockerPassword = ""

node {
    checkout([
        $class: 'GitSCM',
        branches: [[name: env.GIT_BUILD_REF]],
        userRemoteConfigs: [[url: env.GIT_REPO_URL, credentialsId: env.CREDENTIALS_ID]]
    ])

    stage('部署') {
        echo '开始部署……'
        // 检测分支,只部署 master
        if(GIT_LOCAL_BRANCH != 'master') {
            echo 'do noting.'
            return
        }

        imageName = "myteam-docker.pkg.coding.net/my-project/my-repo/my-app:latest"
        docker.build(imageName)
        // 推送 Docker 镜像到仓库(CODING 制品库)
        docker.withRegistry("https://myteam-docker.pkg.coding.net", CODING_ARTIFACTS_CREDENTIALS_ID) {
            docker.image(imageName).push()
        }

        // 获取内置的制品库凭证
        withCredentials([usernamePassword(credentialsId: env.CODING_ARTIFACTS_CREDENTIALS_ID, usernameVariable: 'DOCKER_USER', passwordVariable: 'DOCKER_PASSWORD')]) {
            dockerUser = DOCKER_USER
            dockerPassword = DOCKER_PASSWORD
        }
        // 需要先创建一对密钥,把私钥放在 CODING 凭据管理,把公钥放在服务器的 `.ssh/authorized_keys`,实现 SSH 免密码登录
        withCredentials([sshUserPrivateKey(credentialsId: "0f3236ab-716b-4c53-acd7-a37eb832a823", keyFileVariable: 'id_rsa')]) {
            remote.identityFile = id_rsa

            // SSH 连接到远端服务器,拉取 Docker 镜像
            sshCommand remote: remote, command: "docker login -u ${dockerUser} -p ${dockerPassword} $DOCKER_SERVER"
            sshCommand remote: remote, command: "docker pull ${imageName}"
            sshCommand remote: remote, command: "docker stop web | true"
            sshCommand remote: remote, command: "docker rm web | true"
            sshCommand remote: remote, command: "docker run --name web -d ${imageName}"
        }
    }
}

部署到 Linux Web 服务器

  1. 创建一个私钥放在 CODING,把公钥放在服务器的 .ssh/authorized_keys,实现 SSH 信任,参考文档:《在持续集成中使用凭据》
  2. CI 生成压缩包;
  3. CI SSH 上传压缩包到服务器,解压缩;
pipeline {
  agent any
  stages {
    stage('检出') {
      steps {
        checkout(
          [$class: 'GitSCM', branches: [[name: env.GIT_BUILD_REF]],
          userRemoteConfigs: [[url: env.GIT_REPO_URL, credentialsId: env.CREDENTIALS_ID]]]
        )
      }
    }
    stage('构建') {
      steps {
        echo '构建中...'
        sh 'apt-get install -y python3-pip'
        sh 'pip3 install mkdocs'
        sh 'mkdocs build --clean'
        // 打包成压缩包
        sh 'tar -zcf tmp.tar.gz apache2/ site/'
        echo '构建完成.'
      }
    }
    stage('部署') {
      steps {
        echo '部署中...'
        script {
          def remote = [:]
          remote.name = 'web-server'
          remote.allowAnyHosts = true
          remote.host = '106.54.86.239'
          remote.user = 'ubuntu'
          // 需要先创建一对 SSH 密钥,把私钥放在 CODING 凭据管理,把公钥放在服务器的 `.ssh/authorized_keys`,实现免密码登录
          withCredentials([sshUserPrivateKey(credentialsId: "c4af855d-402a-4f38-9c83-f6226ae3441c", keyFileVariable: 'id_rsa')]) {
            remote.identityFile = id_rsa

            // SSH 上传文件到远端服务器
            sshPut remote: remote, from: 'tmp.tar.gz', into: '/tmp/'
            // 解压缩
            sshCommand remote: remote, command: "tar -zxf /tmp/tmp.tar.gz -C /tmp/"
            sshCommand remote: remote, sudo: true, command: "mkdir -p /var/www/china-speed"
            sshCommand remote: remote, sudo: true, command: "cp -R /tmp/site/* /var/www/china-speed/"
            sshCommand remote: remote, sudo: true, command: "cp -R /tmp/apache2/ /etc/"
            // 重启 apache2
            sshCommand remote: remote, sudo: true, command: "a2ensite example.com"
            sshCommand remote: remote, sudo: true, command: "a2enmod headers rewrite ssl"
            sshCommand remote: remote, sudo: true, command: "systemctl reload apache2"
          }
        }

        echo '部署完成'
      }
    }
  }
}
上一篇上传 Composer 类型制品
文档是否对您有用?
感谢反馈有用
感谢反馈没用