利用Coding.net完成hugo的自动发布和部署

2020-11-04 • 预计阅读时间 4 分钟

CI/CD

最近由于gitea升级导致的悲剧。决定把代码迁移到Coding上。上次使用还是在腾讯收购之前……发现还是有挺大的变化的,目前和github的区别主要是强调DevOps和项目全生命周期的管理。不过对于我这样的免费用户更看中的是提供的一些如无限的仓库,免费的Build服务器。虽然有一点限制,不过对于个人来说足够了。

  • 最多三个并发
  • 每月1000分钟的编译时间
  • 单次构建不能超过30分钟

编译的服务器配置还是可以的2 核 / 4GB / 100GB 磁盘空间 / Ubuntu

Coding的CI是基于Jenkinsfile的持续集成方案。这个还是不错的,想想之前已经用过gitlabdrone的方案。每家的时候都有点差别、不过总的来说还是Jenkins的方案更通用一点。

方案

通过Coding托管blog的代码,在每次提交以后触发自动CI流程。这个时候通过Docker获取较Hugo的编译镜像。然后挂在源码。完成编译。将编译好的内容打包,通过codingArtifactsGeneric上传到制品库中。然后利用ssh将发布物上传到远程的服务器,清空旧文件。并解压。然后重启docker.

其中在部署的同时还会通过首页 | Server酱给微信发个通知……

其中远程登录服务器使用的是ssh私钥的形式。这个需要将ssh的登录私钥上传到coding上,并获得一个credentialsId。通过环境变量传给Jenkinsfile

私钥的格式是需要注意的,如果使用较新的系统,由于OpenSSH的版本大于7.8会导致Coding无法识别。区别的办法是通过查看私钥第一行的内容,如果是-----BEGIN OPENSSH PRIVATE KEY-----则需要修改格式。将私钥转换成经典格式……

方法1:

ssh-keygen -p -f file -m pem -P passphrase -N passphrase

方法2:

通过puttygen先导入私钥,然后在导出。这个时候一定要选Export OPENSSH key,另外一个是转换成新格式的……

通过以上两种方法转换后的私钥第一行为:-----BEGIN RSA PRIVATE KEY-----。Coding在上传私钥的时候也会校验,如果没有这行内容的话,会报私钥格式错误。

以下是完整的Jenkinsfile

pipeline {
  agent {
    docker {
      image 'monachus/hugo'
      reuseNode true
    }

  }
  stages {
    stage('检出(源码库)') {
      steps {
        checkout([$class: 'GitSCM', branches: [[name: 'main']],
        userRemoteConfigs: [[url: env.GIT_REPO_URL, credentialsId: env.CREDENTIALS_ID]]])
      }
    }
    stage('构建并推到成品库') {
      steps {
        sh 'git submodule update --init --recursive'
        sh 'hugo version'
        sh 'export HUGO_ENV=production'
        sh 'hugo --minify --gc'
        sh 'tar -czf latest.tar.gz -C ./public .'
        sh 'ls -al'
        codingArtifactsGeneric(files: 'latest.tar.gz', repoName: "${GENERIC_REPO_NAME}", version: "ver.${CI_BUILD_NUMBER}")
        sh 'echo 完成编译'
      }
    }
    stage('ssh 部署到 web 端') {
      parallel {
        stage('通知') {
          steps {
            sh 'curl "https://sc.ftqq.com/XXXXXXXXXXXX.send?text=blog编译成功@${CI_BUILD_NUMBER}&title=build"'
          }
        }
        stage('ssh 部署到 web 端') {
          steps {
            echo '部署中...'
            script {
              def remote = [:]
              remote.name = 'blog'
              remote.allowAnyHosts = true
              remote.host = "${env.REMOTE_HOST}"
              remote.user = "${env.REMOTE_USER_NAME}"
              remote.port = Integer.parseInt("${env.REMOTE_PORT}")
              withCredentials([sshUserPrivateKey(credentialsId: "${env.REMOTE_CERT}", keyFileVariable: 'id_rsa')]) {
                remote.identityFile = id_rsa
                sshCommand remote: remote, command: "rm -rf /eureka/docker/blog"
                sshPut remote: remote, from: 'latest.tar.gz', into: '/eureka/docker'
                sshCommand remote: remote,  sudo: false, command: "cd /eureka/docker && mkdir blog && tar -zxf latest.tar.gz -C blog && rm -rf latest.tar.gz"
                sshCommand remote: remote,  sudo: false, command: "docker restart blog"
              }
            }

            echo '部署完成'
          }
        }
      }
    }
  }
}

注意事项:

  • REMOTE_HOST,REMOTE_USER_NAME,REMOTE_PORT都是需要你自己定义环境变量的。
  • REMOTE_CERT为上传的私钥ID
  • 由于使用的是Docker来部署的blog,所以如果只是替换的话。有可能会出现404的情况。所以最终reboot解决所有……

上传到制品库的话,建议使用codingArtifactsGeneric来实现。curl的方案还是需要密码,所以不是太安全。

总结

通过以上的配置就可以实现自动发布了。不过具体写些什么好像还是个挺复杂的事情……坚持才是最重要的。今天刚好折腾了下公司项目的CI,CI/CD的最主要作用是减少人的参与,如果你折腾了半天,弄个半吊子的东西,那么跟没有也没什么区别了。行百里者半九十,古人说的还是挺有道理的。做就要做好……

devhugoblog

wentao

写点代码,解决点问题。

bash加载.env配置

Nginx搭配RTMP