您的位置:首页 > 运维架构

DevOps的核心内功心法:OpenShift中实现共享Jenkins

2020-12-21 21:27 2431 查看

一. 介绍

  本文将对OpenShift中共享jenkins的方式进行说明。共享jenkins主要针对默认的行为而言的,OpenShift默认情况下,在每个project中第一次创建pipeline都会自动运行一个jenkins实例,那么有没有一种方法实现多个project共用一个jenkins或者整个OCP平台使用一个jenkins呢?答案是肯定的。
  为了便于描述,我们将OCP中多个project共用的jenkins称为共享jenkins。OpenShift中实现共享jenkins有两种方法:
  方法一:在一个全局项目中部署jenkins,所有的pipeline创建在该项目中
  方法二:在一个项目中创建jenkins,采集分布在不同project中的pipeline
  在开始说明上述两种方法之前,先说明一点jenkins相关的配置。因为共享jenkins意味着jenkins中jobs会很多,需要配置更多的资源(CPU/MEM)来支撑job运行,否则jenkins经常会OOM错误退出。默认内存限制为512M,建议将JVM_ARCH设置为x86_64,内存限制设置为4G或者8G,增加MetaspaceSize(默认100m)的大小。
  通过在jenkins的dc中增加环境变量OPENSHIFT_JENKINS_JVM_ARCH=x86_64来修改JVM_ARCH,增加环境变量JAVA_GC_OPTS=“-XX:+UseParallelGC -XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=40 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:MaxMetaspaceSize=1024m”设置MetaspaceSize大小。
  更多OpenShift jenkins的参数设置,请参考官方说明。
  本文所有测试在OCP 3.6验证通过,建议先阅读《不为人知的OpenShift Jenkins权限细节》理解OCP jenkins的权限再阅读本博客。

二. 禁止默认行为

  在实现共享jenkins之前,先要禁用掉OCP的默认行为——也就是每个project在第一次创建jenkins的时候会自动创建一个jenkins实例。
  默认行为解析:OpenShift在每个项目中,第一次创建pipeline时,会检测当前项目中是否存在名为jenkins的service,如果不存在,则会在openshift project中查找名为jenkins-ephemeral的template,并在当前project下实例化一个jenkins server,关于jenkins-ephemeral中的内容可查看模版的定义。
  默认使用openshift项目下的jenkins-ephemeral模版进行实例化jenkins,这样管理员就可以通过修改jenkins-ephemeral模版来实现在jenkins实例化中创建一些其他的资源对象。当然这种默认行为是可以定义的,通过在master配置文件(/etc/origin/master/master-config.yaml)中设置如下参数:


1
2
3
4
5
6
7
8
jenkinsPipelineConfig:
  autoProvisionEnabled: true
  templateNamespace: openshift
  templateName: jenkins-ephemeral
  serviceName: jenkins
  parameters:
    key1: value1
    key2: value2


参数说明:
1)autoProvisionEnabled:默认为true,如果设置为false,则表示不开启默认行为,第一次创建pipeline时,不会实例化jenkins。
2)templateNamespace:实例化jenkins使用的模版所在的namespace,默认为openshift。
3)templateName:实例化jenkins所使用的模版名称,默认为jenkins-ephemeral。
4)serviceName:第一次创建pipeline后检测jenkins service的名称,在实例化jenkins的模版中定义的service名称必须与该参数一致。
5)parameters:可以定义传入实例化jenkins模版的参数,需要在模版中预先定义好。
使用上述参数管理员完全可以自定义默认行为或者禁用自动实例化jenkins的行为。

  实现共享jenkins的前提是通过设置autoProvisionEnabled=false禁用每个project自动启动jenkins实例的行为,其他参数保持默认即可。注意修改master配置文件之后必须重启master服务使得配置更改生效。

三. 方法一的实现

  使用一个项目创建jenkins实例,将该项目做为一个全局项目,在该项目下创建所有的pipeline。下面描述操作过程:

1. 禁用默认行为
1)修改master配置文件,设置autoProvisionEnabled=false


1
2
3
4
5
6
7
# vi /etc/origin/master/master-config.yaml
......
jenkinsPipelineConfig:
 autoProvisionEnabled: false
 templateNamespace: openshift
 templateName: jenkins-ephemeral
 serviceName: jenkins


2)重启master服务


1
# systemctl restart atomic-openshift-master


注:高可用情况下,在所有master节点修改配置文件,重启atomic-openshift-master-api服务。

2. 创建一个项目,并实例化jenkins
1)创建名为share-jenkins的项目


1
2
# oc login -u system:admin      
# oc new-project share-jenkins


2)实例化jenkins server
可通过web界面和命令行实现,这里我们使用命令行


1
2
# oc project share-jenkins
# oc new-app --template=jenkins-ephemeral --param=JVM_ARCH=x86_64 --param=MEMORY_LIMIT=4Gi -e JAVA_GC_OPTS="XX:+UsParallelGC -XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=40 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:MaxMetaspaceSize=1024m"


具体实例化jenkins的参数可根据需要设置,或部署之后再次修改dc文件均可,但必须保证创建的service名称为jenkins。

3. 设置项目为全局项目
1)设置用户可见性为全局
  此操作目的是让所有需要使用jenkins的用户都可以访问该项目,通常是将特定的用户或组指定为项目的view或edit。这里我们直接将所有认证用户赋予view权限,权限控制后续在jenins中实现。


1
# oc policy add-role-to-group view system:authenticated


2)设置jenkins可操作其他项目
这种方式需要赋予serviceaccount jenkins对其他所有项目有操作权限,因为该项目中的pipeline要对其他项目执行操作。
如果项目数量相对固定,那么可以单独对这几个项目设置权限


1
# oc policy add-role-to-user edit system:serviceaccount:share-jenkins:jenkins -n [other_project]


如果项目数量不固定,则可以设置为将serviceaccount jenkins赋予cluster-admin的role


1
# oadm policy add-cluster-role-to-user cluster-admin -z jenkins


4. 创建测试pipeline
为了后续测试pipeline,我们创建两个pipeline,并实现简单操作其他项目。
1)创建测试项目demo-dev和demo-uat


1
2
# oc project demo-dev    
# oc project demo-uat


如果使用对单独项目赋权,则执行如下操作:


1
2
# oc policy add-role-to-user edit system:serviceaccount:share-jenkins:jenkins -n demo-dev
# oc policy add-role-to-user edit system:serviceaccount:share-jenkins:jenkins -n demo-uat


2)创建演示pipeline
  创建两个pipeline,用于演示,分别操作demo-dev和demo-uat中的资源 ,实际应用中pipeline根据具体的场景编写。
在share-jenkens项目中创建名为dev-mariadb的演示pipeline,内容如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
node('maven') {
def project_name = 'demo-dev'    
   stage('clean mariadb') {
   sh "oc project ${project_name}"
       sh "oc delete dc,svc,secret -l app=mariadb-ephemeral -n ${project_name}"
   }
   stage('create mariadb') {
       sh "oc new-app --template=mariadb-ephemeral -n ${project_name}"
   }
   stage('complate') {
       echo "deploy complate"
   }
}


  同样在share-jenkens项目中创建名为uat-mariadb的演示pipeline,内容与dev-mariadb一致,只需要把project_name设置为demo-uat即可。创建之后就可以在jenkins中看到两个job,如下图所示:

测试运行两个job,可以看看到均正确运行,且分别在demo-dev和demo-uat项目中创建了mariadb的容器。


5. 设置jenkins中job权限
  可以看到这种方式已经实现了共享jenkins,但是默认jenkins中的job,普通用户是没办法呢运行和编辑的,因为普通用户在该项目中被赋予的是view权限。需要解决jenkins中job的权限问题,可参考上一篇博客《不为人知的OpenShift Jenkins权限细节》了解原理,这里我们直接说明操作过程。
1)在OCP中增加测试用户
创建两个用于测试的用户user-dev和user-uat


1
2
# htpasswd /etc/origin/master/htpasswd user-dev
# htpasswd /etc/origin/master/htpasswd user-uat


  赋予user-dev对project demo-dev为edit role,赋予user-uat对project demo-uat为edit role;这样使用user-dev登录OCP后可以看到项目demo-dev和share-jenkins,使用user-uat登录OCP后可以看到项目demo-uat和share-jenkins,但是对share-jenkins项目只有view权限。
2)修改jenkins权限为“项目矩阵授权策略”
  使用管理员登录jenkins,进入“系统管理——Configure Global Security”,将授权策略设置为“项目矩阵授权策略”,并开启匿名用户的overall/read权限

3)分别赋予user-dev和user-uat对应的job权限
  分别进入jenkins job中,设置user-dev对job dev-mariadb有读写权限,设置user-uat对job uat-mariadb有读写权限。


6. 分别登录用户测试
  使用user-dev登录jenkins,可以看到jenkins中所有的job,但是仅对job dev-mariadb有构建和修改的权限,其余均为只读权限。用户user-uat也是类似的。

到此为止,已经完成了共享jenkins的配置,这种方法的优缺点如下:
优点:
1)实现了jenkins job层面的权限控制 2)实现和配置过程相对简单 3)权限统一由jenkins控制,简化了赋权操作
缺点:
1)所有pipeline需要由管理员统一创建,增加管理员负担 2)所有pipeline在一个项目中,未做到pipeline的隔离

四. 方法二的实现

  使用一个项目创建jenkins实例,使用jenkins plugins——[OpenShift sync](https://github.com/jenkinsci/openshift-sync-plugin)来同步不同project中的pipeline。
下面描述操作过程(最好将方法一中环境删除避免冲突):
1. 禁用默认行为
1)修改master配置文件,设置autoProvisionEnabled=false


1
2
3
4
5
6
# vi /etc/origin/master/master-config.yaml         
jenkinsPipelineConfig:
 autoProvisionEnabled: false
   templateNamespace: openshift
   templateName: jenkins-ephemeral
   serviceName: jenkins


2)重启master服务


1
# systemctl restart atomic-openshift-master


注:高可用情况下,在所有master节点修改配置文件,重启atomic-openshift-master-api服务。

2. 创建一个项目,并实例化jenkins
1)创建名为share-jenkins的项目


1
2
# oc login -u system:admin      
# oc new-project share-jenkins


2)实例化jenkins server
可通过web界面和命令行实现,这里我们使用命令行


1
2
# oc project share-jenkins
# oc new-app --template=jenkins-ephemeral --param=JVM_ARCH=x86_64 --param=MEMORY_LIMIT=4Gi -e JAVA_GC_OPTS="XX:+UsParallelGC -XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=40 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:MaxMetaspaceSize=1024m"


具体实例化jenkins的参数可根据需要设置,或部署之后再次修改dc文件均可,但必须保证创建的service名称为jenkins。
3. 设置项目为全局项目
1)设置用户可见性为全局
此操作目的是让所有需要使用jenkins的用户都可以访问该项目,通常是将特定的用户或组指定为项目的view或edit。这里我们直接将所有认证用户赋予view权限,权限控制后续在jenins中实现。


1
# oc policy add-role-to-group view system:authenticated


2)设置jenkins可操作其他项目
这种方式需要赋予serviceaccount jenkins对其他所有项目有操作权限,因为该项目中的pipeline要对其他项目执行操作。
如果项目数量相对固定,那么可以单独对这几个项目设置权限


1
# oc policy add-role-to-user edit system:serviceaccount:share-jenkins:jenkins -n [other_project]


如果项目数量不固定,则可以设置为将serviceaccount jenkins赋予cluster-admin的role


1
# oadm policy add-cluster-role-to-user cluster-admin -z jenkins


4. 创建测试项目
1)创建测试项目demo-dev和demo-uat


1
2
# oc project demo-dev    
# oc project demo-uat


2)分别设置user-dev和user-uat有项目edit权限


1
2
# oc policy add-role-to-user edit user-dev  -n demo-dev
# oc policy add-role-to-user edit user-uat  -n demo-uat


3)赋予jenkins sa可操作权限
如果使用单独项目赋权,则执行如下命令:


1
2
# oc policy add-role-to-user edit system:serviceaccount:share-jenkins:jenkins -n demo-dev
# oc policy add-role-to-user edit system:serviceaccount:share-jenkins:jenkins -n demo-uat


5. 配置共享jenkins
1)创建jenkins service
根据OCP查找jenkins server的原理可知,在项目中创建pipeline时,会查找名为jenkins的service,所以我们手动创建service,并使用cname将访问service请求转发到share-jenkins项目中的jenkins server。
使用如下service定义文件创建jenkins service。


1
2
3
4
5
6
7
8
9
10
cat > jenkins-svc.yaml << EOF
kind: "Service"
apiVersion: "v1"
metadata:
 name: "jenkins"
spec:
 type: ExternalName
 externalName: jenkins.share-jenkins.svc.cluster.local
selector: {}
>>EOF


分别在demo-dev和demo-uat中创建jenkins service


1
2
# oc create -f jenkins-svc.yaml -n demo-dev
# oc create -f jenkins-svc.yaml -n demo-uat


2)创建route


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cat > jenkins-route.yaml << EOF
apiVersion: v1
kind: Route
metadata:
 creationTimestamp: null
 name: jenkins
spec:
 host: jenkins-share-jenkins.apps.cloud.com
 to:
   kind: Service
   name: jenkins
   weight: 100
 wildcardPolicy: None
status: {}
>>EOF


分别在demo-dev和demo-uat中创建jenkins route


1
2
# oc create -f jenkins-route.yaml -n demo-dev
# oc create -f jenkins-route.yaml -n demo-uat


注意:必须创建route对象,并将hostname指定为share-jenkins中对应的jenkins域名,否则无法通过点击view log跳转到jenkins server中。因为此处hostname已被share-jenkins项目的jenkins server使用,所以web console中会出现如下警告提示,忽略即可。



3)配置jenkins pipeline同步插件

默认OpenShift Jenkins Sync的插件仅会同步当前project的pipeline,我们手动在插件中添加需要同步的project。
使用管理员登录jenkins,切换到“系统管理——系统设置”,配置OpenShift Jenkins Sync插件,添加创建的演示项目demo-dev和demo-uat,如下图:

如图所示,多个项目使用空格分隔。

6. 创建演示pipeline
1)在demo-dev下创建pipeline
使用user-dev登录OCP,在demo-dev项目下创建名为test-mariadb的演示pipeline,内容如下:


1
2
3
4
5
6
7
8
9
10
11
12
def project_name = 'demo-dev'    
node('maven') {    
   stage('clean mariadb') {
       sh "oc delete dc,svc,secret -l app=mariadb-ephemeral -n ${project_name}"
   }
   stage('create mariadb') {
       sh "oc new-app --template=mariadb-ephemeral -n ${project_name}"
   }
   stage('complate') {
       echo "deploy complate"
   }
}


2)在demo-uat下创建pipeline
  同样使用user-uat登录OCP,在demo-uat项目下创建名为test-mariadb的演示pipeline,内容与demo-dev中的基本一致,仅需要修改project_name=’demo-uat’。

7. 测试共享jenkins

创建完成之后,使用user-dev登录jenkins,可以看到所有pipeline已经同步到jenkins job中了,如下图所示:

从图中可以看出对user-dev对所有job为只读权限,无法构建job。
注意:OpenShift Jnekins Sync插件配置多个项目后,会有一定的延迟(同步周期为5分钟),请内心等待数分钟。
以user-dev登录OCP,在项目demo-dev中,切换到pipeline界面,点击“start pipeline”按钮,pipeline开始构建,并且状态同步到jenkins中。

点击pipeline中的“view log”按钮,可以正常的跳转到share-jenkins项目中的jenkins server查看构建日志。

  同样的可以使用user-uat登录测试。可以发现,user-uat登录之后,同样在jenkins中对job只有只读权限。用户只可以在OCP中启动pipeline,修改pipeline以及查看构建日志等。实际上,用户也完全没有对jenkins job有任何操做权限的必要。

  另外在这种实现方法中,想要使用共享jenkins,每次新建一个project就需要在project中创建jenkins的service和route对象,如果project数目对固定,则手动创建即可,如果project名称不固定,则可以使用project-template实现自动创建。

到此为止,已经完成了共享jenkins的配置,这种方法的优缺点如下:
优点:
1)实现了pipeline的隔离 2)不同项目的pipeline由用户自己创建维护,无需管理员参与 3)jenkins中所有job为只读权限,安全性更高
缺点:
1)实现和配置过程相对复杂 2)在同步多个项目的pipeline时,效率偏低,第一次同步延迟在分钟级别

五. 方法一和方法二的对比

1)方法一中pipeline构建权限由jenkins控制,方法二中pipeline构建权限由OCP控制
2)方法一无法做到pipeline隔离,所有pipeline均在同一个项目中;尽管在jenkins中可以实现隔离 ,但是用户依然可以在OCP的项目中查看所有pipeline,但无法执行任何操作。方法二完美的实现了pipeline的隔离。
3)方法一所有的pipeline首次必须由管理员创建模版,后续可以由用户自行在jenkins中修改,而方法二pipeline完全交由用户管理,交给用户自己管理就有可能出现乱用。
4)方法一相对于方法二更健壮,在同步pipeline上出错的可能性更小,主要由于OpenShift Jenkins Sync插件的不稳定性导致。

六. 方法一与方法二的结合

  由两种方法对比可以看出,都可以实现共享jenkins的目的,主要的区别在权限以及pipeline隔离性上。用户可以根据实际场景选择合适的方式。
  下面我们尝试能否将方法一与方法二结合,理论上是可行的。我们在方法二的基础上,引入方法一中的job权限隔离,似乎是一种完美的方案。大致过程如下:
1)首先完成方法二的所有配置
2)切换jenkins认证策略为“项目矩阵授权策略”,开启匿名用户的overall/read权限,如下图:

3)开启指定job的项目权限,并赋予特定的人


4)登录测试job可见性及操作权限


用户user-dev仅对job demo-dev/test-mariadb可见,而且有操作权限。

  虽然可以将两种方法的优势都结合起来,但是引入了更多复杂性,如果单独使用方法一或方法二就能满足需求,则直接单独使用方法一或方法二即可。

七. 总结

  本文通过不同的方法实现OCP中共享jenkins,分析了优缺点,并尝试将二者的优势结合在一起。用户可以根据具体的场景需求选择合适的方案。

八. 遇到的问题

  第二种方法中不同project中的pipeline通过service设定的cname连接jenkins server,在初始中,可能会出现启动pipeline/job缓慢的问题,此时pipeline的状态new,如下图:


  这种情况不用担心,该现象只是出现在刚开始的阶段,也可能不会出现。




内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: