本实验操作需要:Jenkins,git代码仓库(如gitlab,gitee等都可以),maven,docker,docker镜像仓库(habor,nexus或者阿里云ACR等)以及k8s环境。
前期准备工作
本例需要Jenkins插件如下:
Git
Git Parameter
Git Pipeline for Blue Ocean
GitLab
Credentials
Credentials Binding
Blue Ocean
Blue Ocean Pipeline Editor
Blue Ocean Core JS
Pipeline SCM API for Blue Ocean
Dashboard for Blue Ocean
Build With Parameters
Dynamic Extended Choice Parameter Plug-In
Dynamic Parameter Plug-in
Extended Choice Parameter
List Git Branches Parameter
Pipeline
Pipeline: Declarative
Kubernetes
Kubernetes CLIKubernetes Credentials
Image Tag Parameter
Active Choices
安装完毕记得重启一下jenkins。
因为是实验环境,我这里直接拷贝一份杜宽老师的代码
杜宽/spring-boot-project放在我的代码仓库中。
- 添加docker镜像仓库的凭证:
- 在jenkins上添加git的ssh-key,每个代码仓库都会有指导创建,这里不赘述了,不了解的百度一下。
如果添加后拉取代码有提示错误信息 :
Failed to connect to repository : Command "git ls-remote -h git@GIT_URL:/home/git/www.git HEAD" returned status code 128: stdout: stderr: Permission denied, please try again. Permission denied, please try again. Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password). fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists.
在Manage Jenkins --> Configure Global Security 下有一个配置,这里的选项选择为No verification,即可解决。
- 在jenkins上添加k8s集群kebectl控制认证配置,一般路径在~/.kube/config。
创建Jenkinsfile
在代码仓库根下创建Jenkinsfile文件。
pipeline {
agent any
stages {
stage('Pulling Code') {
parallel {
stage('Pulling Code by Jenkins') {
when {
expression {
env.gitlabBranch == null
}
}
steps {
git(changelog: true, poll: true, url: 'git@gitcode.net:qq_39626154/spring-boot-project.git', branch: "${BRANCH}", credentialsId: 'git-ssh-key')
script {
COMMIT_ID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
TAG = BUILD_TAG + '-' + COMMIT_ID
println "Current branch is ${BRANCH}, Commit ID is ${COMMIT_ID}, Image TAG is ${TAG}"
}
}
}
stage('Pulling Code by trigger') {
when {
expression {
env.gitlabBranch != null
}
}
steps {
git(url: 'git@gitcode.net:qq_39626154/spring-boot-project.git', branch: env.gitlabBranch, changelog: true, poll: true, credentialsId: 'git-ssh-key')
script {
COMMIT_ID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
TAG = BUILD_TAG + '-' + COMMIT_ID
println "Current branch is ${env.gitlabBranch}, Commit ID is ${COMMIT_ID}, Image TAG is ${TAG}"
}
}
}
}
}
stage('Building') {
steps {
sh """
/usr/local/maven/bin/mvn clean install -DskipTests
ls target/*
"""
}
}
stage('Docker build for creating image') {
environment {
HARBOR_USER = credentials('HARBOR_ACCOUNT')
}
steps {
sh """
echo ${HARBOR_USER_USR} ${HARBOR_USER_PSW} ${COMMIT_ID} ${TAG}
docker build -t ${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${COMMIT_ID} .
docker login -u ${HARBOR_USER_USR} -p ${HARBOR_USER_PSW} ${HARBOR_ADDRESS}
docker push ${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${COMMIT_ID}
"""
}
}
stage('Deploying to K8s') {
environment {
MY_KUBECONFIG = credentials('study-k8s-kubeconfig')
}
steps {
sh """
/usr/local/bin/kubectl --kubeconfig $MY_KUBECONFIG set image deploy -l app=${IMAGE_NAME} ${IMAGE_NAME}=${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${COMMIT_ID} -n $NAMESPACE
"""
}
}
}
environment {
COMMIT_ID = ""
HARBOR_ADDRESS = "registry.cn-hangzhou.aliyuncs.com"
REGISTRY_DIR = "maodocker"
IMAGE_NAME = "spring-boot-project"
NAMESPACE = "kubernetes"
TAG = ""
}
parameters {
gitParameter(branch: '', branchFilter: 'origin/(.*)', defaultValue: '', description: 'Branch for build and deploy', name: 'BRANCH', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'PT_BRANCH')
}
}
创建Dockerfile
在执行流水线过程时,需要将代码的编译产物做成镜像。Dockerfile主要写的是如何生成公司业务的镜像,而本示例是Java项目,只需要把JAR包放在有JRE环境的镜像中,然后启动该JAR包即可:
# 基础镜像可以按需修改,可以更改为公司自有的镜像
FROM registry.cn-beijing.aliyuncs.com/dotbalo/jre:8u211-data
#JAR包名称改成实际的名称,本示例为spring-cloud-eureka-0.0.1-SNAPSHOT.jar
COPY target/spring-cloud-eureka-0.0.1-SNAPSHOT.jar ./
# 启动JAR包
CMD java -jar spring-cloud-eureka-0.0.1-SNAPSHOT.jar
定义 Kubernetes 资源
在GitLab创建的Group为kubernetes,可以认为其是一个项目,同一个项目可以部署至Kubernetes集群中的同一个Namespace中,本示例为kubernetes命名空间。由于使用的是私有仓库因此需要先配置拉取私有仓库镜像的密钥:
# kubectl create ns kubernetes
namespace/kubernetes created
# kubectl create secret docker-registry harborkey-docker-server=CHANGE HERE FOR YOUR HARBOR ADDRESS --docker-username=admin-docker-password=Harbor12345 --docker-email=mail@kubeasy.com -n kubernetes
secret/harborkey created
yaml文件app.yaml,资源限制部分请按照业务需求调整。
---
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: spring-boot-project
name: spring-boot-project
namespace: kubernetes
spec:
ports:
- name: web
port: 8761
protocol: TCP
targetPort: 8761
selector:
app: spring-boot-project
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
creationTimestamp: null
name: spring-boot-project
namespace: kubernetes
spec:
ingressClassName: nginx
rules:
- host: spring-boot-project.test.com
http:
paths:
- backend:
service:
name: spring-boot-project
port:
number: 8761
path: /
pathType: ImplementationSpecific
---
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: spring-boot-project
name: spring-boot-project
namespace: kubernetes
spec:
replicas: 1
selector:
matchLabels:
app: spring-boot-project
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: spring-boot-project
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- spring-boot-project
topologyKey: kubernetes.io/hostname
weight: 100
containers:
- env:
- name: TZ
value: Asia/Shanghai
- name: LANG
value: C.UTF-8
image: registry.cn-hangzhou.aliyuncs.com/maodocker/springboot-project:v0.0.1
imagePullPolicy: IfNotPresent
lifecycle: {}
livenessProbe:
failureThreshold: 2
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
tcpSocket:
port: 8761
timeoutSeconds: 2
name: spring-boot-project
ports:
- containerPort: 8761
name: web
protocol: TCP
readinessProbe:
failureThreshold: 2
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
tcpSocket:
port: 8761
timeoutSeconds: 2
resources:
limits:
cpu: 994m
memory: 1170Mi
requests:
cpu: 10m
memory: 55Mi
dnsPolicy: ClusterFirst
imagePullSecrets:
- name: harborkey
restartPolicy: Always
securityContext: {}
serviceAccountName: default
先再集群上部署该应用:
# kubectl apply -f app.yaml
创建Jenkins任务
点击Build Now,第一次构建之后会出现Build with Parameters就可以选择分支构建。
点击构建查看控制台输出: