跳到主要内容

解压

Jenkinsflie

Jenkins Pipeline 提供了一套可扩展的工具,用于将“简单到复杂”的交付流程实现为“持续交付即代码”。Jenkins Pipeline 的定义通常被写入到一个文本文件(称为 Jenkinsfile )中,该文件可以被放入项目的源代码控制库中。

演示1:使用Jenkinsfile管理pipeline
  • 在项目中新建Jenkinsfile文件,拷贝已有script内容
  • 配置pipeline任务,流水线定义为Pipeline Script from SCM
  • 执行push 代码测试

Jenkinsfile:

pipeline {
agent {label '172.21.65.227'}
environment {
PROJECT = 'eladmin-api'
}
stages {
stage('printenv') {
steps {
echo 'Hello World'
sh 'printenv'
}
}
stage('checkout') {
steps {
checkout([$class: 'GitSCM', branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'gitlab-user', url: 'http://gitlab.luffy.com/eladmin/eadmin-api.git']]])
}
}
stage('build-image') {
steps {
sh 'docker build . -t 172.21.65.226/eladmin/eladmin-api:latest -f Dockerfile'
}
}
}
post {
success {
echo 'Congratulations!'
}
failure {
echo 'Oh no!'
}
always {
echo 'I will always say Hello again!'
}
}
}
演示2:优化及丰富流水线内容
  • 优化代码检出阶段,由于目前已经配置了使用git仓库地址,且使用SCM来检测项目,因此代码检出阶段完全没有必要再去指定一次

  • 构建镜像的tag使用git的commit id

  • 丰富通知内容

  • 编译和构建拆分不同的stage,增加构建速度

pipeline {
agent { label '172.21.65.227'}
environment {
PROJECT = 'eladmin-api'
}
stages {
stage('printenv') {
steps {
echo 'Hello World'
sh 'printenv'
}
}
stage('checkout') {
steps {
checkout scm
}
}
stage('mvn package') {
steps {
sh 'mvn clean package'
}
}
stage('build-image') {
steps {
retry(2) { sh 'docker build . -t 172.21.65.226/eladmin/eladmin-api:${GIT_COMMIT} -f Dockerfile'}
}
}
}
post {
success {
echo 'Congratulations!'
sh """
curl 'https://oapi.dingtalk.com/robot/send?access_token=1ced770ad03109697003451029999b3dfb01f01cfda59e5fea8e285724218752' \
-H 'Content-Type: application/json' \
-d '{"msgtype": "text",
"text": {
"content": "😄👍构建成功👍😄\n 项目名称: ${JOB_BASE_NAME}\n Commit Id: ${GIT_COMMIT}\n 构建地址:${RUN_DISPLAY_URL}"
}
}'
"""
}
failure {
echo 'Oh no!'
sh """
curl 'https://oapi.dingtalk.com/robot/send?access_token=1ced770ad03109697003451029999b3dfb01f01cfda59e5fea8e285724218752' \
-H 'Content-Type: application/json' \
-d '{"msgtype": "text",
"text": {
"content": "😖❌构建失败❌😖\n 项目名称: ${JOB_BASE_NAME}\n Commit Id: ${GIT_COMMIT}\n 构建地址:${RUN_DISPLAY_URL}"
}
}'
"""
}
always {
echo 'I will always say Hello again!'
}
}
}

需要在172.21.65.227节点安装maven环境

链接: https://pan.baidu.com/s/1z9dRGv_4bS1uxBtk5jsZ2Q 提取码: 3gva

# 解压
$ tar zxf apache-maven-3.6.3-bin.tar.gz

# 修改mvn配置,配置maven源和本地仓库路径
$ vi apache-maven-3.6.3/conf/settings.xml
\<?xml version="1.0" encoding="UTF-8"?\>
<settings xmlns="http://maven.apache.org/SETTINGS/_1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"\>
<localRepository>/opt/maven-repo</localRepository>
<proxies>
</proxies>

<servers>
</servers>

<mirrors>
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>

</settings>


# 拷贝目录,并软连接
$ cp -r apache-maven-3.6.3 /usr/lib/
$ ln -s /usr/lib/apache-maven-3.6.3/bin/mvn /usr/bin/mvn


# 验证
$ mvn -v
Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
Maven home: /usr/lib/apache-maven-3.6.3
Java version: 11.0.17, vendor: Red Hat, Inc., runtime: /usr/lib/jvm/java-11-openjdk-11.0.17.0.8-2.el7_9.x86_64
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "3.10.0-1160.36.2.el7.x86_64", arch: "amd64", family: "unix"

修改Dockerfile

FROM java:8u111
WORKDIR /opt/eladmin
COPY eladmin-system/target/ .
CMD [ "sh", "-c", "java -Dspring.profiles.active=prod -jar eladmin-system-2.6.jar" ]
演示3:使用k8s部署服务
  • 新建mainfests目录,将k8s所需的文件放到mainfests目录中

  • 将镜像地址改成模板,在pipeline中使用新构建的镜像进行替换

  • 执行kubectl apply -f mainfests应用更改,需要配置kubectl认证

    $ scp -r k8s-master:/root/.kube /root
pipeline {
agent { label '172.21.65.227'}

environment {
IMAGE_REPO = "172.21.65.226:5000/eladmin/eladmin-api"
}

stages {
stage('printenv') {
steps {
echo 'Hello World'
sh 'printenv'
}
}
stage('checkout') {
steps {
checkout scm
}
}
stage('mvn package') {
steps {
sh 'mvn clean package'
}
}
stage('build-image') {
steps {
retry(2) { sh 'docker build . -t ${IMAGE_REPO}:${GIT_COMMIT}'}
}
}
stage('push-image') {
steps {
retry(2) { sh 'docker push ${IMAGE_REPO}:${GIT_COMMIT}'}
}
}
stage('deploy') {
steps {
timeout(time: 1, unit: 'MINUTES') {
sh "sed -i 's#{{IMAGE_URL}}#${IMAGE_REPO}:${GIT_COMMIT}#g' manifests/*"
sh "kubectl apply -f manifests/"
}
}
}
}
post {
success {
echo 'Congratulations!'
sh """
curl 'https://oapi.dingtalk.com/robot/send?access_token=1ced770ad03109697003451029999b3dfb01f01cfda59e5fea8e285724218752' \
-H 'Content-Type: application/json' \
-d '{"msgtype": "text",
"text": {
"content": "😄👍构建成功👍😄\n 项目名称: ${JOB_BASE_NAME}\n Commit Id: ${GIT_COMMIT}\n 构建地址:${RUN_DISPLAY_URL}"
}
}'
"""
}
failure {
echo 'Oh no!'
sh """
curl 'https://oapi.dingtalk.com/robot/send?access_token=1ced770ad03109697003451029999b3dfb01f01cfda59e5fea8e285724218752' \
-H 'Content-Type: application/json' \
-d '{"msgtype": "text",
"text": {
"content": "😖❌构建失败❌😖\n 项目名称: ${JOB_BASE_NAME}\n Commit Id: ${GIT_COMMIT}\n 构建地址:${RUN_DISPLAY_URL}"
}
}'
"""
}
always {
echo 'I will always say Hello again!'
}
}
}

演示4:使用凭据管理敏感信息

上述Jenkinsfile中存在的问题是敏感信息使用明文,暴漏在代码中,如何管理流水线中的敏感信息(包含账号密码),之前我们在对接gitlab的时候,需要账号密码,已经使用过凭据来管理这类敏感信息,同样的,我们可以使用凭据来存储钉钉的token信息,那么,创建好凭据后,如何在Jenkinsfile中获取已有凭据的内容?

Jenkins 的声明式流水线语法有一个 credentials() 辅助方法(在environment 指令中使用),它支持 secret 文本带密码的用户名,以及 secret 文件凭据。

下面的流水线代码片段展示了如何创建一个使用带密码的用户名凭据的环境变量的流水线。

在该示例中,带密码的用户名凭据被分配了环境变量,用来使你的组织或团队以一个公用账户访问 Bitbucket 仓库;这些凭据已在 Jenkins 中配置了凭据 ID jenkins-bitbucket-common-creds

当在 environment 指令中设置凭据环境变量时:

environment {
BITBUCKET_COMMON_CREDS = credentials('jenkins-bitbucket-common-creds')
}

这实际设置了下面的三个环境变量:

  • BITBUCKET_COMMON_CREDS - 包含一个以冒号分隔的用户名和密码,格式为 username:password
  • BITBUCKET_COMMON_CREDS_USR - 附加的一个仅包含用户名部分的变量。
  • BITBUCKET_COMMON_CREDS_PSW - 附加的一个仅包含密码部分的变量。
pipeline {
agent {
// 此处定义 agent 的细节
}
environment {
//顶层流水线块中使用的 environment 指令将适用于流水线中的所有步骤。
BITBUCKET_COMMON_CREDS = credentials('jenkins-bitbucket-common-creds')
}
stages {
stage('Example stage 1') {
//在一个 stage 中定义的 environment 指令只会将给定的环境变量应用于 stage 中的步骤。
environment {
BITBUCKET_COMMON_CREDS = credentials('another-credential-id')
}
steps {
//
}
}
stage('Example stage 2') {
steps {
//
}
}
}
}

因此对Jenkinsfile做改造:

jenkins/pipelines/p5.yaml

pipeline {
agent { label '172.21.65.227'}

environment {
IMAGE_REPO = "172.21.51.143:5000/myblog"
DINGTALK_CREDS = credentials('dingTalk')
}

stages {
stage('printenv') {
steps {
echo 'Hello World'
sh 'printenv'
}
}
stage('check') {
steps {
checkout scm
}
}
stage('build-image') {
steps {
retry(2) { sh 'docker build . -t ${IMAGE_REPO}:${GIT_COMMIT}'}
}
}
stage('push-image') {
steps {
retry(2) { sh 'docker push ${IMAGE_REPO}:${GIT_COMMIT}'}
}
}
stage('deploy') {
steps {
sh "sed -i 's#{{IMAGE_URL}}#${IMAGE_REPO}:${GIT_COMMIT}#g' manifests/*"
timeout(time: 1, unit: 'MINUTES') {
sh "kubectl apply -f manifests/"
}
}
}
}
post {
success {
echo 'Congratulations!'
sh """
curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \
-H 'Content-Type: application/json' \
-d '{"msgtype": "text",
"text": {
"content": "😄👍构建成功👍😄\n 关键字:luffy\n 项目名称: ${JOB_BASE_NAME}\n Commit Id: ${GIT_COMMIT}\n 构建地址:${RUN_DISPLAY_URL}"
}
}'
"""
}
failure {
echo 'Oh no!'
sh """
curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \
-H 'Content-Type: application/json' \
-d '{"msgtype": "text",
"text": {
"content": "😖❌构建失败❌😖\n 关键字:luffy\n 项目名称: ${JOB_BASE_NAME}\n Commit Id: ${GIT_COMMIT}\n 构建地址:${RUN_DISPLAY_URL}"
}
}'
"""
}
always {
echo 'I will always say Hello again!'
}
}
}

本章小结

上面我们已经通过Jenkinsfile完成了最简单的项目的构建和部署,那么我们来思考目前的方式:

  1. 目前都是在项目的单一分支下进行操作,企业内一般会使用feature、develop、release、master等多个分支来管理整个代码提交流程,如何根据不同的分支来做构建?
  2. 构建视图中如何区分不同的分支?
  3. 如何不配置webhook的方式实现构建?
  4. 如何根据不同的分支选择发布到不同的环境(开发、测试、生产)?