CI/CD构建发布实战

1,685 阅读8分钟

背景

由于公司的项目A项目B这2个项目使用的Angular版本不同,所以公共组件库也分为了2个分支,一个给项目A一个给项目B使用,公共组件库每次发布之前除了要同步部分相同的代码之外,还需要切换分支,才能进行发布。

以下是项目A项目B版本、分支关系对照表

项目A项目B
Angular版本9.x11.x
gitlab发布分支0.4.x0.5.x

为了改变这一现状,决定将发布的工作交给jenkins去处理,即只要gitlab上有创建tag的操作,则触发Webhooks, 剩下的事情由Jenkins来实现代码获取安装项目代码依赖执行编译并发布

准备工作

目前我的环境是一台宿主机服务器,上面有一个docker服务,其中jenkins服务是作为容器跑在docker上,所以,为了不影响现有的构建任务,我决定为jenkins单独添加一个执行发布任务的服务器作为节点,该节点可以是物理机、虚拟机或者docker容器,换句话说,只要是能够被jenkins可能访问到的机器都是可以的。在这里为了简单(其实是没有可以用的资源),我选择在同一台宿主机上使用docker容器作为节点,并且它将会和jenkins处于同一个虚拟网络,只要有正确的授权,Jenkins能够很容易访问到它。

准备一个docker镜像

首先,需要准备一个docker镜像,该镜像启动后将会作为Jenkins的一个执行构建任务的节点。其中必须预置一些软件或应用。

  • ubuntu

    构建操作系统基于ubuntu,启动ubuntu后,需要在容器内准备发布环境。

  • nodejs v14

    • nrm全局安装
    npm i -g nrm
    
    • 添加发布账号和指定仓库镜像地址
    npm adduser --registry http://10.6.32.13:4873/ #之后输入username passwrod
    
    • 添加发布仓库镜像地址
    nrm add cy http://10.6.32.13:4873/
    
    • 指定镜像地址
    nrm use cy
    
  • openssh

    jenkins需要远程登陆到代理节点上来完成任务。ssh是linux系统常用的登录方式。

  • java

    jenkins在代理节点上执行任务是通过执行java程序来完成的,

    需要注意的是默认情况下java要安装在指定的几个目录之一,jenkins会自动识别。也可以在Jenkins上配置节点的时候指定java的目录。

image.png 也可以直接写一个Dockerfile包含以上所有需要执行的命令。以下是一个Dockerfile示例

# '开始获取ubuntu'
FROM ubuntu
​
RUN apt-get update -y \
    && apt-get install curl -y \
    && cp /etc/apt/sources.list /etc/apt/sources.list.bak_`date "+%y_%m_%d"` \
    && sed -i 's/http://.*.ubuntu.com/https://mirrors.aliyun.com/g' /etc/apt/sources.list \
    && apt-get update -y \
    && apt-get install openssh-server -y    \
    && apt-get upgrade -y \
    && curl -sL https://deb.nodesource.com/setup_14.x | bash -\
    && apt-get install nodejs -y    \
    && apt-get install git  -y  \
    && npm config set registry https://registry.npm.taobao.org \
    && npm i -g yarn \
    && yarn config set registry https://registry.npm.taobao.org \
    && npm i -g @angular/cli    \
    && mkdir -p /home/projects  \
    && git clone http://10.6.3.15:82/mes/mes-lib.git /home/projects
​
CMD '/etc/init.d/ssh start'
EXPOSE 80 22

启动镜像

镜像启动后,会返回一个容器ID

docker run -itd [容器ID] /bin/bash

上面的命令执行成功后,会自动登陆到容器内,首先需要确保ssh服务是处于启动的状态,如果没有继续启动ssh服务,也将其设置为自动启动。

service ssh start

为了能够让jenkins能够登陆到本节点,需要将Jenkins服务器上的公钥追加到本节点服务器中的~/.ssh/auth/authorized_keys

echo 'jenkins 服务器的公钥' >> ~/.ssh/authorized_keys

配置gitlab访问账号

本容器将来是作为发布公共组件库而创建的,因此拥有一个有访问权限的gitlab账号是必须的。通常获取gitlab仓库代码有httpssh两种方式,http需要输入账号密码,而ssh登陆是比较方便的一种,与gitlab张傲绑定一次即可,与密码无关。

生成ssh密钥

做这一步之前,首先要确定~/.ssh/目录中是否存在 id_rsa id_rsa.pub, 其中id_rsa是私钥文件,id_ras.pub是私钥成对的公钥文件。如果不存在则执行:

ssh-keygen -m PEM -t rsa -b 4096  # 回车之后,一路回车就可以生成了

执行成功后会在~/.ssh/目录中产生id_rsaid_rsa.pub文件

绑定gitlab账号
  • 进入~/.ssh目录,复制公钥文件id_rsa.pub中的文本。

  • 使用有访问权限的账号登陆gitlab页面,进入 用户设置 Settings -> SSH Keys 在表单中填入 id_rsa.pub 中复制的文本,点击确定即可

image.png

以上准备完之后,就可以开始在Jenkins上操作了。

Jenkins

创建凭据

  • 确保Jenkins服务器上存在ssh密钥
docker exec -it [jenkins 容器Id] bash # 在宿主机上执行该命令登陆jenkins服务器

执行命令进入ssh密钥文件存放目录,如果目录不存在则意味着jenkins没有创建过ssh密钥

cd ~/.ssh/ 

执行ls命令查看~/.ssh/目录中是否存在文件id_rsa id_rsa.pub, 其中id_rsa是私钥文件,id_ras.pub是私钥成对的公钥文件。

如果不存在则需要执行下列命令生成密钥文件, 执行成功后会在~/.ssh/目录中产生id_rsaid_rsa.pub文件

ssh-keygen -m PEM -t rsa -b 4096  # 回车之后,一路回车就可以生成了

最后需要将私钥添加到jenkins全局凭据中。

  • 使用管理员账号登陆jenkins web页面,进入 管理Jenkins -> 凭据 -> 系统 -> 全局凭据 -> 添加凭据

进入添加凭据表单页面后,如图所示进行选择

image.png

点击最后的Add之后,将id_rsa文件中的内容贴到红框中,然后点击确定

image.png

添加jenkins节点

进入 管理Jenkins -> 节点管理 -> 新建节点 输入节点名称,选择固定节点,点击确定。

image.png

填写以下表单:

image.png

  • 远程工作目录

    构建任务的执行目录,即,发布公共模块其中一个步骤需要从gitlab上获取代码,那么代码就在这个目录中。

  • 标签

    由于添加的这个节点是一个专门用来执行发布任务的,所以需要填写标签,在创建流水线任务的时候要指定这个标签

  • 用法

    不希望jenkins中其他的构建任务使用该节点,则选择只允许运行绑定到这台机器的Job

  • 启动方式

    通过SSH登陆到代理服务器执行任务,选择Launch agents via SSH

    需要注意的是,要安装插件 SSH Build Agents plugin才会有该选项

    • 主机

      节点服务器的IP地址,可以登陆到宿主机执行命令查询

      docker inspect [节点容器Id]
      

image.png

执行之后在控制台输出的结果的最后有一个 IPAddress 的属性后面对应的就是该容器的IP地址,复制填入表单。

  • Credentials(凭据)

    选择上一步中添加的凭据

  • Host Key Verification Strategy

    选择Non verifying Verification Strategy

点击确定后,Jenkins会自动根据表单中的配置去连接节点(代理)服务器,成功后会在左下角出现一个新的任务执行节点(代理)服务器。

image.png

创建流水线任务

  • 使用管理员账号登陆Jenkins,创建任务
  • 输入任务名称,选择流水线,点击确定

image.png

  • 编辑任务属性 - 构建触发器

image.png

勾选 Build when a change is pushed to GitLab. Gitlab webhook URL http://xxxxxxxxxx复制后面的URL,这个URL将会配置到gitlab仓库的Webhooks中

  • 编辑任务属性 - 流水线

image.png

流水线脚本

pipeline {
    agent {
        label '代理节点标签' // 将该任务与前面新建的节点标签绑定,意味着本任务只会在该节点上运行
    }
    stages {
        stage('Get Tag') {
            steps {
                script { 
                    println env.gitlabSourceRepoHttpUrl         // 打印环境变量
                    println env.gitlabAfter                     // 打印环境变量
                    println env.gitlabTargetBranch              // 当前触发任务中包含的标签,其值为 refs/tags/[tag]
                    dirs = env.gitlabTargetBranch.split('/')    // 将字符串分割,得到数组
                    tag = dirs[dirs.length - 1]                 // 取数组最后的一个元素,即为tag号
                    println 'tag is ' + tag
                    // 执行shell,拼接字符串脚本, clone当前最新的标签的代码
                    sh 'git clone [代码仓库的ssh访问地址] -b ' + tag + ' ./' + env.gitlabAfter   
                    // shell脚本,执行npm install 和 发布命令
                    sh 'cd ./' + env.gitlabAfter + ' && npm install && npm run publish:lib'     
                }
            }
        }
    }
}

值得一提的是,打印一下包含了当前构建任务信息的环境变量,你总能从打印结果中获得一些有用的东西,上方脚本中的变量就是从打印结果中拿到的

pipeline {
    stages {
        stage('env variable') {
            sh 'printenv'  // 打印所有的环境变量
        }
    }
}

gitlab

配置Webhooks

  • 登陆可以访问仓库的账号,进入仓库首页 ->Settings -> Integrations, 填写表单

image.png

  • URL

    该处填写,Jenkins流水线任务的访问URL

  • Trigger

    Tag push events, 只有在打标签后才会触发Webhook, 将构建请求发送到Jenkins

这一步可能会出现404、403、401的错误

[403的解决办法]  www.cnblogs.com/kaerxifa/p/… 

到此,仓库创建tag触发webhooks通知jenkins触发构建任务,整个流程就串联起来了。