创建ci空间
给jenkins建立单独的表空间ci,与其他应用隔离ci.yaml:
| 1 | apiVersion: v1 | 
创建用户
创建jenkins-admin的用户,进行角色管理jenkins-rbac.yaml:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41---
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: jenkins
  name: jenkins-admin
  namespace: ci
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: jenkins-admin
  labels:
    k8s-app: jenkins
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: jenkins-admin
  namespace: ci
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  labels:
    k8s-app: jenkins
  name: jenkins
rules:
- apiGroups: ["", "extensions", "apps"]
  resources:
    - nodes
    - nodes/proxy
    - endpoints
    - secrets
    - pods
    - deployments
    - services
  verbs: ["get", "list", "watch"]
创建jenkins应用
jenkins需要挂载三个目录,挂载/var/jenkins_home的目录到/home/ap/ci/jenkins/var/jenkins_home,挂载/home/data的目录到/home/ap/ci/jenkins/data,挂载/home/jenkins到/home/ap/ci/jenkins/jenkins
同时jenkins需要安装到master服务器上,所以需要给master打上label,指令:
kubectl label nodes master type=k8s-master
同时在配置文件中设置:1
2nodeSelector:
     type: k8s-master
具体配置文件如下jenkins.yaml1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43apiVersion: apps/v1beta2 # for versions before 1.8.0 use apps/v1beta1
kind: Deployment
metadata:
  name: jenkins
  namespace: ci
  labels:
    k8s-app: jenkins
spec:
  replicas: 1
  selector:
    matchLabels:
      k8s-app: jenkins
  template:
    metadata:
      labels:
        k8s-app: jenkins
    spec:
	  nodeSelector:
        type: k8s-master
      containers:
      - name: jenkins
        image: jenkins:devops
        volumeMounts:
        - name: var-jenkins-home
          mountPath: /var/jenkins_home
        - name: jenkins-data
          mountPath: /home/data
        - name: home-jenkins
          mountPath: /home/jenkins	  
        ports:
        - containerPort: 8080
        - containerPort: 50000
      volumes:
        - name: var-jenkins-home
          hostPath:
            path: /home/ap/ci/jenkins/var/jenkins_home
        - name: jenkins-data
          hostPath:
            path: /home/ap/ci/jenkins/data
        - name: home-jenkins
          hostPath:
            path: /home/ap/ci/jenkins/jenkins
      serviceAccount: "jenkins-admin"
创建jenkins服务
jenkins-service.yaml:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: jenkins
  name: jenkins
  namespace: ci
  annotations:
    prometheus.io/scrape: 'true'
spec:
  ports:
    - port: 8080
      name: jenkins
      targetPort: 8080
      nodePort: 31888
    - port: 50000
      name: jenkins-agent
      targetPort: 50000
  type: NodePort
  selector:
    k8s-app: jenkins
创建完查看集群信息:1
2
3[root@master jenkins_k8s]# kubectl get service -n ci
NAME      TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)                          AGE
jenkins   NodePort   10.102.120.26   <none>        8080:31888/TCP,50000:31461/TCP   34m
现在就可以通过http://{IP}:31888访问jenkins了
kubernetes插件配置
下载插件kubernetes,在【系统管理】-【系统设置】-【新增一个云】-【Kubernetes】配置k8s的插件
参考上图的说明,进行配置。要注意的是,这里的Name字段配的名字,后面在配置pipeline的Jenkins任务时,是需要用到的(假设这里使用的名字叫Kubernetes)。然后点【Test Connection】,如果前面的Service Account配置的没问题的话,就会提示“Connection successful”,否则,会有访问apiserver的403权限报错。
用pipeline方式创建一个如下的Jenkins构建任务:1
2
3
4
5
6
7
8
9// this guarantees the node will use this template
def label = "mypod-${UUID.randomUUID().toString()}"
podTemplate(label: label) {
    node(label) {
        stage('Run shell') {
            sh 'echo hello world'
        }
    }
}
图2中Jenkins URL请填http://
问题与解决
1、 jenkins 插件目录和工作目录的挂载:1
2
3
4
5
6
7
8
9
10  volumeMounts:
  - name: jenkins-home
    mountPath: /var/jenkins_home
  ports:
  - containerPort: 8080
  - containerPort: 50000
volumes:
  - name: jenkins-home
    hostPath:
      path: /home/ap/ci/jenkins/test
volumes将容器中的/var/jenkins_home目录挂载到本地的/home/ap/ci/jenkins/test文件夹中
2、 slave连接jenkins
slave连接jenkins时,新建出来的容器报错:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65[root@master jenkins_k8s]# kubectl logs pod/jenkins-slave-vcr29-lg2bz  -n ci
Warning: JnlpProtocol3 is disabled by default, use JNLP_PROTOCOL_OPTS to alter the behavior
Jun 14, 2018 8:08:33 AM hudson.remoting.jnlp.Main createEngine
INFO: Setting up agent: jenkins-slave-vcr29-lg2bz
Jun 14, 2018 8:08:33 AM hudson.remoting.jnlp.Main$CuiListener <init>
INFO: Jenkins agent is running in headless mode.
Jun 14, 2018 8:08:33 AM hudson.remoting.Engine startEngine
INFO: Using Remoting version: 3.19
Jun 14, 2018 8:08:33 AM hudson.remoting.Engine startEngine
WARNING: No Working Directory. Using the legacy JAR Cache location: /home/jenkins/.jenkins/cache/jars
Jun 14, 2018 8:08:33 AM hudson.remoting.jnlp.Main$CuiListener status
INFO: Locating server among [http://10.128.13.24:31888/]
Jun 14, 2018 8:08:33 AM org.jenkinsci.remoting.engine.JnlpAgentEndpointResolver resolve
INFO: Remoting server accepts the following protocols: [JNLP4-connect, JNLP-connect, Ping, JNLP2-connect]
Jun 14, 2018 8:08:33 AM hudson.remoting.jnlp.Main$CuiListener status
INFO: Agent discovery successful
  Agent address: 10.128.13.24
  Agent port:    50000
  Identity:      2e:b1:d0:06:6f:be:fb:5a:53:86:f6:a5:27:03:49:98
Jun 14, 2018 8:08:33 AM hudson.remoting.jnlp.Main$CuiListener status
INFO: Handshaking
Jun 14, 2018 8:08:33 AM hudson.remoting.jnlp.Main$CuiListener status
INFO: Connecting to 10.128.13.24:50000
Jun 14, 2018 8:08:33 AM hudson.remoting.jnlp.Main$CuiListener status
INFO: Trying protocol: JNLP4-connect
Jun 14, 2018 8:08:39 AM org.jenkinsci.remoting.protocol.impl.SSLEngineFilterLayer onRecv
SEVERE: [JNLP4-connect connection to 10.128.13.24/10.128.13.24:50000] 
javax.net.ssl.SSLHandshakeException: General SSLEngine problem
	at sun.security.ssl.Handshaker.checkThrown(Handshaker.java:1478)
	at sun.security.ssl.SSLEngineImpl.checkTaskThrown(SSLEngineImpl.java:535)
	at sun.security.ssl.SSLEngineImpl.writeAppRecord(SSLEngineImpl.java:1214)
	at sun.security.ssl.SSLEngineImpl.wrap(SSLEngineImpl.java:1186)
	at javax.net.ssl.SSLEngine.wrap(SSLEngine.java:469)
	at org.jenkinsci.remoting.protocol.impl.SSLEngineFilterLayer.processRead(SSLEngineFilterLayer.java:392)
	at org.jenkinsci.remoting.protocol.impl.SSLEngineFilterLayer.onRecv(SSLEngineFilterLayer.java:117)
	at org.jenkinsci.remoting.protocol.ProtocolStack$Ptr.onRecv(ProtocolStack.java:669)
	at org.jenkinsci.remoting.protocol.impl.AckFilterLayer.onRecv(AckFilterLayer.java:255)
	at org.jenkinsci.remoting.protocol.ProtocolStack$Ptr.onRecv(ProtocolStack.java:669)
	at org.jenkinsci.remoting.protocol.NetworkLayer.onRead(NetworkLayer.java:136)
	at org.jenkinsci.remoting.protocol.impl.BIONetworkLayer.access$2200(BIONetworkLayer.java:48)
	at org.jenkinsci.remoting.protocol.impl.BIONetworkLayer$Reader.run(BIONetworkLayer.java:283)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at hudson.remoting.Engine$1.lambda$newThread$0(Engine.java:93)
	at java.lang.Thread.run(Thread.java:748)
Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
	at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
	at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1728)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:304)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1514)
	at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
	at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026)
	at sun.security.ssl.Handshaker$1.run(Handshaker.java:966)
	at sun.security.ssl.Handshaker$1.run(Handshaker.java:963)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.security.ssl.Handshaker$DelegatedTask.run(Handshaker.java:1416)
	at org.jenkinsci.remoting.protocol.impl.SSLEngineFilterLayer.processRead(SSLEngineFilterLayer.java:382)
	... 11 more
Caused by: java.security.cert.CertificateException: Public key of the first certificate in chain (subject: C=US, OU=jenkins.io, O=instances, CN=364eef21b316f8b881b4b55dcc19bb20) is not in the list of trusted keys
	at org.jenkinsci.remoting.protocol.cert.PublicKeyMatchingX509ExtendedTrustManager.checkPublicKey(PublicKeyMatchingX509ExtendedTrustManager.java:217)
	at org.jenkinsci.remoting.protocol.cert.PublicKeyMatchingX509ExtendedTrustManager.checkServerTrusted(PublicKeyMatchingX509ExtendedTrustManager.java:263)
	at org.jenkinsci.remoting.protocol.cert.DelegatingX509ExtendedTrustManager.checkServerTrusted(DelegatingX509ExtendedTrustManager.java:148)
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1501)
	... 18 more
原因:
jenkins-slave连接到http://IP:50000,但k8s只能暴露30000-32767端口,所以slave会连接失败。
三种方法解决:
(1) jenkins的kubernetes配置中,Jenkins URL填http://
(2) 使用ingress代替service的port暴露,详细见查考链接
(3) k8s启动时带上解除端口限制的参数,详细见查考链接
参考文档:
RBAC的授权:https://www.kubernetes.org.cn/4062.html
jenkins配置:https://blog.csdn.net/felix_yujing/article/details/78725142
jenkins配置:https://blog.csdn.net/aixiaoyang168/article/details/79767649
ingress代替service的port暴露:https://zhangchenchen.github.io/2017/12/17/achieve-cicd-in-kubernetes-with-jenkins/
k8s启动时带上解除端口限制的参数:https://github.com/kubernetes/kubeadm/issues/122