Kubernetes CI/CD(2)
本章节通过在Jenkins创建一个kubernetes云环境,动态的在kubernetes集群中创建pod完成pipeline的构建流程,关于直接在宿主机上搭建Jenkins集群的可参照Kubernetes CI/CD(1)
部署Jenkins
下载Jenkins对应的镜像
docker pull jenkins/jenkins:2.221
将jenkins镜像上传到自己的私有镜像仓库中
docker tag jenkins/jenkins:2.221 192.168.0.107/k8s/jenkins:2.221 docker push 192.168.0.107/k8s/jenkins:2.221
编写启动Jenkins的yml文件
cat > jenkins.yml << EOF
kind: PersistentVolume
apiVersion: v1
metadata:
name: jenkins
labels:
type: local
app: jenkins
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /opt/k8s/yml/jenkins/data
--- kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: jenkins-claim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
--- apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins
namespace: default
automountServiceAccountToken: true
--- apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: Jenkins-cluster-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: jenkins
namespace: default
--- apiVersion: v1
kind: Service
metadata:
name: jenkins
labels:
app: jenkins
spec:
ports:
- port: 80
targetPort: 8080
nodePort: 8888
name: jenkins
- port: 50000
targetPort: 50000
nodePort: 50000
name: agent
selector:
app: jenkins
tier: jenkins
type: NodePort
--- apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins
labels:
app: jenkins
spec:
strategy:
type: Recreate
selector:
matchLabels:
app: jenkins
tier: jenkins
template:
metadata:
labels:
app: jenkins
tier: jenkins
spec:
serviceAccountName: jenkins
containers:
- image: 192.168.0.107/k8s/jenkins:2.221
imagePullPolicy: IfNotPresent
name: jenkins
securityContext:
privileged: true
runAsUser: 0
volumeMounts:
- name: kubeconfig
mountPath: /var/jenkins_home/.kube
- name: docker
mountPath: /var/run/docker.sock
- name: docker-bin
mountPath: /usr/bin/docker
- name: jenkins-persistent-storage
mountPath: /var/jenkins_home
ports:
- containerPort: 8080
name: jenkins
- containerPort: 50000
name: agent
volumes:
- name: kubeconfig
emptyDir: {}
- name: docker
hostPath:
path: /var/run/docker.sock
- name: docker-bin
hostPath:
path: /opt/k8s/bin/docker
- name: jenkins-persistent-storage
persistentVolumeClaim:
claimName: jenkins-claim
EOF
安装 kubernetes相关插件
kubernetes-cd
kubernetes-client-api
kubernetes-credentials
kubernetes
配置kubernetes云(配置详情官方网站kubernetes-plugin)
新加一个Cloud
在Jenkins界面执行Manage Jenkins -> Manage Nodes and Clouds -> Configure Clouds -> Add a new Cloud
配置cloud,点击Kubernetes Cloud details
- Kubernetes 地址:指定要连接的k8s集群API地址,因为我们master是在k8s集群中启动的,所以此处可以直接用https://kubernetes.default.svc.cluster.local,其中kubernetes是k8s集群给我们启动的一个service,内部会把对他的访问转发给API server,如果Jenkins不在k8s集群中,或者想要启动的构建pod和master不是一个集群,这个地方就需要相应的k8s集群地址
- 凭据:访问k8s集群的认证凭证,我们启动Jenkins集群时同时创建了Service account,并赋给了Jenkins容器,所以这个地方可以直接创建一个service count类型的凭据,如果是访问其他集群,需要用服务证书key来配置
配置好后点击:连接测试,正常的话会出现Connection test successful的提示
配置Jenkins相关信息(主要是agent和master通信的信息)
- Jenkins 地址: 连接jenkins master的地址,因为我们jenkins对应的service启动节点是80,所以这个地方就去掉了端口号,并且service也启动了50000端口映射到容器的50000,所以直接配置成http://jenkins
构建一个简单的流水线验证cloud的构建功能
在Jenkins界面新建一个item,名称hello-pipeline-cloud, 类型选择:流水线(pipeline)
编辑pipeline部分
podTemplate(cloud: "kubernetes") {
node(POD_LABEL) { stage('Run shell') {
sh 'echo hello world'
} }
}- cloud: "kubernetes",指定执行的云环境,默认是kubernetes,所以这个地方可以省略,当有多个云环境或者我们创建的cloud名称不是kubernetes则需要明确指定
- POD_LABEL 是在1.17.0版本后引入的一个新特性,可以自动对创建的pod进行打标签
执行构建
首先我们可以在要执行的k8s集群上执行如下命令观察执行构建过程中k8s云给我做了什么事
kubectl get pod -w
在Jenkins界面选择刚创建的工程,点击 Build Now
对应的集群的输出
root@master:/opt/k8s/yml/jenkins# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
jenkins-68d8b54c45-gshvp 1/1 Running 0 60m
hello-pipeline-cloud-9-7n3c4-8stzj-n8g6v 0/1 Pending 0 0s
hello-pipeline-cloud-9-7n3c4-8stzj-n8g6v 0/1 Pending 0 0s
hello-pipeline-cloud-9-7n3c4-8stzj-n8g6v 0/1 ContainerCreating 0 0s
hello-pipeline-cloud-9-7n3c4-8stzj-n8g6v 1/1 Running 0 1s
hello-pipeline-cloud-9-7n3c4-8stzj-n8g6v 1/1 Terminating 0 7s
hello-pipeline-cloud-9-7n3c4-8stzj-n8g6v 0/1 Terminating 0 8s
hello-pipeline-cloud-9-7n3c4-8stzj-n8g6v 0/1 Terminating 0 9s
hello-pipeline-cloud-9-7n3c4-8stzj-n8g6v 0/1 Terminating 0 9s可以看到k8s集群给我们创建了一个新的pod:hello-pipeline-cloud-9-7n3c4-8stzj-n8g6v,构建完成后会自动把这个pod停掉
Jenkins构建的日志
Started by user admin
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] podTemplate
[Pipeline] {
[Pipeline] node
Still waiting to schedule task
All nodes of label ‘hello-pipeline-cloud_9-7n3c4’ are offline
Created Pod: hello-pipeline-cloud-9-7n3c4-8stzj-n8g6v in namespace default
Agent hello-pipeline-cloud-9-7n3c4-8stzj-n8g6v is provisioned from template hello-pipeline-cloud_9-7n3c4-8stzj
---
apiVersion: "v1"
kind: "Pod"
metadata:
annotations:
buildUrl: "http://jenkins/job/hello-pipeline-cloud/9/"
runUrl: "job/hello-pipeline-cloud/9/"
labels:
jenkins: "slave"
jenkins/label: "hello-pipeline-cloud_9-7n3c4"
name: "hello-pipeline-cloud-9-7n3c4-8stzj-n8g6v"
spec:
containers:
- env:
- name: "JENKINS_SECRET"
value: "********"
- name: "JENKINS_AGENT_NAME"
value: "hello-pipeline-cloud-9-7n3c4-8stzj-n8g6v"
- name: "JENKINS_NAME"
value: "hello-pipeline-cloud-9-7n3c4-8stzj-n8g6v"
- name: "JENKINS_AGENT_WORKDIR"
value: "/home/jenkins/agent"
- name: "JENKINS_URL"
value: "http://jenkins/"
image: "jenkins/jnlp-slave:3.35-5-alpine"
name: "jnlp"
volumeMounts:
- mountPath: "/home/jenkins/agent"
name: "workspace-volume"
readOnly: false
nodeSelector:
beta.kubernetes.io/os: "linux"
restartPolicy: "Never"
securityContext: {}
volumes:
- emptyDir:
medium: ""
name: "workspace-volume" Running on hello-pipeline-cloud-9-7n3c4-8stzj-n8g6v in /home/jenkins/agent/workspace/hello-pipeline-cloud
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Run shell)
[Pipeline] sh
+ echo hello world
hello world
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // podTemplate
[Pipeline] End of Pipeline
Finished: SUCCESS从日志中可以看到k8s集群采用默认的pod模版给我启动了一个pod,并且把我们的构建内容sh 'echo hello world'在pod对应的容器中执行了
如果默认的模版不能满足我们的要求(比如在内网工作,对应的image想用我们自己私有仓库中的镜像可以重写name是jnlp的容器模版)后面一个例子,我们会重写这个模版,并在我们自定义的容器中执行我们的构建
构建自定义podtemplage
在Jenkins界面新建一个item,名称hello-pipeline-selfpodtemplate, 类型选择:流水线(pipeline)
编辑pipeline部分
podTemplate(yaml: """
apiVersion: v1
kind: Pod
metadata:
labels:
app: busybox
spec:
containers:
- name: busybox
image: 192.168.0.107/k8s/busybox:latest
command:
- cat
tty: true
"""
,containers: [containerTemplate(name: 'jnlp', image: '192.168.0.107/jenkins/jnlp-slave:3.35-5-alpine')]
,cloud: "kubernetes") {
node(POD_LABEL) {
container('busybox') {
sh "hostname"
}
}
}- yaml 通过这个字段,我们定义了一个自己的podtemplate,容器名称是busybox,并在后面使用
- containers的containerTemplate,我们重写了jnlp容器启动的镜像名称。jnlp镜像必须启动,他要和jenkins master通信,来告知构建状态,并且不能配置其它容器模版的名称为jnlp,否则会造成构建一直不会结束
- 具体的构建流程,我们通过container('busybox')指定了构建要执行的容器,这个地方我们可以根据要构建的类型,配置maven、gradle、docker等各种构建环境来配置不同的podtemplate以此满足不同的构建需求,这也是用云环境进行构建的优势
同样,我们看下k8s集群的pod创建情况
root@master:/opt/k8s/yml/jenkins# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
jenkins-68d8b54c45-gshvp 1/1 Running 0 83m hello-pipeline-selfpodtemplate-6-ch89k-0v48m-xxsqw 0/2 Pending 0 0s
hello-pipeline-selfpodtemplate-6-ch89k-0v48m-xxsqw 0/2 Pending 0 0s
hello-pipeline-selfpodtemplate-6-ch89k-0v48m-xxsqw 0/2 ContainerCreating 0 0s
hello-pipeline-selfpodtemplate-6-ch89k-0v48m-xxsqw 2/2 Running 0 2s
hello-pipeline-selfpodtemplate-6-ch89k-0v48m-xxsqw 2/2 Terminating 0 7s看到这次k8s集群创建的pod包含了两个容器,如果我们describe这个pod可以看到里面是我们指定的容器
Jenkins日志
Started by user admin
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] podTemplate
[Pipeline] {
[Pipeline] node
Created Pod: hello-pipeline-selfpodtemplate-6-ch89k-0v48m-xxsqw in namespace default
Still waiting to schedule task
Waiting for next available executor on ‘hello-pipeline-selfpodtemplate-6-ch89k-0v48m-xxsqw’
Agent hello-pipeline-selfpodtemplate-6-ch89k-0v48m-xxsqw is provisioned from template hello-pipeline-selfpodtemplate_6-ch89k-0v48m
---
apiVersion: "v1"
kind: "Pod"
metadata:
annotations:
buildUrl: "http://jenkins/job/hello-pipeline-selfpodtemplate/6/"
runUrl: "job/hello-pipeline-selfpodtemplate/6/"
labels:
app: "busybox"
jenkins: "slave"
jenkins/label: "hello-pipeline-selfpodtemplate_6-ch89k"
name: "hello-pipeline-selfpodtemplate-6-ch89k-0v48m-xxsqw"
spec:
containers:
- command:
- "cat"
image: "192.168.0.107/k8s/busybox:latest"
name: "busybox"
tty: true
volumeMounts:
- mountPath: "/home/jenkins/agent"
name: "workspace-volume"
readOnly: false
- env:
- name: "JENKINS_SECRET"
value: "********"
- name: "JENKINS_AGENT_NAME"
value: "hello-pipeline-selfpodtemplate-6-ch89k-0v48m-xxsqw"
- name: "JENKINS_NAME"
value: "hello-pipeline-selfpodtemplate-6-ch89k-0v48m-xxsqw"
- name: "JENKINS_AGENT_WORKDIR"
value: "/home/jenkins/agent"
- name: "JENKINS_URL"
value: "http://jenkins/"
image: "192.168.0.107/jenkins/jnlp-slave:3.35-5-alpine"
imagePullPolicy: "IfNotPresent"
name: "jnlp"
resources:
limits: {}
requests: {}
securityContext:
privileged: false
tty: false
volumeMounts:
- mountPath: "/home/jenkins/agent"
name: "workspace-volume"
readOnly: false
nodeSelector:
beta.kubernetes.io/os: "linux"
restartPolicy: "Never"
securityContext: {}
volumes:
- emptyDir:
medium: ""
name: "workspace-volume" Running on hello-pipeline-selfpodtemplate-6-ch89k-0v48m-xxsqw in /home/jenkins/agent/workspace/hello-pipeline-selfpodtemplate
[Pipeline] {
[Pipeline] container
[Pipeline] {
[Pipeline] sh
+ hostname
hello-pipeline-selfpodtemplate-6-ch89k-0v48m-xxsqw
[Pipeline] }
[Pipeline] // container
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // podTemplate
[Pipeline] End of Pipeline
Finished: SUCCESS- 可以看到jnlp对应的镜像名称变成我们指定的镜像
- pod template 的内容默认是打印出来的,可以通过配置不显示 podTemplate(showRawYaml:false,...)
遇到问题
追加kubernetes service account凭据时报错
HTTP ERROR 403 No valid crumb was included in the request
简单解决方法,在Configure Global Security配置页面去掉CSRF Protection
Kubernetes CI/CD(2)的更多相关文章
- Kubernetes CI/CD(1)
本文通过在kubernetes上启动Jenkins服务,并将宿主机上的docker.docker.sock挂载到Jenkins容器中,实现在Jenkins容器中直接打镜像的形式实现CI功能. Kube ...
- Kubernetes学习之路(二)之ETCD集群二进制部署
ETCD集群部署 所有持久化的状态信息以KV的形式存储在ETCD中.类似zookeeper,提供分布式协调服务.之所以说kubenetes各个组件是无状态的,就是因为其中把数据都存放在ETCD中.由于 ...
- Kubernetes学习之路(十)之资源清单定义
一.Kubernetes常用资源 以下列举的内容都是 kubernetes 中的 Object,这些对象都可以在 yaml 文件中作为一种 API 类型来配置. 类别 名称 工作负载型资源对象 Pod ...
- Kubernetes 部署Web UI (Dashboard)
Kubernetes 部署Web UI (Dashboard) 项目下载地址:https://github.com/kubernetes/kubernetes/tree/master/cluster/ ...
- CI框架浅析(二)
该文延续上篇文章: CI框架浅析(一) 在CI框架的核心库中,CodeIgniter.php负责加载所有需要的类库,第一个加载的是公共库 core/Common.php Common.php 负责加载 ...
- kubernetes集群搭建(2):docker私有仓库
kubernetes集群搭建(1):环境准备 中各节点已经安装好了docker,请确认docker已启动并正常运行 1.通过命令启动私库 docker run -d -p 5000:5000 --pr ...
- 浅谈 kubernetes service 那些事(上篇)
一.问题 首先,我们思考这样一个问题: 访问k8s集群中的pod, 客户端需要知道pod地址,需要感知pod的状态.那如何获取各个pod的地址?若某一node上的pod故障,客户端如何感知? 二.k8 ...
- 浅谈 kubernetes service 那些事 (下篇)
欢迎访问网易云社区,了解更多网易技术产品运营经验. 五.K8s 1.8 新特性--ipvs ipvs与iptables的性能差异 随着服务的数量增长,IPTables 规则则会成倍增长,这样带来的问题 ...
- Kubernetes学习之路(一)之概念和架构解析和证书创建和分发
1.Kubernetes的重要概念 转自:CloudMan老师公众号<每天5分钟玩转Kubernetes>https://item.jd.com/26225745440.html Clus ...
随机推荐
- ubuntu 16.10 shu rufa meiy ou l e geng xi zhi hou
- Frameworks.Entity.Core 7
1描述:实体基类,与业务和架构无关名称:EntityBase属性:public abstract 2描述:/ MongoDB的一些扩展方法名称:MongoExtensions修饰: public st ...
- tomcat梳理
tomcat梳理 Tomcat的缺省端口是多少,怎么修改? 默认接口是8080 修改 1)找到Tomcat目录下的conf文件夹 2)进入conf文件夹里面找到server.xml文件 3)打开ser ...
- vscode写python时的代码错误提醒和自动格式化
python的代码错误检查通常用pep8.pylint和flake8,自动格式化代码通常用autopep8.yapf.black.这些工具均可以利用pip进行安装,这里介绍传统的利用pip.exe安装 ...
- ros之自定义服务数据
如何自定义服务数据 string name Uint8 age Uint8 sex Uint8 unknown =0 Uint8 male =1 Uint8 female = 2 (上面的是Reque ...
- Linux之时间同步操作
Linux之时间同步操作 时间同步操作应用的命令 yum进行软件安装,软件安装过程中如遇到询问,一律选择y,ntp是时间同步命令 [root@localhost ~]# yum -y install ...
- 通过欧拉计划学Rust编程(第54题)
由于研究Libra等数字货币编程技术的需要,学习了一段时间的Rust编程,一不小心刷题上瘾. 刷完欧拉计划中的63道基础题,能学会Rust编程吗? "欧拉计划"的网址: https ...
- 视觉slam十四讲课后习题ch3-7
题目回顾: 设有小萝卜一号和小萝卜二号位于世界坐标系中,小萝卜一号的位姿为:q1=[0.35,0.2,0.3,0.1],t2=[0.3,0.1,0.1]^T (q的第一项为实部.请你把q归一化后在进行 ...
- C++标准模板库(STL)学习笔记
C++标准模板库(STL) 一.vector(变长数组) 1.使用vector #include <vector> using namespace std; 2.vector的定义 vec ...
- The current test process
样机测试 测试前: 工作内容: 1.需求分析.编写.评审: 项目开工会由项目负责人参加,参加会议时做好笔记,对项目的功能类似,功能模块,测试时间点有个大致的了解. 原始需求进行需求文档细化:按照模块进 ...