1 基本介绍

CODING 是一个面向软件研发团队的研发协作管理平台,提供云原生开发环境、在线编码、代码托管、项目管理、测试管理、持续集成、制品库、持续部署、团队知识库等系列工具产品,帮助研发团队实践敏捷开发与 DevOps。

2 核心特性

本文仅讨论 CODING 提供的持续集成、制品库、持续部署功能。

使用 CODING 实现 CI/CD 自动化 - 图1

2.1 持续集成

2.1.1 构建计划

首先,创建您的项目,本文以“基础平台”为例。从项目进入“持续集成”菜单,选择“构建计划”,界面示例如下。
image.png
创建您的构建计划,根据实际情况选择 CODING 代码仓库或者关联外部的代码仓库(本文以腾讯云工蜂为例)。
image.png
进入下一步,你可以选择图形化编辑器或者文本编辑器完成 Jenkins 构建脚本的创建。

环境变量是一个很重要的功能,我们可以在这个基础上设置密码、Token,Profile 等逻辑信息。

image.png
笔者认为 CODING 应该在此处新增版本历史的功能,如果不小心误删这项构建计划,写了半天的 Jenkins 脚本就没了。目前的代替方案是在我们的 Git 目录添加名为 .coding 的目录,把内容保存到 Jenkinsfile 文件中,基于 Git 进行版本控制。
image.png
然后,回到配置界面的“基础信息”选项卡,修改 CODING 读取 Jenkinsfile 的位置。
image.png
接着,根据你的配合使用情况去调整触发规则(每次 commit 就触发一次并不是很好哦~)。
image.png
在“变量与缓存”设置相关环境参数和缓存目录。

有时候,我们更新依赖可能不生效,需要你手动在配置界面点击“重置缓存”再次拉取依赖。

image.png

2.1.2 自定义计划模板

CODING 提供了自定义构建计划,我们可以把之前调试好的配置保存为模板。建议把通用脚本、常用变量、缓存目录写在模板里面。
image.png
如果需要调整保存后的模板,可以从“团队设置中心”> “功能设置”>“持续集成”进去。
image.png

2.2 制品库

2.2.1 仓库管理

新建仓库(建议分别创建 Docker、Maven、npm)
image.png
为制品库设置代理(其实默认的代理就够用了)
image.png

2.2.2 构建制品

在仓库管理有个“操作指引”,按着官方的说明,分别配置制品的凭据、推送和拉取。
image.png

2.3 持续部署

2.3.1 部署到 K8s 集群

CODING 持续部署需要绑定目标集群,以腾讯云 EKS(弹性集群)为例。CODING 目前支持三种云账号类型:

  • 腾讯云 TKE:如果您是从腾讯云开发者平台入口注册登录,才会显示此类账号。
  • Kubernetes:支持 Kubeconfig 和 Service Account 两个常用凭据。
  • 腾讯云账号:即腾讯云 API 密钥。

在创建构建计划的环节我们选择了关联代码仓库,因此 CODING 对外部代码仓库实现部署只能通过 Kubernetes 授权访问凭据的方式完成(官方给出的答复)。
首先,Kubernetes 授权访问凭据需要我们在腾讯云的 EKS 目标集群设置 CODING 通过外网访问的白名单。
image.png
设置白名单后,复制界面生成的 Kubeconfig 内容到 CODING 的 “部署控制台” >“云账号”> “绑定云账号”。
image.png
绑定成功后,在构建计划的“持续部署”选项会出现绑定后的 K8s 选项。
image.png

如果有不清楚的地方,可以参考下官方的步骤。

2.3.2 主机部署

TODO

3 实战案例

3.1 Spring Boot 工程实战

3.1.1 关联 Git 代码仓库

以阿里的 Sentinel 为例,先关联好对应的仓库。
image.png
修改 Sentinel 的 pom.xml 文件,本文使用基于 Google 的 jib 插件打包 Docker 镜像,其他场景可以根据 Dockerfile 或者其他 Maven 插件实现同样的功能。

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <parent>
  7. <groupId>com.alibaba.csp</groupId>
  8. <artifactId>sentinel-parent</artifactId>
  9. <version>1.8.2</version>
  10. </parent>
  11. <artifactId>sentinel-dashboard</artifactId>
  12. <packaging>jar</packaging>
  13. <version>1.8.2</version>
  14. <properties>
  15. <!-- 此处省略一些内容,下列内容是新增的部分 -->
  16. <docker.username/>
  17. <docker.password/>
  18. <docker.image>shjrccr.ccs.tencentyun.com/xxx/sentinel</docker.image> <!-- 对应目标集群的镜像残酷,我们这里选择腾讯云的镜像仓库 -->
  19. <versions-maven-plugin.version>2.7</versions-maven-plugin.version> <!-- 增加这个插件实现动态版本打包 -->
  20. </properties>
  21. <build>
  22. <finalName>sentinel-dashboard</finalName>
  23. <plugins>
  24. <plugin>
  25. <groupId>org.codehaus.mojo</groupId>
  26. <artifactId>versions-maven-plugin</artifactId>
  27. <version>${versions-maven-plugin.version}</version>
  28. <configuration>
  29. <generateBackupPoms>false</generateBackupPoms>
  30. </configuration>
  31. </plugin>
  32. </plugins>
  33. </build>
  34. <profiles>
  35. <profile>
  36. <id>coding</id>
  37. <properties>
  38. <spring.profiles.active>prod</spring.profiles.active>
  39. </properties>
  40. <build>
  41. <plugins>
  42. <!-- 基于 Google 的 jib 插件打包镜像 -->
  43. <plugin>
  44. <groupId>com.google.cloud.tools</groupId>
  45. <artifactId>jib-maven-plugin</artifactId>
  46. <version>2.2.0</version>
  47. <configuration>
  48. <from>
  49. <image>openjdk:11-jre-slim</image>
  50. </from>
  51. <to>
  52. <image>${docker.image}</image>
  53. <auth>
  54. <username>${docker.username}</username>
  55. <password>${docker.password}</password>
  56. </auth>
  57. <tags>
  58. <tag>${project.version}</tag>
  59. </tags>
  60. </to>
  61. <container>
  62. <entrypoint>
  63. <shell>bash</shell>
  64. <option>-c</option>
  65. <arg>/entrypoint.sh</arg>
  66. </entrypoint>
  67. <ports>
  68. <port>8080</port>
  69. </ports>
  70. <environment>
  71. <TZ>Asia/Shanghai</TZ>
  72. <SPRING_OUTPUT_ANSI_ENABLED>ALWAYS
  73. </SPRING_OUTPUT_ANSI_ENABLED>
  74. <JAVA_SLEEP>1</JAVA_SLEEP>
  75. <JAVA_OPTS>-Xms256m -Xmx256m</JAVA_OPTS>
  76. </environment>
  77. <creationTime>USE_CURRENT_TIMESTAMP
  78. </creationTime>
  79. <mainClass>
  80. com.alibaba.csp.sentinel.dashboard.DashboardApplication
  81. </mainClass>
  82. </container>
  83. <extraDirectories>
  84. <paths>src/main/docker/jib</paths>
  85. <permissions>
  86. <permission>
  87. <file>/entrypoint.sh</file>
  88. <mode>755</mode>
  89. </permission>
  90. </permissions>
  91. </extraDirectories>
  92. <allowInsecureRegistries>true
  93. </allowInsecureRegistries>
  94. </configuration>
  95. </plugin>
  96. </plugins>
  97. </build>
  98. </profile>
  99. </profiles>
  100. </project>

可能有些同学注意到了,pom.xml 没有指定 Coding 的仓库地址。一般我们建议把外部环境配置放在 Maven 的 settings.xml 文件,这样做是为了减少代码的侵入。
本地开发时可以参考下面的配置。

  1. <settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 http://maven.apache.org/xsd/settings-1.2.0.xsd">
  4. <localRepository>本地仓库路径</localRepository>
  5. <pluginGroups>
  6. </pluginGroups>
  7. <proxies>
  8. </proxies>
  9. <servers>
  10. <!-- coding -->
  11. <server>
  12. <id>coding</id>
  13. <username>Coding 制品库用户名</username>
  14. <password>Coding 制品库密码</password>
  15. </server>
  16. </servers>
  17. <mirrors>
  18. </mirrors>
  19. <profiles>
  20. <profile>
  21. <id>coding</id>
  22. <properties>
  23. <!-- docker.username -->
  24. <docker.username>上传 Docker 镜像仓库的用户名</docker.username>
  25. <docker.password>上传 Docker 镜像仓库的密码</docker.password>
  26. <altReleaseDeploymentRepository>
  27. coding::default::https://xxx-maven.pkg.coding.net/repository/xxx/maven-releases/
  28. </altReleaseDeploymentRepository>
  29. <altSnapshotDeploymentRepository>
  30. coding::default::https://xxx-maven.pkg.coding.net/repository/xxx/maven-snapshots/
  31. </altSnapshotDeploymentRepository>
  32. </properties>
  33. <repositories>
  34. <repository>
  35. <id>xxx-maven-releases</id>
  36. <name>xxx-maven-releases</name>
  37. <url>https://xxx-maven.pkg.coding.net/repository/xxx/maven-releases/</url>
  38. <releases>
  39. <enabled>true</enabled>
  40. </releases>
  41. <snapshots>
  42. <enabled>false</enabled>
  43. </snapshots>
  44. </repository>
  45. <repository>
  46. <id>xxx-maven-snapshots</id>
  47. <name>xxx-maven-snapshots</name>
  48. <url>https://xxx-maven.pkg.coding.net/repository/xxx/maven-snapshots/</url>
  49. <releases>
  50. <enabled>false</enabled>
  51. </releases>
  52. <snapshots>
  53. <enabled>true</enabled>
  54. </snapshots>
  55. </repository>
  56. </repositories>
  57. <pluginRepositories>
  58. <pluginRepository>
  59. <id>xxx-maven-releases</id>
  60. <name>xxx-maven-releases</name>
  61. <url>https://xxx-maven.pkg.coding.net/repository/xxx/maven-releases/</url>
  62. <releases>
  63. <enabled>true</enabled>
  64. </releases>
  65. <snapshots>
  66. <enabled>false</enabled>
  67. </snapshots>
  68. </pluginRepository>
  69. <pluginRepository>
  70. <id>xxx-maven-snapshots</id>
  71. <name>xxx-maven-snapshots</name>
  72. <url>https://xxx-maven.pkg.coding.net/repository/xxx/maven-snapshots/</url>
  73. <releases>
  74. <enabled>false</enabled>
  75. </releases>
  76. <snapshots>
  77. <enabled>true</enabled>
  78. </snapshots>
  79. </pluginRepository>
  80. </pluginRepositories>
  81. </profile>
  82. </profiles>
  83. <activeProfiles>
  84. <activeProfile>coding</activeProfile>
  85. </activeProfiles>

3.1.2 初始化 Maven 配置文件

在 Coding 构建时需要手动指定 settings.xml 文件,所以,我们可以把文件放在 .coding 目录下。文件内容中有 ${env.xxx} 的变量值,通过 Coding 的变量传递。

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <settings>
  3. <servers>
  4. <server>
  5. <id>coding</id>
  6. <username>${env.MAVEN_USERNAME}</username>
  7. <password>${env.MAVEN_PASSWORD}</password>
  8. </server>
  9. </servers>
  10. <profiles>
  11. <profile>
  12. <id>coding</id>
  13. <properties>
  14. <docker.username>${env.DOCKER_USERNAME}</docker.username>
  15. <docker.password>${env.DOCKER_PASSWORD}</docker.password>
  16. <docker.image>${env.DOCKER_IMAGE}</docker.image>
  17. </properties>
  18. <repositories>
  19. <repository>
  20. <id>coding</id>
  21. <url>${env.MAVEN_REPO_URL}</url>
  22. <releases>
  23. <enabled>true</enabled>
  24. </releases>
  25. <snapshots>
  26. <enabled>true</enabled>
  27. </snapshots>
  28. </repository>
  29. </repositories>
  30. <pluginRepositories>
  31. <pluginRepository>
  32. <id>coding</id>
  33. <url>${env.MAVEN_REPO_URL}</url>
  34. <releases>
  35. <enabled>true</enabled>
  36. </releases>
  37. <snapshots>
  38. <enabled>false</enabled>
  39. </snapshots>
  40. </pluginRepository>
  41. </pluginRepositories>
  42. </profile>
  43. </profiles>
  44. <activeProfiles>
  45. <activeProfile>coding</activeProfile>
  46. </activeProfiles>
  47. </settings>

3.1.2 调整 Jenkinsfile 构建脚本

进入 Coding 图形化编辑器,按“开始 -> 检出 -> 编译 -> 推送到 Maven 制品库 > 推送到 Docker 制品库”依次配置。
image.png
由于配置步骤比较多,在这里直接提供一份调试好的内容,复制下面的内容到 Coding 的“文本编辑器”中,然后切换为 “图形化编辑器”,Coding 会生成相应的可视化界面,按需调整即可。

  1. pipeline {
  2. agent any
  3. environment {
  4. CODING_MAVEN_REPO_NAME = "maven"
  5. CODING_MAVEN_REPO_ID = "${CCI_CURRENT_TEAM}-${PROJECT_NAME}-${CODING_MAVEN_REPO_NAME}"
  6. CODING_MAVEN_REPO_URL = "${CCI_CURRENT_WEB_PROTOCOL}://${CCI_CURRENT_TEAM}-maven.pkg.${CCI_CURRENT_DOMAIN}/repository/${PROJECT_NAME}/${CODING_MAVEN_REPO_NAME}/"
  7. CODING_DOCKER_REPO_NAME = "docker"
  8. CODING_DOCKER_REPO_HOST = "${CCI_CURRENT_TEAM}-docker.pkg.${CCI_CURRENT_DOMAIN}"
  9. CODING_DOCKER_REPO_URL = "${CODING_DOCKER_REPO_HOST}/${PROJECT_NAME}/${CODING_DOCKER_REPO_NAME}/${DEPOT_NAME}"
  10. TCR_NAMESPACE_NAME = "test"
  11. TCR_DOCKER_REPO_URL = "shjrccr.ccs.tencentyun.com/${TCR_NAMESPACE_NAME}/${DEPOT_NAME}"
  12. }
  13. stages {
  14. stage('检出') {
  15. steps {
  16. checkout([$class: 'GitSCM',
  17. branches: [[name: GIT_BUILD_REF]],
  18. userRemoteConfigs: [[
  19. url: GIT_REPO_URL,
  20. credentialsId: CREDENTIALS_ID
  21. ]]])
  22. }
  23. }
  24. stage('编译') {
  25. steps {
  26. script {
  27. if (env.TAG_NAME ==~ /.*/ ) {
  28. CODING_ARTIFACT_VERSION = "${env.TAG_NAME}"
  29. } else if (env.MR_SOURCE_BRANCH ==~ /.*/ ) {
  30. CODING_ARTIFACT_VERSION = "mr-${env.MR_RESOURCE_ID}-${env.GIT_COMMIT_SHORT}"
  31. } else {
  32. CODING_ARTIFACT_VERSION = "${env.BRANCH_NAME.replace('/', '-')}-${env.GIT_COMMIT_SHORT}"
  33. }
  34. }
  35. withCredentials([
  36. usernamePassword(
  37. credentialsId: env.CODING_ARTIFACTS_CREDENTIALS_ID,
  38. usernameVariable: 'CODING_ARTIFACTS_USERNAME',
  39. passwordVariable: 'CODING_ARTIFACTS_PASSWORD'
  40. )
  41. ]) {
  42. withEnv([
  43. "MAVEN_REPO_URL=${CODING_MAVEN_REPO_URL}",
  44. "MAVEN_USERNAME=${CODING_ARTIFACTS_USERNAME}",
  45. "MAVEN_PASSWORD=${CODING_ARTIFACTS_PASSWORD}",
  46. "CODING_ARTIFACT_VERSION=${CODING_ARTIFACT_VERSION}"
  47. ]) {
  48. sh 'mvn -Pcoding versions:set -DnewVersion=${CODING_ARTIFACT_VERSION} clean package -DskipTests -s ./.coding/settings.xml'
  49. }
  50. }
  51. }
  52. }
  53. stage('推送到 Maven 制品库') {
  54. steps {
  55. withCredentials([
  56. usernamePassword(
  57. credentialsId: env.CODING_ARTIFACTS_CREDENTIALS_ID,
  58. usernameVariable: 'CODING_ARTIFACTS_USERNAME',
  59. passwordVariable: 'CODING_ARTIFACTS_PASSWORD'
  60. )
  61. ]) {
  62. withEnv([
  63. "MAVEN_REPO_URL=${CODING_MAVEN_REPO_URL}",
  64. "MAVEN_USERNAME=${CODING_ARTIFACTS_USERNAME}",
  65. "MAVEN_PASSWORD=${CODING_ARTIFACTS_PASSWORD}"
  66. ]) {
  67. sh 'mvn -Pcoding deploy -DskipTests -s ./.coding/settings.xml'
  68. }
  69. }
  70. }
  71. }
  72. stage('推送到 Docker 制品库') {
  73. steps {
  74. withEnv([
  75. "DOCKER_USERNAME=${DOCKER_USERNAME}",
  76. "DOCKER_PASSWORD=${DOCKER_PASSWORD}",
  77. "DOCKER_IMAGE=${TCR_DOCKER_REPO_URL}:${CODING_ARTIFACT_VERSION}"
  78. ]) {
  79. sh 'mvn -Pcoding jib:build -Djib.disableUpdateChecks=true -DskipTests -s ./.coding/settings.xml'
  80. }
  81. }
  82. }
  83. stage('部署到 K8s 集群') {
  84. steps {
  85. withEnv(["DOCKER_IMAGE=${TCR_DOCKER_REPO_URL}:${CODING_ARTIFACT_VERSION}"]) {
  86. cdDeploy(deployType: 'PATCH_IMAGE', application: '${CCI_CURRENT_TEAM}', pipelineName: '${PROJECT_NAME}-${CCI_JOB_NAME}-2222222', image: '${DOCKER_IMAGE}', cloudAccountName: 'guoyuanlu-k8s-test', namespace: 'test-college', manifestType: 'Deployment', manifestName: 'sentinel-dashboard', containerName: 'sentinel-dashboard', credentialId: 'xxxxxxxxxxxxxxxxxxxxxxx', personalAccessToken: '${CD_PERSONAL_ACCESS_TOKEN}')
  87. }
  88. }
  89. }
  90. }
  91. }

在“部署到 K8s 集群”的步骤中,您需要在界面手动选择集群,生成新的 Token,否则部署会报错。
image.png
选择对应的 Deployment 后保存,切回“文本编辑器”查看 credentialId 的值是否发生变化。image.png
配置成功的效果图如下。
image.png

3.2 Vue.js 工程实战

3.2.1 关联 Git 代码仓库

以开源的若依项目(Vue)为例,先关联好对应的仓库。
image.png
在代码目录下分别创建以下目录:

  • .coding/Jenkinsfile
  • .coding/nginx.conf
  • .npmrc
  • Dockerfile

如下图所示。
image.png

3.2.2 初始化 .npmrc 文件

将 npm 的私服指向 CODING 制品库。

  1. registry=https://xxx-npm.pkg.coding.net/xxx/npm/
  2. always-auth=true
  3. //xxx-npm.pkg.coding.net/xxx/npm/:username=${CODING_ARTIFACTS_USERNAME}
  4. //xxx-npm.pkg.coding.net/xxx/npm/:_password=${CODING_ARTIFACTS_PASSWORD}
  5. //xxx-npm.pkg.coding.net/xxx/npm/:email=xxx@gmail.com

3.2.3 初始化 nginx.conf 文件

前端依赖 Nginx 的镜像进行部署,所以,我们要把 nginx 的配置也加上。

  1. user nginx;
  2. worker_processes 1;
  3. error_log logs/error.log warn;
  4. pid logs/nginx.pid;
  5. events {
  6. worker_connections 1024;
  7. }
  8. http {
  9. include /etc/nginx/mime.types;
  10. default_type application/octet-stream;
  11. log_format main '$remote_addr - $remote_user [$time_local] "$request" '
  12. '$status $body_bytes_sent "$http_referer" '
  13. '"$http_user_agent" "$http_x_forwarded_for"';
  14. access_log logs/access.log main;
  15. sendfile on;
  16. keepalive_timeout 65;
  17. client_max_body_size 500m;
  18. server {
  19. listen 80;
  20. server_name localhost;
  21. charset utf-8;
  22. gzip_static on;
  23. gzip_vary on;
  24. gzip_min_length 1k;
  25. gzip_comp_level 9;
  26. gzip_types text/css text/javascript application/javascript application/x-javascript application/xml;
  27. gzip_disable "MSIE [1-6]\.";
  28. error_page 500 502 503 504 /50x.html;
  29. location = /50x.html {
  30. root /usr/share/nginx/html;
  31. }
  32. location / {
  33. root /usr/share/nginx/html;
  34. index index.html index.htm;
  35. proxy_set_header X-Real-IP $remote_addr;
  36. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  37. }
  38. location ^~ /api/ {
  39. proxy_pass http://xxx-admin-server:8070/;
  40. proxy_set_header X-Real-IP $remote_addr;
  41. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  42. }
  43. }
  44. }

3.2.4 调整 Dockerfile 打包脚本

  1. FROM nginx:1.15.2-alpine
  2. LABEL maintainer="梦想歌"
  3. COPY dist/ /usr/share/nginx/html
  4. COPY .coding/nginx.conf /etc/nginx/conf.d/default.conf
  5. EXPOSE 80

3.2.5 调整 Jenkinsfile 构建脚本

  1. pipeline {
  2. agent any
  3. environment {
  4. CODING_DOCKER_REPO_NAME = "docker"
  5. CODING_DOCKER_REPO_HOST = "${CCI_CURRENT_TEAM}-docker.pkg.${CCI_CURRENT_DOMAIN}"
  6. CODING_DOCKER_REPO_URL = "${CODING_DOCKER_REPO_HOST}/${PROJECT_NAME}/${CODING_DOCKER_REPO_NAME}/${DEPOT_NAME}"
  7. TCR_NAMESPACE_NAME = "xxx"
  8. TCR_DOCKER_REPO_URL = "shjrccr.ccs.tencentyun.com/${TCR_NAMESPACE_NAME}/${DEPOT_NAME}"
  9. }
  10. stages {
  11. stage('检出') {
  12. steps {
  13. checkout([$class: 'GitSCM',
  14. branches: [[name: GIT_BUILD_REF]],
  15. userRemoteConfigs: [[
  16. url: GIT_REPO_URL,
  17. credentialsId: CREDENTIALS_ID
  18. ]]])
  19. }
  20. }
  21. stage('编译') {
  22. steps {
  23. script {
  24. if (env.TAG_NAME ==~ /.*/ ) {
  25. CODING_ARTIFACT_VERSION = "${env.TAG_NAME}"
  26. } else if (env.MR_SOURCE_BRANCH ==~ /.*/ ) {
  27. CODING_ARTIFACT_VERSION = "mr-${env.MR_RESOURCE_ID}-${env.GIT_COMMIT_SHORT}"
  28. } else {
  29. CODING_ARTIFACT_VERSION = "${env.BRANCH_NAME.replace('/', '-')}-${env.GIT_COMMIT_SHORT}"
  30. }
  31. }
  32. sh 'rm -rf /usr/lib/node_modules/npm/'
  33. dir ('/root/.cache/downloads') {
  34. sh 'wget -nc "https://coding-public-generic.pkg.coding.net/public/downloads/node-linux-x64.tar.xz?version=v16.13.0" -O node-v16.13.0-linux-x64.tar.xz | true'
  35. sh 'tar -xf node-v16.13.0-linux-x64.tar.xz -C /usr --strip-components 1'
  36. }
  37. withCredentials([
  38. usernamePassword(
  39. credentialsId: env.CODING_ARTIFACTS_CREDENTIALS_ID,
  40. usernameVariable: 'CODING_ARTIFACTS_USERNAME',
  41. passwordVariable: 'CODING_ARTIFACTS_PASSWORD'
  42. )]) {
  43. script {
  44. sh '''
  45. echo "CODING_ARTIFACTS_USERNAME=${CODING_ARTIFACTS_USERNAME}" >> $CI_ENV_FILE
  46. echo "CODING_ARTIFACTS_PASSWORD=${CODING_ARTIFACTS_PASSWORD}" >> $CI_ENV_FILE
  47. '''
  48. readProperties(file: env.CI_ENV_FILE).each {
  49. key, value -> env[key] = value
  50. }
  51. }
  52. sh 'npm install'
  53. sh 'npm run build:prod'
  54. }
  55. }
  56. }
  57. stage('推送到 Docker 制品库') {
  58. steps {
  59. withEnv([
  60. "DOCKER_USERNAME=${DOCKER_USERNAME}",
  61. "DOCKER_PASSWORD=${DOCKER_PASSWORD}",
  62. "DOCKER_IMAGE=${TCR_DOCKER_REPO_URL}:${CODING_ARTIFACT_VERSION}"
  63. ]) {
  64. sh 'docker login --username=${DOCKER_USERNAME} --password=${DOCKER_PASSWORD} shjrccr.ccs.tencentyun.com'
  65. sh 'docker build -t ${DOCKER_IMAGE} .'
  66. sh 'docker tag ${DOCKER_IMAGE} ${DOCKER_IMAGE}'
  67. sh 'docker push ${DOCKER_IMAGE}'
  68. }
  69. }
  70. }
  71. stage('部署到 K8s 集群') {
  72. steps {
  73. withEnv(["DOCKER_IMAGE=${TCR_DOCKER_REPO_URL}:${CODING_ARTIFACT_VERSION}"]) {
  74. cdDeploy(deployType: 'PATCH_IMAGE', application: '${CCI_CURRENT_TEAM}', pipelineName: '${PROJECT_NAME}-${CCI_JOB_NAME}-202222222', image: '${DOCKER_IMAGE}', cloudAccountName: 'xxx-k8s-test', namespace: 'test', manifestType: 'Deployment', manifestName: 'xxx-client', containerName: 'xxx-client', credentialId: 'aaaaaaaaaaaaaaaaaaaaaaa', personalAccessToken: '${CD_PERSONAL_ACCESS_TOKEN}')
  75. }
  76. }
  77. }
  78. }
  79. }

构建成功的效果图如下。
image.png