需求:
因为不同的服务需要的资源不一样,如cpu,内存等,需要做一个通用模版,对这些差异化资源通过参数来进行定制。
目录:
(1).准备工作
1.jenkins安装时间戳插件
2.测试用的golang-demo
3.其他准备
(2).参数化构建
1.创建pipeline并定制参数
2.定义流水线
3.执行构建
(3).语法注意事项
(4).使用jenkinsfile的方式进行参数化构建
(5).参考资料
(1).准备工作
1.jenkins安装时间戳插件
image的tag使用时间戳,需要安装jenkins插件:build timestamp。
还需要在jenkins的系统配置中修改timestamp的格式(默认是utc格式,不符合image名称语法):
时间戳改为数字形式,精确到秒。
2.测试用的golang-demo
https://gitee.com/future-cicd/jenkins-kubernetes-golang-demo
3.其他准备
jenkins-3:使用jenkinsfile在kubernetes中创建jnlp完成一个简单构建
jenkins-2:使用pipeline在kubernetes创建jnlp完成第一个最简task构建并剖析
jenkins-1:kubernetes中部署的jenkins配置k8s集群连接
harbor-1:创建用户与项目并推送第一个本地镜像到harbor
(2).参数化构建
1.创建pipeline并定制参数
创建pipeline后进行参数化配置:
repo_url:https://gitee.com/future-cicd/jenkins-kubernetes-golang-demo.git
demo的仓库地址。
credentialsId:xxxxxx
这个其实不需要,因为demo是public的,如果是private的,你需要在jenkins里创建credentialsId,输入你的用户名密码。
branch_name:master
要拉取的分支。
k8s_namespace:demo
要部署在k8s中的namespace。
harbor_url:harbor-core.qianlixinzou.com:31600
image要推送到的镜像仓库私服地址。
harbor_group:devops
image存放在harbor的group。
k8s_requests_memory,k8s_requests_cpu,k8s_limits_memory,k8s_limits_cpu:对应k8s的requests, limit。
2.定义流水线
流水线内容:
备份在:
https://gitee.com/future-cicd/jenkins-kubernetes-golang-demo/blob/master/jenkinsfile-with-params-build
代码语言:javascript复制def image_tag = "${BUILD_TIMESTAMP}"
def image_name = "${env.JOB_NAME}"
def app_name = "${env.JOB_NAME}"
def harbor_url = "${params.harbor_url}"
def k8s_yaml = """
---
apiVersion: v1
kind: Namespace
metadata:
name: ${params.k8s_namespace}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ${app_name}
namespace: ${params.k8s_namespace}
spec:
replicas: 1
selector:
matchLabels:
app: ${app_name}
template:
metadata:
name: ${app_name}
labels:
app: ${app_name}
spec:
volumes:
- name: ${app_name}-logs
hostPath:
path: /app/logs/${app_name}
type: DirectoryOrCreate
containers:
- name: ${app_name}
env:
- name: APP_NAME
value: ${app_name}
- name: TZ # 添加
value: Asia/Shanghai # 添加
image: ${params.harbor_url}/${params.harbor_group}/${app_name}:${image_tag}
imagePullPolicy: IfNotPresent
volumeMounts:
- name: ${app_name}-logs
mountPath: /app/logs
resources:
requests:
memory: "${params.k8s_requests_memory}"
cpu: ${params.k8s_requests_cpu}
limits:
memory: "${params.k8s_limits_memory}"
cpu: ${params.k8s_limits_cpu}
limits:
ports:
- name: web
containerPort: 8080
startupProbe:
httpGet:
path: /helloworld
port: 8080
failureThreshold: 30
periodSeconds: 60
livenessProbe:
failureThreshold: 6
httpGet:
path: /helloworld
port: 8080
initialDelaySeconds: 50
periodSeconds: 5
timeoutSeconds: 5
readinessProbe:
failureThreshold: 10
httpGet:
path: /helloworld
port: 8080
initialDelaySeconds: 30
periodSeconds: 5
timeoutSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: ${app_name}-web
namespace: ${params.k8s_namespace}
spec:
selector:
app: ${app_name}
type: ClusterIP
ports:
- name: tcp
port: 80
targetPort: 8080
"""
podTemplate(cloud: 'kubernetes',nodeSelector: 'jenkins-jnlp=yes',
containers: [
containerTemplate(
name: 'container-go',
//设置go代理,否则有些依赖包无法下载。
envVars: [
envVar(key: 'GO111MODULE', value: 'on'),
envVar(key: 'GOPROXY', value: 'https://mirrors.aliyun.com/goproxy/'),
envVar(key: 'CGO_ENABLED', value: 'p0'),
envVar(key: 'GOOS', value: 'linux')
],
image: harbor_url '/devops/jenkins-jnlp-golang:1.18',
ttyEnabled: true,
command: 'cat'
),
containerTemplate(
name: 'container-docker',
ttyEnabled: true,
image: harbor_url '/devops/jenkins-jnlp-docker:19.03'
),
],
//需要将docker和kubectl挂在到pod中这样才可以在pod中与k8s进行联通操作。
volumes: [
hostPathVolume(hostPath: '/run/docker.sock', mountPath: '/run/docker.sock'),
hostPathVolume(hostPath: '/etc/docker', mountPath: '/etc/docker'),
hostPathVolume(hostPath: '/root/.kube', mountPath: '/root/.kube'),
hostPathVolume(hostPath: '/usr/bin/kubectl', mountPath: '/usr/bin/kubectl')
]
)
{
node(POD_LABEL) {
stage('stage-1.Clone') {
// 从git仓库拉取代码
checkout([
$class: 'GitSCM',
branches: [
[name: "${params.branch_name}"]
],
browser: [$class: 'GitLab', repoUrl: "${params.repo_url}"],
doGenerateSubmoduleConfigurations: false,
extensions: [],
submoduleCfg: [],
userRemoteConfigs: [
[url: "${params.repo_url}", credentialsId: "${params.credentialsId}"]
]
])
}
stage('stage-2.Test') {
}
stage('stage-3.Build') {
container('container-go') {
// 将go应用构建名为app的可执行二进制文件
sh "go mod tidy"
//必须加CGO_ENABLED=0,因为alpine缺少很多go程序依赖的lib库,不加会提示你app not found,你需要ldd app才能看到需要依赖的lib库。
sh "CGO_ENABLED=0 go build -o app "
}
container('container-docker') {
sh """
echo "FROM ${params.harbor_url}/devops/alpine-golang-common:0.1" > ./Dockerfile
echo "ADD ./app /app/3rd/" >> ./Dockerfile
cat ./Dockerfile
"""
sh "docker build ./ -t ${params.harbor_url}/${params.harbor_group}/${image_name}:${image_tag}"
}
}
stage('stage-4.Push') {
container('container-docker') {
sh "docker push ${params.harbor_url}/${params.harbor_group}/${image_name}:${image_tag}"
}
}
stage('stage-5.Deploy') {
container('container-docker') {
writeFile(file: "k8s_yaml.yaml", text: "${k8s_yaml}")
sh "cat k8s_yaml.yaml"
sh "kubectl apply -f k8s_yaml.yaml"
}
}
}
}
3.执行构建
(3).语法注意事项
主要是流水线定义中的语法注意:
获取jenkins时间戳插件中的时间戳:
def image_tag = "${BUILD_TIMESTAMP}"
获取jenkins任务的隐藏变量的写法,如JOB_NAME:
def image_name = "${env.JOB_NAME}"
def app_name = "${env.JOB_NAME}"
获取参数化构建中定义的参数:
def harbor_url = "${params.harbor_url}"
将变量值写入磁盘文件:
writeFile(file: "k8s_yaml.yaml", text: "${k8s_yaml}")
(4).使用jenkinsfile的方式进行参数化构建
创建流水线job,从前边那个复制即可。
流水线定义选择:Pipeline script from SCM
配置完成后,执行构建。由于job_name起的名字太长,容器化时会报错:
这个不重要,可以自行修改,这里只是验证jenkinsfile中也是可以取到各种变量。
(5).参考资料
1.JenkinsPipeline语法概要
https://www.ssgeek.com/post/jenkinspipeline-yu-fa-gai-yao/#421-文件目录相关步骤