1. 创建jenkins容器
docker run --name jenkins --user=root -p 8080:8080 -p 50000:50000 -v /var/jenkins_home:/var/jenkins_home -v /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v /usr/local/maven3:/usr/local/maven3 -d jenkins/jenkins
解释docker脚本
- -v /var/jenkins_home:/var/jenkins_home :指定jenkins主要目录位置
- -v /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime : 指定容器时区 应该也可以用 -e TZ="Asia/Shanghai 但是没有测试
- -v /var/run/docker.sock:/var/run/docker.sock : 指定宿主机docker位置,让容器内也能使用docker命令 ,k8s也可以这么设置,但是还没试
- -v /usr/bin/docker:/usr/bin/docker :和上面一样, 指定宿主机docker位置,让容器内也能使用docker命令 ,k8s也可以这么设置,但是还没试
- -v /usr/local/maven3:/usr/local/maven3 : 指定宿主机maven位置,让容器内也能使用maven3 命令
- -p 8080:8080 : 指定jenkins访问端口
2. 启动jenkens,
访问页面:http://host:8080
-
初始密码:
Jenkins initial setup is required. An admin user has been created and a password generated. Please use the following password to proceed to installation: 8a9754c9ced144568f5a14be449fd801 This may also be found at: /var/jenkins_home/secrets/initialAdminPassword
选择推荐安装,因为里面有很多现有的插件
3. 安装相关插件
- Git Parameter
- Gitlab
4. 设置jenkins时区
System.setProperty('org.apache.commons.jelly.tags.fmt.timeZone', 'Asia/Shanghai')
5. 创建凭证(注意设置的凭证ID,在下面的Pipeline script中都有使用到)
1. 创建gitlab凭证
2. 创建远程docker私有库凭证
在新凭据设置界面,类型选择为“Username with password”,ID设置为“aliyun-docker”(此处的ID必须与Jenkinsfile中的保持一致)。Username与Password分别设置为镜像私库的用户名和密码。
3. 创建k8s配置文件凭证
k8s中使用kubectl命令时需要yaml格式的服务器及授权信息配置文件。这里将kubectl的yaml配置文件的内容以base64编码后保存在jenkins的凭据中。pipeline任务执行时,先从jenkins凭据中获取内容,进行base64解码后将配置保存为~/.kube/config文件。kubectl的配置文件的内容如下(位置在/root/.kube/config):
k8s配置文件样例:
apiVersion: v1
kind: Config
clusters:
- name: "test"
cluster:
server: "https://xxxxx"
api-version: v1
certificate-authority-data: "xxxxxx"
users:
- name: "user1"
user:
token: "xxxx"
contexts:
- name: "test"
context:
user: "user1"
cluster: "test"
current-context: "test"
6. 创建项目(我们选择创建流水线项目)
Pipeline script与SCM介绍
不同点
Pipeline script
- 在脚本中有parameters时,执行构建时可以选择参数值,例如选择git分支;
- 拉取git代码时需要自己写checkout脚本
- 拉取git代码时需要自己指定文件夹名称
- Pipeline script模式好像不会在每一个docker中拉一次代码,看日志时没有看到具体是怎么做的
SCM
- 在脚本中有parameters时,不能选择参数,只能使用默认值(可能是没玩明白)
- 拉取git代码不能动态变化拉取的git分支,因为jenkinsfile就在代码里需要先拉代码才能得到相关脚本
- 拉取git代码时不需要自己指定文件夹名称,默认就是项目名称,好像也不能更改
- 在使用docker关键字时,在每个docker容器内部都会拉取一遍代码,也就是说每个docker容器内都有一个重复的副本
相同点
他们使用相同的Pipeline 脚本,除了拉取代码部分需要稍作更改,其他可以完全复制(复制时注意进入项目的路径)
经过对比,我们选择使用Pipeline script方式,因为这样在设置参数时相对灵活
7. Pipeline script 脚本
注意Pipeline script 脚本不能有注释(//xxx),不能有分号(;)否则会执行失败
pipeline{
agent any
options {
timeout(time: 1, unit: 'HOURS')
skipStagesAfterUnstable()
}
environment {
K8S_CONFIG = credentials('k8s-config')
ALIYUN_DOCKER = credentials('aliyun-docker')
APP_NAME = 'xh-zuul-backend'
IMAGE_SERVER = 'registry.cn-beijing.aliyuncs.com'
IMAGE_NAME = 'space_dev'
}
parameters {
string(name: 'TAG', defaultValue: 'v8.0.0', description: '镜像和k8s的tag')
gitParameter(branchFilter: 'origin/(.*)', defaultValue: ' master', description: '父级项目分支', name: 'ZUUL_BACKEND_BRANCH', type: 'PT_BRANCH', useRepository: 'http://gitlab.mixinr.com:18080/mixinr-web/xh-zuul-backend.git')
}
stages {
stage('Checkout git'){
steps{
dir("${APP_NAME}"){
git branch: "${ZUUL_BACKEND_BRANCH}", credentialsId: 'xhmh-gitlab', url: 'http://gitlab.mixinr.com:18080/mixinr-web/xh-zuul-backend.git'
}
}
}
stage('Maven package'){
agent {
docker {
image 'maven:3-jdk-8-alpine'
args "-v /root/local/.m2:/root/.m2 -v ${WORKSPACE}/${APP_NAME}:/root/project"
}
}
steps{
sh """
cd /root/project
mvn clean package -U -Dmaven.test.skip=true
"""
}
}
stage('Docker build'){
steps{
sh """
cd ${WORKSPACE}/${APP_NAME}
docker build -t ${IMAGE_SERVER}/${IMAGE_NAME}/${APP_NAME}:${TAG} .
docker login -u ${ALIYUN_DOCKER_USR} -p ${ALIYUN_DOCKER_PSW} ${IMAGE_SERVER}
docker push ${IMAGE_SERVER}/${IMAGE_NAME}/${APP_NAME}:${TAG}
docker rmi ${IMAGE_SERVER}/${IMAGE_NAME}/${APP_NAME}:${TAG}
"""
}
}
stage('Deploy k8s') {
agent {
docker {
image 'lwolf/helm-kubectl-docker'
args "-v ${WORKSPACE}/${APP_NAME}:/root/project"
}
}
steps {
sh """
mkdir -p ~/.kube
echo ${K8S_CONFIG} | base64 -d > ~/.kube/config
cd /root/project
echo export IMAGE_URL=${IMAGE_SERVER} export IMAGE_TAG=${TAG} export APP_NAME=${APP_NAME} export IMAGE_NAME=${IMAGE_NAME} > param.txt
source param.txt && envsubst < k8s-deployment.yml > k8s-deployment-tmp.yml
kubectl apply -f k8s-deployment-tmp.yml -n test
"""
}
}
}
}
参数解释
详细的语法讲解:https://www.cnblogs.com/cay83/p/7537840.html
- 设置可选的操作
options {
//执行的timeout
timeout(time: 1, unit: 'HOURS')
//状态为Unstable时跳过后面的stage
skipStagesAfterUnstable()
}
- environment指令指定一系列键值对,这些键值对将被定义为所有step或stage-specific step的环境变量,具体取决于environment指令在Pipeline中的位置。
environment {
K8S_CONFIG = credentials('k8s-config')
ALIYUN_DOCKER = credentials('aliyun-docker')
APP_NAME = 'xh-zuul-backend'
IMAGE_SERVER = 'registry.cn-beijing.aliyuncs.com'
IMAGE_NAME = 'space_dev'
}
- K8S_CONFIG : 为k8s中kubectl命令的yaml配置文件内容,数据保存为jenkins的“Secret Text”类型的凭据,用credentials方法从凭据中获取。这里保存的yaml配置文件内容以base64编码格式保存,在设置凭据时先要进行base64编码。(此base64编码是非必须的,如果直接保存原文,下面Jenkinsfile中需要去掉base64 -d 解码)
- ALIYUN_DOCKER:阿里云镜像仓库的用户密码,数据保存为jenkins的“username and password”类型的凭据,用credentials方法从凭据中获取。使用时通过ALIYUN_DOCKER_USR获取用户名,ALIYUN_DOCKER_PSW获取密码。
- APP_NAME:设置的项目名称
- IMAGE_SERVER:设置的镜像server
- IMAGE_NAME:设置的镜像名称
-
设置变量,在使用Pipeline script 脚本模式时,每一个在parameters块中声明的参数都要在构建时指定参数,如下:
点击 Build with Parameters进行构建,设置用于构建项目的参数
parameters {
string(name: 'TAG', defaultValue: 'v8.0.0', description: '镜像和k8s的tag')
gitParameter(branchFilter: 'origin/(.*)', defaultValue: ' master', description: '父级项目分支', name: 'ZUUL_BACKEND_BRANCH', type: 'PT_BRANCH', useRepository: 'http://xxx.mixinr.com/xh-zuul-backend.git')
}
- TAG:设置了一个tag,用于指定创建的镜像tag和k8s部署的tag
- ZUUL_BACKEND_BRANCH:设置git分支参数,动态拉取指定git库的分支,现在使用了branchFilter对分支进行了过滤,注意:拉取选择的分支jenkins会在前面加上origin路径,例如:选择了origin/master,实际jenkins在拉取代码时变成了origin/origin/master,所以要注意分支名称
- stages说明,只是一个用户自定义的阶段集合,steps只是stage中必须要有的结构,具体执行的操作都要放到steps块中
-
Checkout git:拉取git代码
stage('Checkout git'){ steps{ dir("${APP_NAME}"){ git branch: "${ZUUL_BACKEND_BRANCH}", credentialsId: 'xhmh-gitlab', url: 'http://gitlab.mixinr.com:18080/mixinr-web/xh-zuul-backend.git' } } }
- dir("${APP_NAME}") : 创建了一个文件夹,名称是上面定义的APP_NAME
- git:
- branch :指定了分支
- credentialsId : 指定了git的凭证,xhmh-gitlab是我们在上面创建gitlab的凭证id
- url:指定了拉取的代码url地址
-
对项目进行maven打包操作,agent是设置代理,使用什么环境执行下面steps操作
stage('Maven package'){ agent { docker { image 'maven:3-jdk-8-alpine' args "-v /root/local/.m2:/root/.m2 -v ${WORKSPACE}/${APP_NAME}:/root/project" } } steps{ sh """ cd /root/project mvn clean package -U -Dmaven.test.skip=true """ } }
- WORKSPACE:该参数是jenkins默认的环境变量,他的值是当前jenkens所在目录+workspace+创建的流水线名称,相当于执行了pwd命令,在该项目中路径为:/var/jenkins_home/workspace/pipline-demo
- docker :指定了使用docker容器的方式运行steps中的代码
- image:指定要拉取的镜像
- args:设置一些参数,这些参数会在直接写到docker run中
- sh:执行shell脚本
-
docker build :执行了一些docker命令
stage('Docker build'){ steps{ sh """ cd ${WORKSPACE}/${APP_NAME} docker build -t ${IMAGE_SERVER}/${IMAGE_NAME}/${APP_NAME}:${TAG} . docker login -u ${ALIYUN_DOCKER_USR} -p ${ALIYUN_DOCKER_PSW} ${IMAGE_SERVER} docker push ${IMAGE_SERVER}/${IMAGE_NAME}/${APP_NAME}:${TAG} docker rmi ${IMAGE_SERVER}/${IMAGE_NAME}/${APP_NAME}:${TAG} """ } }
-
部署到k8s,agent是设置代理,使用什么环境执行下面steps操作
stage('Deploy k8s') { agent { docker { image 'lwolf/helm-kubectl-docker' args "-v ${WORKSPACE}/${APP_NAME}:/root/project" } } steps { sh """ mkdir -p ~/.kube echo ${K8S_CONFIG} | base64 -d > ~/.kube/config cd /root/project echo export IMAGE_URL=${IMAGE_SERVER} export IMAGE_TAG=${TAG} export APP_NAME=${APP_NAME} export IMAGE_NAME=${IMAGE_NAME} > param.txt source param.txt && envsubst < k8s-deployment.yml > k8s-deployment-tmp.yml kubectl apply -f k8s-deployment-tmp.yml -n test """ } }
-
docker :指定了使用docker容器的方式运行steps中的代码
- image:指定要拉取的镜像,这个镜像中有k8s的客户端
- args:设置一些参数,这些参数会在直接写到docker run中
-
sh:
echo ${K8S_CONFIG} | base64 -d > ~/.kube/config : 使用docker的方式执行kubectl命令。在执行前先将K8S_CONFIG中的内容进行base64解密并存为~/.kube/config配置文件,这样在docker容器中就能使用
-
envsubst:使用envsubst命令将k8s的部署文件设置对应参数;例如:k8s-deployment.yml
apiVersion: apps/v1 kind: Deployment metadata: name: $APP_NAME-deployment labels: app: $APP_NAME spec: replicas: 1 selector: matchLabels: app: $APP_NAME template: metadata: labels: app: $APP_NAME spec: containers: - name: $APP_NAME image: $IMAGE_URL/$IMAGE_NAME/$APP_NAME:$IMAGE_TAG ports: - containerPort: 40080
-
- kubectl apply:部署到k8s
8. 开始构建项目
-
点击立即构建
-
报错,查看控制台,鼠标放到#29上点击
-
查看控制台信息发现是没有设置参数
-
刷新项目页面,发现立即构建变成了Build with Parameters
-
点击配置,看到参数化构建过程已经被勾选,里面的参数就是设置Pipeline script脚本中的Parameters参数,这也是和SCM不一样的地方,如果是使用SCM,就不会有构建参数的过程了
-
再次点击build with 选择参数后构建
-
构建成功,鼠标放到上面可以看某一阶段的log日志