由于jenkins 版本升级导致以前的功能不能用了。主要是 kubernetes-plugin 配置文件位置换了。导致以前的配置文件丢失,在实践中又发现比以前更好的实现方式。故重新写个新版教程。
该篇文件需要配合 基于K8S构建企业级Jenkins CI/CD平台实战(二) 之 kubernetes-plugin 插件使用 观看
jenkins 安装
参考 基于K8S构建企业级Jenkins CI/CD平台实战(一) 之 环境搭建
Jenkins定制Agent
可以使用我个人已经编译好的
docker pull andanyoung/kubectl-maven-agent
由于官方提供了简单的 jenkins-agent。 如果我们的打包流程需要用到git、Java、Maven、Kubernetes的话,我们也需要将这些集成到行的 jenkins-agent 中。 我们基于Jenkins的官方基础镜像进行定制,Dockerfile如下:
FROM jenkins/inbound-agent:latest-jdk8
ARG MAVEN_VERSION=3.6.3
ARG KUBECTL_VERSION=v1.22.3
# tool
USER root
RUN apt-get update && \
apt-get install -y curl && \
apt-get clean
# maven
RUN curl -OL https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz && \
tar -zxf ./apache-maven-${MAVEN_VERSION}-bin.tar.gz && \
mv apache-maven-${MAVEN_VERSION} /usr/local && \
rm -f apache-maven-${MAVEN_VERSION}-bin.tar.gz && \
ln -s /usr/local/apache-maven-${MAVEN_VERSION}/bin/mvn /usr/bin/mvn && \
ln -s /usr/local/apache-maven-${MAVEN_VERSION} /usr/local/apache-maven && \
mkdir -p /home/jenkins/.m2 && \
chown -R jenkins:jenkins /home/jenkins/.m2
# kubectl
RUN curl -OL https://storage.googleapis.com/kubernetes-release/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl && \
chmod +x ./kubectl && \
mv ./kubectl /usr/local/bin/kubectl && \
ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
echo $TZ > /etc/timezone
VOLUME [ "/home/jenkins/.m2" ]
USER jenkins
ENTRYPOINT ["/usr/local/bin/jenkins-agent"]
# docker build --build-arg KUBECTL_VERSION=v1.22.3 --build-arg MAVEN_VERSION=3.6.3 -t "andanyoung/kubectl-maven-agent" .
# docker push andanyoung/kubectl-maven-agent
inbound-agent 和 nlp-slave 的区别
Jenkins agent 官方 Docker 镜像重命名了 。
- jenkins/agent 镜像:原名称为jenkins/slave,从4.3-2 开始更名为
- jenkins/agentjenkins/inbound-agent 镜像:原名称为 jenkins/jnlp-slave ,从 4.3-2 开始更名为 jenkins/inbound-agent
- jenkins/ssh-agent 镜像:原名称为 jenkins/ssh-slave ,从 2.0.0 开始更名为 jenkins/ssh-agent
kubernetes-plugin 的使用
参考 基于K8S构建企业级Jenkins CI/CD平台实战(二) 之 kubernetes-plugin 插件使用
jenkins插件连接K8S配置
需要先安装pipeline插件, 建议不在 pipeline UI上配置pod创建模版,免得以后每来一个项目都要创建,管理不方便,建议使用pipeline统一 配置。
Kubernetes插件介绍:https://github.com/jenkinsci/kubernetes-plugin
配置路径 “系统管理” —> “系统设置” —> “云(翻到最后)” —> “Kubernetes”
新版已放到 “节点管理” -> “configureClouds” (> v2.343)
- Name 处默认为 kubernetes,也可以修改为其他名称,如果这里修改了,下边在执行 Job 时指定 podTemplate() 参数 cloud 为其对应名称,否则会找不到,cloud 默认值取:kubernetes
- Kubernetes URL jenkins找到 k8s的地址。 我填写了 https://kubernetes.default 这里我填写了 Kubernetes Service 对应的 DNS 记录,通过该 DNS 记录可以解析成该 Service 的 Cluster IP,注意:也可以填写 https://kubernetes.default.svc.cluster.local 完整 DNS 记录,因为它要符合 <svc_name>.<namespace_name>.svc.cluster.local 的命名方式,或者直接填写外部 Kubernetes 的地址 https://:。
- Jenkins URL 是k8s 访问jenkins地址。这里我填写了 http://jenkins.default / http://jenkins.ops (这里是jenkins service 地址带上了命名空间)。跟上边类似,也是使用 Jenkins Service 对应的 DNS 记录,不过要指定为 8080 端口,因为我们设置暴漏 8080 端口。同时也可以用 http://:<Node_Port> 方式,例如我这里可以填 http://192.168.99.100:30645 也是没有问题的,这里的 30645 就是对外暴漏的 NodePort。
注意 命名空间- Kubernetes 命名空间 可不写
测试并验证
通过 Kubernetes 安装 Jenkins Master 完毕并且已经配置好了连接,接下来,我们可以配置 Job 测试一下是否会根据配置的 Label 动态创建一个运行在 Docker Container 中的 Jenkins Slave 并注册到 Master 上,而且运行完 Job 后,Slave 会被注销并且 Docker Container 也会自动删除吧!
创建一个 Pipeline 类型 Job 并命名为 my-k8s-jenkins-pipeline,然后在 Pipeline 脚本处填写一个简单的测试脚本如下:
def label = "mypod-${UUID.randomUUID().toString()}"
podTemplate(label: label, cloud: 'kubernetes')
{
node(label) {
stage('Run shell') {
sh 'sleep 30s'
sh 'echo hello world.'
}
}
}
node(label ) 中的 label :匹配 node 配置 为 label的节点。
podTemplate(label) 中的 label: 定义 节点 node 运行 podTemplate 的 label ,也就是 节点node的 label
可以看出 podTemplate 和node 配置并没有相关,只需要label 相关联
创建 kubernetes pod tempalte
运行docker命令
在Kubernetes集群内部,Kubernetes映射/var/run/docker.sock(因此我们共享相同的Docker sock)。 将jenkins用户添加到默认docker用户组下, 从而保证jenkins可以直接访问/var/run/docker.sock
usermod -a -G docker jenkins
配置 kubernetes凭证
参考k8s 带你一步步 创建用户账号(User Account), 最终生成一个用户账号 和一个kube配置文件
#
测试Pipeline
podTemplate (inheritFrom: "maven-kubectl"){
node(POD_LABEL) {
stage('Run shell') {
sh 'echo hello world'
sh 'kubectl config view'
sh 'docker version'
}
stage('k8s') {
kubeconfig(credentialsId: '586b9f76-15d3-4d35-8c76-28e02b144ce9') {
sh 'kubectl config view'
sh "kubectl get pod -n prod"
}
}
}
}
采用配置文件的方式就不用写 serverUrl 了。因为配置文件就包含serverUrl
构建SpringBoot脚本
- 1.先在k8s里创建 deployment。yml如下
apiVersion: apps/v1
kind: Deployment
metadata:
name: ces-purchase
spec:
replicas: 3
selector:
matchLabels:
app: pod-purchase
template:
metadata:
labels:
app: pod-purchase
spec:
affinity:
# 反亲和性调度 使各个pod不在同个node里
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
topologyKey: kubernetes.io/hostname
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- pod-purchase
imagePullSecrets:
- name: harborregcred
containers:
- name: pod-ces-purchase
image: docker.aliuncle.top:8000/ces/ces-purchase-impl:1.1-SNAPSHOT
imagePullPolicy: Always
resources:
limits:
memory: 2G
requests:
memory: 2G
lifecycle:
postStart:
exec:
command:
- sleep
- 30s
preStop:
exec:
command:
- sh
- '-c'
- >-
curl -X "POST"
"http://localhost:8080/actuator/serviceregistry?status=DOWN"
-H "Content-Type:
application/vnd.spring-boot.actuator.v2+json;charset=UTF-8"
- sleep 30s
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
scheme: HTTP
initialDelaySeconds: 60
timeoutSeconds: 10
periodSeconds: 120
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
scheme: HTTP
initialDelaySeconds: 10
timeoutSeconds: 10
periodSeconds: 120
env:
- name: SW_AGENT_NAME
value: ces-purchase
- name: SW_AGENT_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: SW_AGENT_COLLECTOR_BACKEND_SERVICES
valueFrom:
configMapKeyRef:
name: skywalking-cm
key: skywalking.collector.backend_service
- 2.jenkins 只负责拉代码,打包,调用k8s更新方法
def k8s_deployment = project_name
//def run_env = "pre"
def app_name = project_name
//项目git 地址
def git_address = "http://git.***.com/ces/ces-application/${project_name}.git"
//项目git 分支地址
def git_branch = "prod"
//git 证书ID
def git_auth = "andnayang-git"
def docker_path = run_env == "pre" ? "ces_pre":"ces"
//打包镜像名称
def docker_image_name = "docker.**.top:8000/${docker_path}/${app_name}-impl"
//打包镜像tag
def docker_image_tag = BUILD_NUMBER
//docker registry 地址
def docker_registry = "docker.***.top:8000"
def docker_registry_auth = "a83fa85e-5753-484b-9076-79baa2d6d437"
def docker_host = "tcp://192.168.0.192:2375"
def APM_OPT = '${APM_OPT}'
podTemplate (inheritFrom: "maven-kubectl"){
node(POD_LABEL){
// 第一步
stage('拉取代码'){
git branch: "${git_branch}", credentialsId: "${git_auth}", url: "${git_address}"
}
// 第二步
stage('代码编译'){
sh "mvn clean package -Dmaven.test.skip=true -P${run_env}"
}
// 第三步
stage('构建镜像'){
//Harbor镜像仓库登录验证,
withCredentials([usernamePassword(credentialsId: "${docker_registry_auth}", passwordVariable: 'password', usernameVariable: 'username')]) {
sh """
echo '
FROM docker.***.top:8000/common/jdk8
MAINTAINER ***@qq.com
ENTRYPOINT /usr/bin/java -Djava.security.egd=file:/dev/./urandom -javaagent:/root/agent/skywalking-agent.jar ${APM_OPT} -jar app.jar
COPY ${app_name}-impl/target/${app_name}-impl.jar app.jar
' > Dockerfile
export DOCKER_HOST="${docker_host}"
docker login -u ${username} -p ${password} ${docker_registry}
docker build -t ${docker_image_name}:${docker_image_tag} .
docker push ${docker_image_name}:${docker_image_tag}
"""
}
}
// 第四步
stage('部署到K8S平台'){
kubeconfig(credentialsId: '586b9f76-15d3-4d35-8c76-28e02b144ce9') {
// sh "kubectl rollout restart -n ${run_env} deployment ${k8s_deployment}"
sh "kubectl set image deployments/${app_name} pod-${app_name}=${docker_image_name}:${docker_image_tag} -n ${run_env}"
}
//sh 'kubectl config view'
//sh "kubectl set image deployments/hello-k8s pod-hello-k8s=andanyoung/springboot-hello:${docker_image_tag} -n pre"
}
}
}
上游jenkins 并发构建
- 配置
- pipeline
pipeline {
agent any
stages {
stage('deploy stage') {
steps {
script{
//把选择的项目信息转为数组
def selectedProjects = "${project_name}".split(',')
for (job in selectedProjects){
echo "${job} 正在构建发布"
build wait: false, propagate: false, job: 'ces-application', parameters: [string(name: 'project_name', value: "${job}"), string(name: 'run_env', value: 'prod')]
// build wait: false, propagate: false, job: "${job}"
// 传入gitParameter参数 $mbranch为本次pipeline流水线执行时传入的参数,然后将参数值 传入给每个执行构建任务中
echo "${job} 完成构建发布."
}
}
}
}
}
}
- 效果
参考
- http://idcsec.com/2019/03/27/%E7%94%A8jenkins%E5%8A%A8%E6%80%81%E4%BC%B8%E7%BC%A9%E5%92%8Ckubernetes%E4%B8%BA%E5%BA%94%E7%94%A8%E8%AE%BE%E7%BD%AEci-cd-%E6%B5%81%E7%A8%8B/
- https://www.coder4.com/homs_online/ch06-cd/jenkins-k8s-optimize.html