1. 传统架构与K8S 架构的区别

(1). 传统Master/Slave架构,Master收到Job后,将请求转发到Slave节点处理。Slave节点数固定,Slave节点未能自动申缩容。

(2). K8S中Jenkins Master/Slave架构,Master收到Job后,会自动创建Slave节点处理此Job,根据客户端的Job自动申缩容。

Jenkins的kubernetes-plugin在执行构建时会在kubernetes集群中自动创建一个Pod,并在Pod内部创建一个名为jnlp的容器,该容器会连接Jenkins并运行Agent程序,形成一个Jenkins的Master和Slave架构,然后Slave会执行构建脚本进行构建。如果要在集群集群内部进行部署操作可以使用kubectl执行命令,要解决kubectl的安装和权限分配问题。

因为默认的jnlp容器可以执行的命令比较少,所以要实现执行kubectl命令,就要自定义构建Docker Image,因为一个Pod内部可以运行多个容器,所以可以用自定义的Docker容器实现上述目的(下放实现)。

2. jenkins插件连接K8S配置

需要先安装pipeline插件, 建议不在 pipeline UI上配置pod创建模版,免得以后每来一个项目都要创建,管理不方便,建议使用pipeline统一 配置。
Kubernetes插件介绍:https://github.com/jenkinsci/kubernetes-plugin
配置路径 “系统管理” —> “系统设置” —> “云(翻到最后)” —> “Kubernetes”

  1. Name 处默认为 kubernetes,也可以修改为其他名称,如果这里修改了,下边在执行 Job 时指定 podTemplate() 参数 cloud 为其对应名称,否则会找不到,cloud 默认值取:kubernetes
  2. Kubernetes URL 处我填写了 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://<ClusterIP>:<Ports>
  3. Jenkins URL 处我填写了 http://jenkins.default,跟上边类似,也是使用 Jenkins Service 对应的 DNS 记录,不过要指定为 8080 端口,因为我们设置暴漏 8080 端口。同时也可以用 http://<ClusterIP>:<Node_Port> 方式,例如我这里可以填 http://192.168.99.100:30645 也是没有问题的,这里的 30645 就是对外暴漏的 NodePort。

3.测试并验证

通过 Kubernetes 安装 Jenkins Master 完毕并且已经配置好了连接,接下来,我们可以配置 Job 测试一下是否会根据配置的 Label 动态创建一个运行在 Docker Container 中的 Jenkins Slave 并注册到 Master 上,而且运行完 Job 后,Slave 会被注销并且 Docker Container 也会自动删除吧!

4.pipeline 类型支持

创建一个 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

可以看出 podTemplatenode 配置并没有相关,只需要label 相关联

执行构建,此时去构建队列里面,可以看到有一个构建任务,暂时还没有执行中的构建,因为还没有初始化好,稍等一会,就会看到 Master 和 jenkins-slave-jbs4z-xs2r8 已经创建完毕,在等一会,就会发现 jenkins-slave-jbs4z-xs2r8 已经注册到 Master 中,并开始执行 Job,点击该 Slave 节点,我们可以看到通过标签 mypod-b538c04c-7c19-4b98-88f6-9e5bca6fc9ba 关联,该 Label 就是我们定义的标签格式生成的,Job 执行完毕后,jenkins-slave 会自动注销,我们通过 kubectl 命令行,可以看到整个自动创建和删除过程。

5. Container Group 类型支持

创建一个 Pipeline 类型 Job 并命名为 my-k8s-jenkins-container,然后在 Pipeline 脚本处填写一个简单的测试脚本如下:

def label = "mypod-${UUID.randomUUID().toString()}"
podTemplate(label: label, cloud: 'kubernetes', containers: [containerTemplate(name: 'maven', image: 'maven:3.3.9-jdk-8-alpine', ttyEnabled: true, command: 'cat'),]) {node(label) {stage('Get a Maven Project') {git 'https://github.com/jenkinsci/kubernetes-plugin.git'container('maven') {stage('Build a Maven project') {sh 'mvn -B clean install'}}}}
}

注意:这里我们使用的 containers 定义了一个 containerTemplate 模板,指定名称为 maven 和使用的 Image,下边在执行 Stage 时,使用 container('maven'){...} 就可以指定在该容器模板里边执行相关操作了。比如,该示例会在 jenkins-slave 中执行 git clone 操作,然后进入到 maven 容器内执行 mvn -B clean install 编译操作。这种操作的好处就是,我们只需要根据代码类型分别制作好对应的编译环境镜像,通过指定不同的 container 来分别完成对应代码类型的编译操作。模板详细的各个参数配置可以参照 Pod and container template configuration

执行构建,跟上边 Pipeline 类似,也会新建 jenkins-slave 并注册到 master,不同的是,它会在 Kubernetes 中启动我们配置的 maven 容器模板,来执行相关命令。

Console Output

生成的 yaml 文件

apiVersion: "v1"
kind: "Pod"
metadata:annotations:buildUrl: "http://jenkins.ops.svc.cluster.local/job/maven/7/"runUrl: "job/maven/7/"labels:jenkins: "slave"jenkins/label-digest: "42a877c388ee17d414289d422ca60f5fd36ac08f"jenkins/label: "mypod-75997681-42e1-4ed6-bd02-8ac5df191d4f"name: "mypod-75997681-42e1-4ed6-bd02-8ac5df191d4f-h8pqj-bnj15"
spec:containers:- command:- "cat"image: "maven:3.3.9-jdk-8-alpine"imagePullPolicy: "IfNotPresent"name: "maven"resources:limits: {}requests: {}tty: truevolumeMounts:- mountPath: "/home/jenkins/agent"name: "workspace-volume"readOnly: false- env:- name: "JENKINS_SECRET"value: "********"- name: "JENKINS_AGENT_NAME"value: "mypod-75997681-42e1-4ed6-bd02-8ac5df191d4f-h8pqj-bnj15"- name: "JENKINS_NAME"value: "mypod-75997681-42e1-4ed6-bd02-8ac5df191d4f-h8pqj-bnj15"- name: "JENKINS_AGENT_WORKDIR"value: "/home/jenkins/agent"- name: "JENKINS_URL"value: "http://jenkins.ops.svc.cluster.local/"image: "jenkins/inbound-agent:4.11-1-jdk11"name: "jnlp"resources:limits: {}requests:memory: "256Mi"cpu: "100m"volumeMounts:- mountPath: "/home/jenkins/agent"name: "workspace-volume"readOnly: falsenodeSelector:kubernetes.io/os: "linux"restartPolicy: "Never"volumes:- emptyDir:medium: ""name: "workspace-volume"

可以看到一个pod下面有两个 docker启动了。一个是默认的jnlp(jenkins slave agent)另外一个是我们配置的 maven。jnlp 负责与jenkins master 通讯,maven 负责打包。

6.非 Pipeline 类型支持

jenkins 中除了使用 Pipeline 方式运行 Job 外,通常我们也会使用普通类型 Job,如果也要想使用kubernetes plugin 来构建任务,那么就需要点击 “系统管理” —> “系统设置” —> “云” —> “Kubernetes” —> “Add Pod Template” 进行配置 “Kubernetes Pod Template” 信息。

注意:这里的 Labels 名在配置非 pipeline 类型 Job 时,用来指定任务运行的节点。Containers 下的 Name 字段的名字,这里要注意的是,如果 Name 配置为 jnlp,那么 Kubernetes 会用下边指定的 Docker Image 代替默认的 jenkinsci/jnlp-slave 镜像,否则,Kubernetes plugin 还是会用默认的 jenkinsci/jnlp-slave 镜像与 Jenkins Server 建立连接,即使我们指定其他 Docker Image。这里我随便配置为 jnlp-slave,意思就是使用默认的 jenkinsci/jnlp-slave 镜像来运行,因为我们暂时还没制作可以替代默认镜像的镜像。

新建一个自由风格的 Job 名称为 my-k8s-jenkins-simple,配置 “Restrict where this project can be run” 勾选,在 “Label Expression” 后边输出我们上边创建模板是指定的 Labels 名称 jnlp-agent,意思是指定该 Job 匹配 jnlp-agent 标签的 Slave 上运行。

7. 配置自定义 jenkins-slave 镜像

通过 kubernetest plugin 默认提供的镜像 jenkinsci/jnlp-slave 可以完成一些基本的操作,它是基于 openjdk:8-jdk 镜像来扩展的,但是对于我们来说这个镜像功能过于简单,比如我们想执行 Maven 编译或者其他命令时,就有问题了,那么可以通过制作自己的镜像来预安装一些软件,既能实现 jenkins-slave 功能,又可以完成自己个性化需求,那就比较不错了。如果我们从头开始制作镜像的话,会稍微麻烦些,不过可以参考 jenkinsci/jnlp-slave 和 jenkinsci/docker-slave 这两个官方镜像来做,注意:jenkinsci/jnlp-slave 镜像是基于 jenkinsci/docker-slave 来做的。这里我简单演示下,基于 jenkinsci/jnlp-slave:latest 镜像,在其基础上做扩展,安装 Maven 到镜像内,然后运行验证是否可行吧。

创建一个 Pipeline 类型 Job 并命名为 my-k8s-jenkins-container-custom,然后在 Pipeline 脚本处填写一个简单的测试脚本如下:

def label = "mypod-${UUID.randomUUID().toString()}"
podTemplate(label: label, cloud: 'kubernetes',containers: [containerTemplate(name: 'jnlp', image: 'andanyoung/jenkins-slave-maven:latest', alwaysPullImage: false, args: '${computer.jnlpmac} ${computer.name}'),]) {node(label) {stage('stage1') {stage('Show Maven version') {sh 'mvn -version'sh 'sleep 60s'}}}
}

说明一下:这里 containerTemplate 的name 属性必须叫 jnlp ,Kubernetes 才能用自定义 images 指定的镜像替换默认的 jenkinsci/jnlp-slave 镜像。此外,args 参数传递两个 jenkins-slave 运行需要的参数。还有一点就是这里并不需要指定 container('jnlp'){...} 了,因为它被 Kubernetes 指定了要被执行的容器,所以直接执行 Stage 就可以了。

最后,贴一下我自定义的预安装了 Maven 的 Jenkins-slave 镜像的 Dockerfile,当然大家可以基于此预安装一些其他软件,来完成日常持续构建与发布工作吧。

当然也可以直接使用我的 andanyoung/jenkins-slave-maven 镜像

# Dockerfile
FROM jenkins/jnlp-slave:latestLABEL Author  andanyangLABEL Description "This is a extend image base from jenkins/jnlp-slave which install maven in it."# 切换到 root 账户进行操作
USER root
VOLUME [ "/home/jenkins/.m2" ]ARG MAVEN_VERSION=3.8.2
# 安装 maven https://archive.apache.org/dist/maven/maven-3/3.8.2/binaries/apache-maven-3.8.2-bin.tar.gz
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-mavenUSER jenkins## docker build --build-arg MAVEN_VERSION=3.8.2  -t andanyoung/jenkins-slave-maven:3.8.2 .
## docker push andanyoung/jenkins-slave-maven:3.8.2

3. 使用 Pod Templates

为了方便配置一个Pod Templates,在配置kubernetes连接内容的下面,这里的模板只是模板(与类一样使用时还要实例化过程),名称和标签列表不要以为是Pod的name和label,这里的名称和标签列表只是Jenkins查找选择模板时使用的,Jenkins自动创建Pod的name是项目名称+随机字母的组合,所以我们填写jnlp-maven,命名空间填写ops(创建命令:kubectl create namespace ops),Pod内添加一个容器名称是 jnlp (替换掉默认的自动创建jnlp容器),Docker镜像填写:andanyoung/jenkins-slave-maven,也可以是私服地址(搭建Docker私有仓库),下面增加m2maven仓库的持久化 PVC 配置 用户保存 maven 的 setting.xml 配置文件和 本地仓库,保存回到系统管理页面。

如果使用的是私服需要设置 Image pull Secret(生成 Image pull Secret https://andyoung.blog.csdn.net/article/details/120313644 )

  • setting.xml 文件示例(将其放入pvc-maven-m2中)
<?xml version="1.0" encoding="UTF-8"?><settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"><pluginGroups></pluginGroups><proxies></proxies><servers></servers><mirrors><mirror><id>central</id><mirrorOf>central</mirrorOf><name>aliyun maven</name><url>https://maven.aliyun.com/repository/public</url></mirror></mirrors><profiles></profiles></settings>

测试运行

podTemplate (inheritFrom: "jnlp-maven"){node(POD_LABEL) {container('jnlp'){stage('Run shell') {sh 'echo hello world'sh 'mvn -version'}}}
}
  • podTemplate:用Pod模版实例化一个Pod配置并在kubernetes内自动创建
  • inheritFrom:意思是创建的Pod配置继承自jnlp-maven模版
  • POD_LABEL:自动创建Pod的label
  • container:选择哪个容器执行脚本(默认就是 jnlp,container('jnlp'){..} 最外层可以不写)

执行构建结果:

[Pipeline] Start of Pipeline
[Pipeline] podTemplate
[Pipeline] {
[Pipeline] node
Created Pod: kubernetes ops/maven-13-pbvhr-xbdq3-wb3j8
[Normal][ops/maven-13-pbvhr-xbdq3-wb3j8][Scheduled] Successfully assigned ops/maven-13-pbvhr-xbdq3-wb3j8 to a3
[Normal][ops/maven-13-pbvhr-xbdq3-wb3j8][Pulled] Container image "andanyoung/jenkins-slave-maven" already present on machine
[Normal][ops/maven-13-pbvhr-xbdq3-wb3j8][Created] Created container jnlp
[Normal][ops/maven-13-pbvhr-xbdq3-wb3j8][Started] Started container jnlp
Agent maven-13-pbvhr-xbdq3-wb3j8 is provisioned from template maven_13-pbvhr-xbdq3
---
apiVersion: "v1"
kind: "Pod"
metadata:annotations:buildUrl: "http://jenkins.ops.svc.cluster.local/job/maven/13/"runUrl: "job/maven/13/"labels:jenkins: "slave"jenkins/label-digest: "a3166022e7be1cbf48366e0c0ffece53242411af"jenkins/label: "maven_13-pbvhr"name: "maven-13-pbvhr-xbdq3-wb3j8"
spec:containers:- env:- name: "JENKINS_SECRET"value: "********"- name: "JENKINS_AGENT_NAME"value: "maven-13-pbvhr-xbdq3-wb3j8"- name: "JENKINS_NAME"value: "maven-13-pbvhr-xbdq3-wb3j8"- name: "JENKINS_AGENT_WORKDIR"value: "/home/jenkins/agent"- name: "JENKINS_URL"value: "http://jenkins.ops.svc.cluster.local/"image: "andanyoung/jenkins-slave-maven"imagePullPolicy: "IfNotPresent"name: "jnlp"resources:limits:memory: "1Gi"cpu: "1"requests: {}tty: falsevolumeMounts:- mountPath: "/home/jenkins/.m2"name: "volume-0"readOnly: false- mountPath: "/home/jenkins/agent"name: "workspace-volume"readOnly: falseworkingDir: "/home/jenkins/agent"hostNetwork: falsenodeSelector:kubernetes.io/os: "linux"restartPolicy: "Never"volumes:- name: "volume-0"persistentVolumeClaim:claimName: "pvc-maven-m2"readOnly: false- emptyDir:medium: ""name: "workspace-volume"Running on maven-13-pbvhr-xbdq3-wb3j8 in /home/jenkins/agent/workspace/maven
[Pipeline] {
[Pipeline] container
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Run shell)
[Pipeline] sh
+ echo hello world
hello world
[Pipeline] sh
+ mvn -version
Apache Maven 3.8.4 (9b656c72d54e5bacbed989b64718c159fe39b537)
Maven home: /usr/local/apache-maven-3.8.4
Java version: 1.8.0_292, vendor: AdoptOpenJDK, runtime: /opt/java/openjdk/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "3.10.0-1160.15.2.el7.x86_64", arch: "amd64", family: "unix"
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // container
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // podTemplate
[Pipeline] End of Pipeline
Finished: SUCCESS

4. Pod内使用kubectl、Docker命令

如果再springboot 项目中没有用dockerfile-maven-plugin 插件则需要手动使用 docker 命令打包并push到私服

4.1 docker 命令

添加两个主机挂载盘

或者直接用命令方式

hostPathVolume(mountPath: '/var/run/docker.sock', hostPath: '/var/run/docker.sock'),
hostPathVolume(mountPath: '/usr/bin/docker', hostPath: '/usr/bin/docker'),
hostPathVolume(mountPath: '/etc/localtime', hostPath: '/etc/localtime')

修改pipline,运行测试

podTemplate (inheritFrom: "jnlp-maven"){node(POD_LABEL) {container('jnlp'){stage('Run shell') {sh 'echo hello world'sh 'mvn -version'sh 'docker info'}}}
}

这时候会报 权限不足错误,因为 宿主机docker使用 root运行的,pipline pod 使用 jenkins(1000) 运行的

ERROR: Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/info": dial unix /var/run/docker.sock: connect:

注意:我K8S集群使用root运行的所以权限很高,你如果使用其他账号运行的K8S集群,会遇到/var/run/docker.sock没有访问权限的问题,因为Docker必须是root权限运行,解决办法是:

# Docker 服务重启要重新执行
chmod 777 /var/run/docker.sock
# 另一种方法是使用用户组

4.2 Pod内使用Kubectl命令

jnlp-maven 的 Pod Templates 添加 容器 kubectl。其中 andanyoung/kubectl是我自己封装的轻量级kubectl命令库原理很简单,参考https://hub.docker.com/r/andanyoung/kubectl

新增PVC(用于保存kubectl的配置)

修改pipline,运行测试

再 jnlp 上运行 mvn,再 jnlp-kubectl 运行 kubectl 命令

podTemplate (inheritFrom: "jnlp-maven"){node(POD_LABEL) {stage('Run shell') {sh 'echo hello world'sh 'mvn -version'}container('jnlp-kubectl'){stage('Run kubectl') {sh 'kubectl config view'}}}
}

运行结果

[Pipeline] Start of Pipeline
[Pipeline] podTemplate
[Pipeline] {
[Pipeline] node
Created Pod: kubernetes ops/maven-47-spd2w-p9t8w-94194
[Normal][ops/maven-47-spd2w-p9t8w-94194][Scheduled] Successfully assigned ops/maven-47-spd2w-p9t8w-94194 to a3
[Normal][ops/maven-47-spd2w-p9t8w-94194][Pulled] Container image "andanyoung/kubectl" already present on machine
[Normal][ops/maven-47-spd2w-p9t8w-94194][Created] Created container jnlp-kubectl
[Normal][ops/maven-47-spd2w-p9t8w-94194][Started] Started container jnlp-kubectl
[Normal][ops/maven-47-spd2w-p9t8w-94194][Pulled] Container image "andanyoung/jenkins-slave-maven" already present on machine
[Normal][ops/maven-47-spd2w-p9t8w-94194][Created] Created container jnlp
[Normal][ops/maven-47-spd2w-p9t8w-94194][Started] Started container jnlp
Agent maven-47-spd2w-p9t8w-94194 is provisioned from template maven_47-spd2w-p9t8w
---
apiVersion: "v1"
kind: "Pod"
metadata:annotations:buildUrl: "http://jenkins.ops.svc.cluster.local/job/maven/47/"runUrl: "job/maven/47/"labels:jenkins: "slave"jenkins/label-digest: "9d6c53e7f3a6bb33281553a37c902ca1c01f8881"jenkins/label: "maven_47-spd2w"name: "maven-47-spd2w-p9t8w-94194"
spec:containers:- image: "andanyoung/kubectl"imagePullPolicy: "IfNotPresent"name: "jnlp-kubectl"resources:limits: {}requests: {}tty: truevolumeMounts:- mountPath: "/home/jenkins/.m2"name: "volume-0"readOnly: false- mountPath: "/var/run/docker.sock"name: "volume-1"readOnly: false- mountPath: "/usr/bin/docker"name: "volume-2"readOnly: false- mountPath: "/home/jenkins/agent"name: "workspace-volume"readOnly: falseworkingDir: "/home/jenkins/agent"- env:- name: "JENKINS_SECRET"value: "********"- name: "JENKINS_AGENT_NAME"value: "maven-47-spd2w-p9t8w-94194"- name: "JENKINS_NAME"value: "maven-47-spd2w-p9t8w-94194"- name: "JENKINS_AGENT_WORKDIR"value: "/home/jenkins/agent"- name: "JENKINS_URL"value: "http://jenkins.ops.svc.cluster.local/"image: "andanyoung/jenkins-slave-maven"imagePullPolicy: "IfNotPresent"name: "jnlp"resources:limits:memory: "1Gi"cpu: "1"requests: {}tty: truevolumeMounts:- mountPath: "/home/jenkins/.m2"name: "volume-0"readOnly: false- mountPath: "/var/run/docker.sock"name: "volume-1"readOnly: false- mountPath: "/usr/bin/docker"name: "volume-2"readOnly: false- mountPath: "/home/jenkins/agent"name: "workspace-volume"readOnly: falseworkingDir: "/home/jenkins/agent"hostNetwork: falseimagePullSecrets:- name: ""nodeSelector:kubernetes.io/os: "linux"restartPolicy: "Never"volumes:- name: "volume-0"persistentVolumeClaim:claimName: "pvc-maven-m2"readOnly: false- hostPath:path: "/usr/bin/docker"name: "volume-2"- hostPath:path: "/var/run/docker.sock"name: "volume-1"- emptyDir:medium: ""name: "workspace-volume"Running on maven-47-spd2w-p9t8w-94194 in /home/jenkins/agent/workspace/maven
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Run shell)
[Pipeline] sh
+ echo hello world
hello world
[Pipeline] sh
+ mvn -version
Apache Maven 3.8.4 (9b656c72d54e5bacbed989b64718c159fe39b537)
Maven home: /usr/local/apache-maven-3.8.4
Java version: 1.8.0_292, vendor: AdoptOpenJDK, runtime: /opt/java/openjdk/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "3.10.0-1160.15.2.el7.x86_64", arch: "amd64", family: "unix"
[Pipeline] }
[Pipeline] // stage
[Pipeline] container
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Run kubectl)
[Pipeline] sh
+ kubectl config view
apiVersion: v1
clusters: null
contexts: null
current-context: ""
kind: Config
preferences: {}
users: null
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // container
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // podTemplate
[Pipeline] End of Pipeline
Finished: SUCCESS

当然你不能运行kubectl get pod 命令,因为现在的用户为 default 用户。没有权限

+ kubectl get pod
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:ops:default" cannot list resource "pods" in API group "" in the namespace "ops"

5. 为Jenkins创建kubernetes集群账号和证书

参考:k8s 带你一步步 创建用户账号(User Account)

接下来我们需要创建一个 名为 jenkins 的 User Account 账号并赋予相应权限

在Master上执行:

# 进入集群CA证书所在目录
cd /etc/kubernetes/pki# 执行创建证书命令
(umask 077;openssl genrsa -out jenkins.key 2048)# O=组织信息,CN=用户名
openssl req -new -key jenkins.key -out jenkins.csr -subj "/O=kubernetes/CN=jenkins"# 签署证书
openssl  x509 -req -in jenkins.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out jenkins.crt -days 3650

生成kubectl配置文件

生成配置文件位置 /root/jenkins.conf

master url --server=https://10.31.90.200:8443

# 1. 创建集群配置
kubectl config set-cluster k8s --server=https://10.31.90.200:8443 --certificate-authority=ca.crt --embed-certs=true --kubeconfig=/root/jenkins.conf
Cluster "k8s" set.# 创建jenkins用户信息
kubectl config set-credentials jenkins --client-certificate=jenkins.crt --client-key=jenkins.key --embed-certs=true --kubeconfig=/root/jenkins.conf# 创建context配置 设置上下文信息,jenkins用户与集群建立关系
kubectl config set-context jenkins@default-cluster --cluster=default-cluster --user=jenkins --kubeconfig=/root/jenkins.conf ## 切换context
kubectl config use-context default-context --kubeconfig=/root/jenkins.conf# 查看结果
kubectl config view
apiVersion: v1
clusters:
- cluster:certificate-authority-data: DATA+OMITTEDserver: https://192.168.122.3:6443name: default-cluster
contexts:
- context:cluster: default-clusteruser: jenkinsname: jenkins@default-cluster
current-context: jenkins@default-cluster
kind: Config
preferences: {}
users:
- name: jenkinsuser:client-certificate-data: REDACTEDclient-key-data: REDACTED

最后生成 /root/jenkins.conf 文件

最后将该文件放在 配置的 PVC(pvc-kube-config) 下面,再次运行测试

为 jenkins 用户添加权限

切换刚创建的上下文(切换用户)

# 切换用户
kubectl config use-context jenkins@default-cluster# 测试
kubectl get pod# 没有权限
Error from server (Forbidden): pods is forbidden: User "jenkins" cannot list resource "pods" in API group "" in the namespace "default"

目前新账号没有分配权限无法使用,创建dev-test命名空间,并创建管理该命名空间下pod资源的角色,然后绑定到jenkins账户:

创建角色:
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:name: jenkins-role
rules:
- apiGroups: [""]resources: ["pods"]verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]resources: ["pods/exec"]verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]resources: ["pods/log"]verbs: ["get","list","watch"]
- apiGroups: [""]resources: ["events"]verbs: ["watch"]
- apiGroups: [""]resources: ["secrets"]verbs: ["get"]
绑定账号与角色:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:name: jenkins-role-bind
roleRef:apiGroup: rbac.authorization.k8s.iokind: Rolename: jenkins-role
subjects:
- apiGroup: rbac.authorization.k8s.iokind: Username: jenkins

注意:Role和RoleBinding的命名空间都是dev-test权限才生效,否则是不会生效的,账号jenkins此时拥有对dev-test命名空间pod的管理权限。

测试权限:

# 在Node节点执行
[root@centos7-k8s-node1 ~]# kubectl apply -f ndsutils.yaml -n dev-test
pod/dnsutils created
[root@centos7-k8s-node1 ~]# kubectl get pod -n dev-test
NAME       READY   STATUS    RESTARTS   AGE
dnsutils   1/1     Running   0          11s
[root@centos7-k8s-node1 ~]# kubectl get pod -n default
Error from server (Forbidden): pods is forbidden: User "jenkins" cannot list resource "pods" in API group "" in the namespace "default"

测试运行(增删改查,自行认证吧)

podTemplate (inheritFrom: "jnlp-maven"){node(POD_LABEL) {stage('Run shell') {sh 'echo hello world'sh 'mvn -version'}container('jnlp-kubectl'){stage('Run kubectl') {sh 'kubectl get pod -n dev-test'}}}
}

运行结果

+ kubectl get pod
NAME                         READY   STATUS    RESTARTS   AGE
jenkins-0                    1/1     Running   0          24h
maven-49-gwdm5-101pq-0spr9   2/2     Running   0          10s

为jenkins账号赋予集群角色

Role 只能拥有当前namespace 的权限,而ClusterRole 没有namespace的限制,没有命名空间的概念,集群角色是在所有命名空间有效。

创建集群角色,此集群角色只有查看Pod的权限:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:name: cluster-reader
rules:
- apiGroups: [""]resources: ["pods"]verbs: ["get","list","watch"]

绑定账号和集群角色:

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:name: cluster-reader-jenkins
roleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: cluster-reader
subjects:
- apiGroup: rbac.authorization.k8s.iokind: Username: jenkins

在Node节点上执行:

[root@centos7-k8s-node1 yaml]# kubectl get pod -A
NAMESPACE              NAME                                         READY   STATUS    RESTARTS   AGE
dev-test               dnsutils                                     1/1     Running   0          7m17s
kube-system            coredns-7ff77c879f-ck49p                     1/1     Running   9          5d3h
kube-system            coredns-7ff77c879f-d2xfc                     1/1     Running   10         5d3h
kube-system            etcd-centos7-k8s-master                      1/1     Running   11         5d3h
kube-system            kube-apiserver-centos7-k8s-master            1/1     Running   6          4d1h
kube-system            kube-controller-manager-centos7-k8s-master   1/1     Running   12         5d3h
kube-system            kube-flannel-ds-amd64-52vcn                  1/1     Running   9          5d3h
kube-system            kube-flannel-ds-amd64-vtw58                  1/1     Running   12         5d3h
kube-system            kube-flannel-ds-amd64-xm8d5                  1/1     Running   10         5d3h
kube-system            kube-proxy-l8875                             1/1     Running   18         5d3h
kube-system            kube-proxy-p5fdr                             1/1     Running   9          5d3h
kube-system            kube-proxy-pdvz2                             1/1     Running   16         5d3h
kube-system            kube-scheduler-centos7-k8s-master            1/1     Running   10         5d3h
kube-system            metrics-server-7f6d95d688-vjsbj              1/1     Running   7          4d1h
kubernetes-dashboard   dashboard-metrics-scraper-6b4884c9d5-8hblg   1/1     Running   7          4d1h
kubernetes-dashboard   kubernetes-dashboard-7b544877d5-tz4xj        1/1     Running   7          4d1h
nginx-ingress          coffee-5f56ff9788-2745d                      1/1     Running   6          4d1h
nginx-ingress          coffee-5f56ff9788-c8jlx                      1/1     Running   6          4d1h
nginx-ingress          nginx-ingress-hjqzc                          1/1     Running   6          4d1h
nginx-ingress          nginx-ingress-jfh6h                          1/1     Running   6          4d1h
nginx-ingress          tea-69c99ff568-cpp2k                         1/1     Running   6          4d1h
nginx-ingress          tea-69c99ff568-rmnr2                         1/1     Running   6          4d1h

PS: 用户账号有了(User Account),权限也可以配置了。那k8s 发布pod(重启、更新版本等)不是可以实现了吗?请看下回分析。

基于K8S构建企业级Jenkins CI/CD平台实战(二) 之 kubernetes-plugin 插件使用相关推荐

  1. 基于K8S构建企业级Jenkins CI/CD平台实战(三) 之 带你实战Spring boot/Cloud 项目 CI/CD jenkins自动化构建、部署过程

    需要环境 Git(GitLab) Harbor 私服 kubernetes-plugin 使用 Kubernetes jenkins 通过前面三篇我们已经了解了jenkins和 kubernetes- ...

  2. 基于K8S构建企业级Jenkins CI/CD平台实战(一) 之 环境搭建

    一. 持续集成/部署/交付概述 持续集成(Continuous Integration,CI): 代码合并.构建.部署.测试都在一起,不断地执行这个过程,并对结果反馈. 持续部署(Continuous ...

  3. 基于Jenkins和k8s构建企业级DevOps容器云平台

    1.1 什么是DevOps? DevOps中的Dev是Devlopment(开发),Ops是Operation(运维),用一句话来说 DevOps 就是打通开发运维的壁垒,实现开发运维一体化.DevO ...

  4. Jenkins X:基于Kubernetes的CI/CD平台

    背景 Jenkins自动化服务器一直都是DevOps工具链的重要组成部分,并且已发展成为开源持续集成和持续部署(CI&CD)软件的领导者.据不完全统计,截至2019年6月,已有将近26万的Je ...

  5. OpenShift 4 Hands-on Lab (8) 基于Gogs+Nexus+Sonarqube的Jenkins CI/CD Pipeline

    <OpenShift 4.x HOL教程汇总> 说明:本文已经在 OpenShift 4.8 环境中验证(OpenShift 4.9 环境的 Jenkins 版本较新,编译 Java 报错 ...

  6. OpenShift 4之实现一个基于Gogs+Nexus+Sonarqube的Jenkins CI/CD Pipeline

    OpenShift 4之实现一个基于Gogs+Nexus+Sonarqube的Jenkins CI/CD Pipeline 场景说明 运行环境 配置操作过程 准备运行所需资源 配置Gogs并导入应用代 ...

  7. Aooms_基于SpringCloud的微服务基础开发平台实战_002_工程构建

    为什么80%的码农都做不了架构师?>>>    一.关于框架更名的一点说明 最近在做年终总结.明年规划.还有几个项目需要了结.出解决方案,事情还比较多,死了不少脑细胞,距离上一篇文章 ...

  8. 阿里云实时计算产品经理李佳林:基于 Flink 构建大规模风控系统的技术实战

    本⽂由 Flink 社区志愿者邹志业整理,内容来源⾃阿里云实时计算产品经理李佳林在 7 月 5 日 Flink 峰会(CSDN 云原生系列)的演讲.主要内容包括:基于 Flink 构建风控系统.阿里风 ...

  9. 使用 jenkins 构建 CI/CD 平台

    CI/CD 概述 大概了解一下 CI/CD 是啥子,其实之前做过这东西,但是没解释过. 持续集成 (Continuous Integration,CI) :代码合并构建部署测试都在一起,不断地执行这个 ...

最新文章

  1. TensorFlow基础8-实现单层神经网络
  2. maven打jar包,导入本地jar
  3. Spring@Autowired注解与自动装配
  4. sql server 用户'sa'登录失败(错误18456)
  5. CAN接口芯片TJF1051T/3波形
  6. 根据时间格式字符串取出时分秒各自的数值
  7. 纸牌三角形(蓝桥杯)
  8. linux服务器安装Mysql。看了几个教程,没装上,看这个一下就装上了。
  9. 关于《精通Unix下C语言编程与项目实践》的试读策划
  10. 人工智能/数据科学比赛汇总 2019.3
  11. 从数据仓库到大数据平台再到数据中台(内附13张架构图)
  12. 命令行,使用java的java 命令,直接调用执行class文件
  13. PHP图形图像的典型应用 --常用图像的应用(统计图)
  14. 分享一款在线less转css的神器
  15. ListView控件详解
  16. python分数计算器_python计算器实现过程
  17. 画法几何,工程制图基础.....多角度平面投影图推断立体空间结构,实际距离的判别等
  18. UCGUI使用的24位颜色RGB数值对照表
  19. HTTP - 长连接/短连接 - 学习/实践
  20. 红军协同对抗蓝军问题

热门文章

  1. WR:微生物污染源解析中宿主特异性标记物在中国的表现特征
  2. 基因组注释3.基因的功能注释Prokka
  3. KEGG在线数据库使用攻略
  4. R语言使用caretEnsemble包的caretList函数一次性构建多个机器学习模型、使用lattice包的bwplot函数使用箱图对比多个模型在多个指标上的性能差异
  5. 增强迪基-福勒检验(ADF检验、augmented Dickey-Fuller test)是什么?解决了什么问题?
  6. R语言使用haven包的read_spss函数读取spss格式数据、使用haven包的read_sas函数读取SAS格式数据、使用haven包的read_dta函数读取Stata格式数据
  7. 临时表,临时表什么时候删除
  8. MCMC+马尔科夫链蒙特卡罗
  9. 校准曲线(calibration curve)是什么?如何绘制校准曲线(calibration curve)?如何通过过校准曲线进行分析?什么是高估?什么是低估?
  10. R语言中的dnorm(),pnorm(),qnorm(),rnorm()的解释