Jenkins Pipeline是一套插件,支持在Jenkins中实现持续集成和持续交付;
pipeline的编写都要写入到一个名为Jenkinsfile的文件中。
流水线脚本管理 Jenkinsfile
流水线脚本有两种写入管理方法:
1、在 Jenkins - Gui 界面里写。
2、存放在 gitlab,与 项目代码同一级目录。命名为 Jenkinsfile ( j 必须大写 ) 文件,编写具体pipeline代码。
好处:****在代码项目中和的 Jenkinsfile ,方便管理,方便备份,不会因为 jenkins宕机丢失整个流水线配置,而且又具备了代码仓的功能,可查看历史记录、复查等等。
如果方法2将Jenkins放在代码层后的使用方法:在 jenkins - GUI 界面 通过 ****pipeline SCM ****连接到 gitlab仓库,获取 Jenkinsfile 文件,
如下图:
pipeline语法
pipeline语法有两种
- Declarative Pipeline(声明式),推荐使用。
- Scripted Pipeline(脚本式),旧版,很少用了。
声明式pipeline:推荐使用。
Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
stages { # stages表示这是一组阶段stage,由多个阶段stage组成,按顺序从上到下执行每个stage
stage('Example') { # 具体阶段,由多个steps组成, 这里的Example时指定这个stage的名称
steps { # 定义步骤,用于指定该阶段具体要执行什么步骤,如:执行命令等等
echo 'Hello World'
}
}
}
}
脚本式pipeline:
Jenkinsfile (Scripted Pipeline)
node {
stage('Example') {
echo 'Hello World'
}
}
语法自动生成
片段生成器:可以自动生产拉取、打包、部署的代码。直接粘贴到 pipeline即可使用。
Declarative Directive Generator:声明式指令生成器。
Declarative Online Documentation:声明式指令官方文档
片段生成器
拉取代码:check out from version control
pipeline指令生成器
在实际工作中,会维护多个项目,如果每个服务都创建一个item,势必给运维维护成本增加很大,因此需要编写一个通用Pipeline脚本,将这些项目部署差异化部分使用Jenkins参数化,人工交互确认发布的分支、副本数、命名空间等。
生成通用化参数-拉取指定分支得代码
parameters {
gitParameter branch: '', branchFilter: '.*', defaultValue: 'origin/master', description: '选取拉取代码的分支', name: 'userChoiceBranch', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'GitParameterDefinition'
}
生成单选项-自定义单选项-
parameters {
choice choices: ['dev', 'pord', 'test', 'default'], description: '发布到哪个namespace', name: 'deployNamespace'
}
完整部署项目到K8S的pipeline脚本示例:
/// 使用def 定义变量
// harbor镜像仓库地址
def registry = "10.0.1.140"
// harbor项目名称
def project = "test"
// harbor项目中的镜像名
def app_name = "java-demo"
// 具体镜像名,镜像的tag版本号,引用的时jenkins自带的BUILD_NUMBERB变量,每build一次这个变量都会自增+1.
def image_name = "${registry}/${project}/${app_name}:${BUILD_NUMBER}"
// 代码仓库地址
def git_address = "http://10.0.1.141:88/root/jenkinstest.git"
//harbor仓库的账号和密码登录凭据
def harbor_auth = "a6e4e47a-dbdd-45af-8735-eb8d158c104d"
// git的账号和密码凭据ID
def git_auth = "8370aa1b-ec04-4caa-b753-851f7fe169a5"
// kubeconfig文件的id值,用于执行kubectl命名时引用。
def k8s_kubeconfig = "4b6cb8e6-e5e4-42a1-8d4b-3514e51a5d3e"
// pod部署时向harbor拉取镜像的secret凭据名称
def secret_name = "myharbor"
pipeline {
agent {
kubernetes {
label "jenkins-slave"
yaml """
apiVersion: v1
kind: Pod
metadata:
name: jenkins-slave
spec:
containers:
- name: jnlp
image: "10.0.1.140/library/jenkins-slave-jdk:1.8.1"
imagePullPolicy: Always
volumeMounts: # 将宿主机的docker命令这些程序挂载进来pod容器中使用。因为你要打包镜像要用到docker命令
- name: docker-cmd
mountPath: /usr/bin/docker
- name: docker-sock
mountPath: /var/run/docker.sock
- name: maven-cache
mountPath: /root/.m2 # 挂载maven仓库的缓存,这样以后再次执行编译就需要全部重新下载项目要用到的依赖jar包等。因为slave pod每次执行完就会被delete的。
volumes:
- name: docker-cmd
hostPath:
path: /usr/bin/docker
- name: docker-sock
hostPath:
path: /var/run/docker.sock
- name: maven-cache
hostPath:
path: /tmp/m2
"""
}
}
**// 定义一些参数选择器,这些会在运行任务前,让执行者去进行选择**
parameters {
// 分支选择器
gitParameter branch: '', branchFilter: '.*', defaultValue: 'master', description: '选择拉取gitlab项目代码的分支', name: 'chooesebranch', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'GitParameterDefinition'
// 选择部署deployment的副本数
choice choices: ['1', '2', '3', '4', '5'], description: '请选择部署到集群的副本数', name: 'replicas'
// 选择部署到哪个namespace中
choice choices: ['default', 'dev', 'prod', 'test'], description: '请选择部署到集群的哪个namespace', name: 'namespace'
}
// 定义每个阶段执行什么东西
stages {
stage('从gitlab拉取代码') {
steps {
checkout([$class: 'GitSCM', branches: [[name: "${chooesebranch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_address}"]]])
}
}
stage('编译项目代码') {
steps {
sh """
mvn -B -DskipTests clean package
"""
}
}
stage('打包镜像并推送到harbor仓库') {
steps {
// 使用withCredentials从jenkins凭据中读取harbor的用户名和密码,并分别保存到指定的变量中,在执行命令时会指定的地方自动输入
withCredentials([usernamePassword(credentialsId: "${harbor_auth}", passwordVariable: 'harborpw', usernameVariable: 'harborusername')]) {
// some block
sh """
# 解压编译后的war包到当前目录
unzip target/*.war -d target/ROOT
# 生成一个Dockerfile,用于后面的打包镜像
# 这里其实推荐将Dockerfile也放入到代码项目中,这样可以直接用就行,不需要echo。。。
echo '
FROM lizhenliang/tomcat
LABEL maitainer lizhenliang
ADD target/ROOT /usr/local/tomcat/webapps/ROOT
' > Dockerfile
# 打包docker镜像
docker build -t ${image_name} .
# 登录harbor镜像仓库,用户名和密码调用jenkins的凭据管理器中存储的相关凭据
docker login -u "${harborusername}" -p "${harborpw}" ${registry}
# 推送镜像到镜像仓库
docker push ${image_name}
"""
}
}
}
stage('部署到k8s中') {
steps {
configFileProvider([configFile(fileId: "${k8s_kubeconfig}", targetLocation: "my.kubeconfig")]) {
// some block
sh """
sed -i 's#J_IMAGE_NAME#${image_name}#' deploy.yml
sed -i 's#J_SECRET_NAME#${secret_name}#' deploy.yml
sed -i 's#J_REPLICASNUM#${replicas}#' deploy.yml
echo "----------------------------------"
cat deploy.yml
echo "----------------------------------"
kubectl apply -f deploy.yml -n ${namespace} --kubeconfig=my.kubeconfig
"""
}
}
}
}
}
/// 使用def 定义变量
// harbor镜像仓库地址
def registry = "192.168.2.6"
// harbor项目名称
def project = "library"
// harbor项目中的镜像名
def app_name = "k8s-flask-web"
// 具体镜像名,镜像的tag版本号,引用的时jenkins自带的BUILD_NUMBERB变量,每build一次这个变量都会自增+1.
def image_name = "${registry}/${project}/${app_name}:${BUILD_NUMBER}"
// 代码仓库地址
def git_address = "https://jihulab.com/SWQJueLian/k8s-flask.git"
//harbor仓库的账号和密码登录凭据
def harbor_auth = "f74d85d9-2fe3-41c3-b8df-6b56ce88545c"
// git的账号和密码凭据ID
def git_auth = "61af6ddc-6d2c-4888-b758-8afd5d529929"
// kubeconfig文件的id值,用于执行kubectl命名时引用。
def k8s_kubeconfig = "7ea988e4-f4e0-44ec-b99d-9b7852461bf3"
// pod部署时向harbor拉取镜像的secret凭据名称
def secret_name = "myharbor"
pipeline {
agent {
kubernetes {
label "jenkins-slave"
yaml """
apiVersion: v1
kind: Pod
metadata:
name: jenkins-slave-py3
spec:
containers:
- name: jnlp
image: "192.168.2.6/library/jenkins-slave@sha256:e9f63cf7551b8970645fa61aaa0c9819152f45bb02e5dc4ba8114acb3f5b0564"
volumeMounts: # 将宿主机的docker命令这些程序挂载进来pod容器中使用。因为你要打包镜像要用到docker命令
- name: localtime # 时区用宿主机的
mountPath: /etc/localtime
- name: nerdctl
mountPath: /usr/bin/nerdctl # nerdctl肯定是要的...锤子个麻烦,还不如docker...
- name: buildctl
mountPath: /usr/bin/buildctl # containerd打包镜像
- name: containerd-sock
mountPath: /run/containerd/containerd.sock
- name: buildkitd-sock # buildkit的socket也要挂载
mountPath: /run/buildkit/buildkitd.sock
volumes:
- name: localtime
hostPath:
path: /etc/localtime
- name: buildctl
hostPath:
path: /usr/local/bin/buildctl
- name: kubectl # kubectl 看情况挂载,也可以准备自己的,提前打到jenkins-slave的镜像中。
hostPath:
path: /usr/bin/kubectl
- name: nerdctl
hostPath:
path: /usr/local/bin/nerdctl
- name: containerd-sock
hostPath:
path: /run/containerd/containerd.sock
- name: buildkitd-sock
hostPath:
path: /var/run/buildkit/buildkitd.sock
"""
}
}
// 定义一些参数选择器,这些会在运行任务前,让执行者去进行选择
parameters {
// 分支选择器
gitParameter branch: '', branchFilter: '.*', defaultValue: 'master', description: '选择拉取gitlab项目代码的分支', name: 'chooesebranch', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'GitParameterDefinition'
// 选择部署deployment的副本数
choice choices: ['1', '2', '3', '4', '5'], description: '请选择部署到集群的副本数', name: 'replicas'
// 选择部署到哪个namespace中
choice choices: ['default', 'dev', 'prod', 'test'], description: '请选择部署到集群的哪个namespace', name: 'namespace'
}
stages {
stage('从gitlab拉取代码') {
steps {
checkout([$class: 'GitSCM', branches: [[name: "${chooesebranch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_address}"]]])
}
}
stage('编译项目代码') {
steps {
sh """
mvn -B -DskipTests clean package
"""
}
}
stage('打包镜像并推送到harbor仓库') {
steps {
// 使用withCredentials从jenkins凭据中读取harbor的用户名和密码,并分别保存到指定的变量中,在执行命令时会指定的地方自动输入
withCredentials([usernamePassword(credentialsId: "${harbor_auth}", passwordVariable: 'harborpw', usernameVariable: 'harborusername')]) {
// some block
sh """
mkdir -pv imagepackage/target/ROOT
# 解压编译后的war包到当前目录
unzip target/*.war -d imagepackage/target/ROOT
cp Dockerfile imagepackage/
ls imagepackage/
# 生成一个Dockerfile,用于后面的打包镜像
# 这里其实推荐将Dockerfile也放入到代码项目中,这样可以直接用就行,不需要echo。。。
#echo '
# FROM lizhenliang/tomcat
# LABEL maitainer lizhenliang
# ADD target/ROOT /usr/local/tomcat/webapps/ROOT
#' > Dockerfile
# 打包docker镜像
cd imagepackage
docker build -t ${image_name} .
# 登录harbor镜像仓库,用户名和密码调用jenkins的凭据管理器中存储的相关凭据
docker login -u "${harborusername}" -p "${harborpw}" ${registry}
# 推送镜像
docker push ${image_name}
ls -l
cd ../
"""
}
}
}
stage('部署到k8s中') {
steps {
configFileProvider([configFile(fileId: "${k8s_kubeconfig}", targetLocation: "my.kubeconfig")]) {
// some block
sh """
sed -i 's#J_IMAGE_NAME#${image_name}#' deploy.yml
sed -i 's#J_SECRET_NAME#${secret_name}#' deploy.yml
sed -i 's#J_REPLICASNUM#${replicas}#' deploy.yml
sed -i 's#J_NS#${namespace}#g' deploy.yml
echo "----------------------------------"
# cat deploy.yml
echo "----------------------------------"
kubectl apply -f deploy.yml --kubeconfig=my.kubeconfig
"""
}
}
}
}
}