zoukankan      html  css  js  c++  java
  • 在k8s上安装Jenkins及常见问题

    持续集成和部署是DevOps的重要组成部分,Jenkins是一款非常流行的持续集成和部署工具,最近试验了一下Jenkins,发现它是我一段时间以来用过的工具中最复杂的。一个可能的原因是它需要与各种其它工具集成才能完成任务,而集成的方法又各不相同。在这些工具中,Docker是最简单的,真的非常好用。K8s比较复杂,开始要花些时间熟悉,但它的整体设计十分合理,一旦搞清核心概念,掌握脉络之后,就非常顺利。它的命令格式即规范又统一,使得有些命令自己都能猜出来,这就是好的设计带来的福利。。但Jenkins给人的感觉就是开始的时候没有设计得很好,后面在不断地打补丁,导致一件事情有好几种不同的做法,对不熟悉的人来讲无所适从。没有统一的风格,处处都是意外,使得整个系统看起来既庞杂又没有章法,当然这也跟它出来的时间比较长有关。虽然它可能不是最好的,但它是免费的,因此不能要求太高。

    由于种种原因,我的Jenkins安装碰到了各种各样的问题,为此我查看了大量的资料。但遗憾的是每个人安装Jenkins的方法都有些不同,很难找到一篇文章能解决所有问题。在我看来,Jenkins的安装有两三个关键之处,非常容易出错,一定要理解透彻才能成功。

    本文分成两部分,第一部分讲正常安装步骤,如果一切顺利,就不需要看第二部分了。我只能说恭喜你,你的运气太好了。第二部分是讲各种问题及解决办法,这应该是本文最有价值的部分。

    第一部分:在 k8s上部署Jenkins

    1. 安装在什么地方?

    容器化是大势所趋,它不但包括应用程序的容器化,还包括与之相关的工具的容器化。当把Jenkins部署在K8s上时,Jenkins的主节点会根据情况自动生成子节点(新的容器)来完成任务,任务结束后会自动销毁子节点。

    我先在Windows上部署了VirtulBox虚机,并用Vagrant来管理虚机,再在虚机上部署了k8s。并通过Vagrant设置虚机和宿主机之间的网络共享,这样就可以在宿主机上用游览器直接访问k8s上的Jenkins。另外还要把宿主机的硬盘挂载到Jenkins上,这样Jenkins的物理存储还是在宿主机上,即使虚机出了问题,所有的配置和数据都不会丢失。

    2. 选择镜像文件

    这个看起来不是问题,但是一不留神就容易出错。我就是因为选错了镜像,导致安装了很多遍,最后才成功,在本文的第二部分会详细说明。我最终用的镜像文件是“jenkinsci/jenkins:2.154-slim”,后来发现这个是比较旧的版本,新的镜像 是“jenkins/jenkins:lts”, 但因为已经安装成功了,就没有再换。Jenkins真的很坑人,有三个镜像“Jenkins”,“jenkinsci/jenkins”, "jenkins/jenkins", 其中正确的是"jenkins/jenkins"。

    选好镜像之后,可以先运行下面命令,下载Jenkins镜像文件到本地(虚机上)。

    vagrant@ubuntu-xenial:~$ docker pull jenkinsci/jenkins:2.154-slim
    

    3. 安装Jenkins镜像:

    在安装之前,需要先把宿主机的Jenkins安装目录挂载到虚机上,这样可以在本地直接操作Jenkins。
    下面是Vagrant的配置文件(Vagrantfile)中的设置,它把宿主机的app目录挂载到虚机的"/home/vagrant/app"。Jenkins就安装在app目录下。

    config.vm.synced_folder "app/", "/home/vagrant/app", id: "app"
    

    下面就是在宿主机上安装好了的Jenkins目录

    file

    安装Jenkins镜像分成四部分,创建服务账户,安装持久卷,安装部署和安装服务,需要按顺序进行。其中的关键是创建服务账户,这个是必须的,没有它不会成功。不知为什么网上的有些文章没有提到它。

    服务账户配置文件(service-account.yaml):

    kind: ClusterRole
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      namespace: default
      name: service-reader
    rules:
      - apiGroups: [""] # "" indicates the core API group
        resources: ["services"]
        verbs: ["get", "watch", "list"]
      - 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: ["secrets"]
        verbs: ["get"]
    
    

    这里创建了一个名为“service-reader”的“ClusterRole”,并把特定的权限(例如["get", "watch", "list"])赋给特定的资源(例如["services"])。

    运行如下命令,创建一个名为“service-reader-pod”的集群角色绑定,它的“clusterrole”是“service-reader”,它的名字是“default:default”,其中第一个“default”是名空间(namespace),第二个“default”是服务账户名字,后面的部署配置文件会引用这个名字(default)。这里由于我没有给Jenkins创建单独的名空间,因此它用的默认名空间(“default”)。

    kubectl create clusterrolebinding service-reader-pod --clusterrole=service-reader  --serviceaccount=default:default
    

    关于服务账户的权限定义,请参阅“Kubernetes plugin for Jenkins” .

    持久卷配置文件(jenkins-volumn.yaml):

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: k8sdemo-jenkins-pv
      labels:
        app: k8sdemo-jenkins
    spec:
      capacity:
        storage: 1Gi
      # volumeMode field requires BlockVolume Alpha feature gate to be enabled.
      volumeMode: Filesystem
      accessModes:
        - ReadWriteOnce
      storageClassName: standard
      local:
        path: /home/vagrant/app/jenkins
      nodeAffinity:
        required:
          nodeSelectorTerms:
            - matchExpressions:
                - key: kubernetes.io/hostname
                  operator: In
                  values:
                    - minikube
    ---
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: k8sdemo-jenkins-pvclaim
      labels:
        app: k8sdemo-jenkins
    spec:
      accessModes:
        - ReadWriteOnce
      # storageClassName: local-storage
      resources:
        requests:
          storage: 1Gi #1 GB
    

    部署配置文件(jenkins-deployment.yaml):

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: k8sdemo-jenkins-deployment
      labels:
        app: k8sdemo-jenkins
    spec:
      selector:
        matchLabels:
          app: k8sdemo-jenkins
      strategy:
        type: Recreate
      template:
        metadata:
          labels:
            app: k8sdemo-jenkins
        spec:
          serviceAccountName: default # 服务账户的名字是default
          containers:
            - image: jenkinsci/jenkins:2.154-slim
              name: k8sdemo-jenkins-container
              imagePullPolicy: Never
              ports:
                - containerPort: 8080
                - containerPort: 50000
              volumeMounts:
                - name: k8sdemo-jenkins-persistentstorage
                  mountPath: /var/jenkins_home
          volumes:
            - name: k8sdemo-jenkins-persistentstorage
              persistentVolumeClaim:
                claimName: k8sdemo-jenkins-pvclaim
    
    

    注意,这里引用了服务账户“default”(serviceAccountName: default)。

    服务配置文件(jenkins-service.yaml):

    apiVersion: v1
    kind: Service
    metadata:
      name: k8sdemo-jenkins-service
      labels:
        app: k8sdemo-jenkins
    spec:
      type: NodePort
      selector:
        app: k8sdemo-jenkins
      ports:
        - port: 8080
          name: http
          protocol : TCP
          nodePort: 30080
          targetPort: 8080
        - port: 50000
          name: agent
          protocol: TCP
          targetPort: 50000
    
    

    这里面的一个关键点是部署和服务都暴露了两个容器端口,一个是8080,另一个是50000. “8080”是外部访问Jenkins的端口,“50000”是Jenkins内部集群之间的互相通信端口。这里的Jenkins集群不需要你搭建,而是Jenkins根据需要自动生成的,因此这两个端口是必须配置的。这里的配置命令都是比较标准的k8s配置,因此没有详细解释。

    如果你想了解k8s命令详情(包括Vagrant配置),请参阅“通过搭建MySQL掌握k8s(Kubernetes)重要概念(上):网络与持久卷”.

    运行下面命令创建Jenkins:

    kubectl apply -f jenkins-volume.yaml
    kubectl apply -f jenkins-deployment.yaml
    kubectl apply -f jenkins-service.yaml
    

    验证安装:

    获得Jenkins的Pod名

    vagrant@ubuntu-xenial:~$ kubectl get pod
    NAME                                           READY   STATUS    RESTARTS   AGE
    envar-demo                                     1/1     Running   15         27d
    k8sdemo-backend-deployment-6b99dc6b8c-tbl4v    1/1     Running   7          11d
    k8sdemo-database-deployment-578fc88c88-mm6x8   1/1     Running   9          16d
    k8sdemo-jenkins-deployment-675dd574cb-bt7rx    1/1     Running   2          24h
    

    查看Jenkins日志

    vagrant@ubuntu-xenial:~$ kubectl logs k8sdemo-jenkins-deployment-675dd574cb-bt7rx
    
    Running from: /usr/share/jenkins/jenkins.war
    webroot: EnvVars.masterEnvVars.get("JENKINS_HOME")
    Nov 02, 2019 1:33:30 AM org.eclipse.jetty.util.log.Log initialized
    INFO: Logging initialized @3749ms to org.eclipse.jetty.util.log.JavaUtilLog
    
    。。。
    
    INFO: Invalidating Kubernetes client: kubernetes null
    Nov 02, 2019 1:35:50 AM hudson.WebAppMain$3 run
    INFO: Jenkins is fully up and running
    --> setting agent port for jnlp
    --> setting agent port for jnlp... done
    

    当看到“INFO: Jenkins is fully up and running”,就说明Jenkins已经运行好了,Jenkins的第一次启动需要一定时间,要耐心等待。

    4. 登录

    前面已经讲过,你可以在Vagrant里设置宿主机和虚机之间的网络互访,我的虚机的地址是“192.168.50.4”,“30080”是Jenkins服务的NodePort的对外地址,因此可以用“http://192.168.50.4:30080/” 访问Jenkins。

    登录之前先要获得初始口令,你可以在Jenkins的“secretsinitialAdminPassword”目录里获得管理员用户初始口令,我挂载Jenkins的宿主机目录是“E:app2kubappjenkins”, 因此口令文件是“E:app2kubappjenkinssecretsinitialAdminPassword”。口令是“072d7157c090479195e0acaa97bc1049”。第一次登录之后,需要重新设置用户和口令。

    5. 安装推荐插件

    登录之后,先要安装必要的插件才能完成整个安装工程, 直接选“Install suggested plugins”就可以了。
    file

    6 安装Kubernetes Plugin

    用管理员账户登录 Jenkins主页面后,找到
    Manage Jenkins-》Manage Plugins-》Available, 勾选安装“Kubernetes plugin”即可。

    下图是安装之后的图:

    file

    7. 配置Kubernetes Plugin

    用管理员账户登录 Jenkins Master主页面后,找到
    Manage Jenkins-》Configure System-》,然后配置Kubernetes Plugin。如下图所示:

    file

    这是最重要的一个配置,决定整个安装的成败。默认的“name”是“Kubernetes“,这个不需要修改,但以后配置Pipelines时要用到。“Kubernetes URL”用 “https://kubernetes.default” 就可以了。设置之后点击“Test Connection”,见到“Connection test successful”就成功了。

    “Jenkins URL”是从外部(从虚拟机而不是宿主机)访问Jenkins的地址。
    你可以用如下命令,找到Kubernetes的“Jenkins Url”:

    vagrant@ubuntu-xenial:~$  sudo minikube service k8sdemo-jenkins-service  --url
    http://10.0.2.15:30080
    http://10.0.2.15:32289
    

    另外一个参数是“Jenkins tunnel”,这个参数是Jenkins Master和Jenkins Slave之间通信必须配置的,但不知道为什么,网上的很多文章都没提这个参数,也许是Jenkins的版本不同,有些版本可能不需要。

    查看容器名

    vagrant@ubuntu-xenial:~$ docker ps -a
    CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS                      PORTS               NAMES
    d15e30169568        f793ea0abe00            "/sbin/tini -- /usr/…"   15 minutes ago      Up 15 minutes                                   k8s_k8sdemo-jenkins-container_k8sdemo-jenkins-deployment-675dd574cb-2thn2_default_fb10e438-0231-4fd2-8dbd-d9e2f0bb9d09_0
    

    查看容器地址:

    vagrant@ubuntu-xenial:~$ docker inspect d15e |grep _8080
                    "K8SDEMO_JENKINS_SERVICE_PORT_8080_TCP_ADDR=10.100.3.79",
                    "K8SDEMO_JENKINS_SERVICE_PORT_8080_TCP=tcp://10.100.3.79:8080",
                    "K8SDEMO_JENKINS_SERVICE_PORT_8080_TCP_PROTO=tcp",
                    "K8SDEMO_JENKINS_SERVICE_PORT_8080_TCP_PORT=8080",
    

    根据上面信息,Jenkins的地址是“tcp://10.100.3.79:8080”,把8080换成50000就可以了。最终结果是“10.100.3.79:50000”,注意不要添加“http”。

    8. 测试Jenkins:

    现在Jenkins已经全部安装好了, 下面进行测试。在Jenkins主页面点击“New Item”创建新项目,如下图所示,输入项目名,然后选择“Pipeline”。

    file

    进入项目配置页面,如下图所示,脚本文件是jenkinsfile-test:

    file

    这是最简单的测试,它直接使用Jenkins主节点(主节点名是master),不需要启动子节点,因此基本上都不会有什么问题。
    在Jenkins主页面选项目“test”,然后选“Build Now”运行项目,再到“Console Output”中查看结果如下:

    Running in Durability level: MAX_SURVIVABILITY
    [Pipeline] Start of Pipeline[Pipeline] podTemplate[Pipeline] {[Pipeline] nodeRunning on Jenkins in /var/jenkins_home/workspace/test
    [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
    
    

    9. 测试子节点:

    这是复杂一点的测试,需要启动子节点,这个才能真正检测出安装的成败。先创建一个新的项目“slave-test”。

    
    def POD_LABEL = "testpod-${UUID.randomUUID().toString()}"
    podTemplate(label: POD_LABEL, cloud: 'kubernetes', containers: [
        containerTemplate(name: 'build', image: 'jfeng45/k8sdemo-backend:1.0', ttyEnabled: true, command: 'cat'),
        containerTemplate(name: 'run', image: 'jfeng45/k8sdemo-backend:1.0', ttyEnabled: true, command: 'cat')
      ]) {
    
        node(POD_LABEL) {
            stage('build a go project') {
                container('build') {
                    stage('Build a go project') {
                        sh 'echo hello'
                    }
                }
            }
    
            stage('Run a Golang project') {
                container('run') {
                    stage('Run a Go project') {
                        sh '/root/main.exe'
                    }
                }
            }
    
        }
    }
    
    

    上面是脚本(jenkins-salve-test)。其中“POD_LABEL”取任何名字都可以(在Kubernetes-plugin 1.17.0 版本之后,系统会自动命名,但以前需要自己取名),“cloud: 'kubernetes'”要与前面定义的“Kubernetes Plugin” 相匹配。它有两个stage,一个是“build”,另一个是“run”。在“podTemplate”里定义了每一个stage的镜像(这样后面的stage脚本里就可以引用),这里为了简便把两个镜像设成是一样的。因为是测试,第一个stage只是输出“echo hello”, 第二个运行镜像“jfeng45/k8sdemo-backend:1.0”里的main.exe程序。

    在Jenkins主页面选项目“slave-test”,然后选“Build Now”运行项目,再到“Console Output”中查看结果如下:

    Running in Durability level: MAX_SURVIVABILITY
    [Pipeline] Start of Pipeline[Pipeline] podTemplate[Pipeline] {[Pipeline] node
    Still waiting to schedule task
    ‘testpod-f754a7a4-6883-4be0-ba4f-c693906041ae-fjwqs-kbb7l’ is offline
    
    Agent testpod-f754a7a4-6883-4be0-ba4f-c693906041ae-fjwqs-kbb7l is provisioned from template Kubernetes Pod Template
    Agent specification [Kubernetes Pod Template] (testpod-f754a7a4-6883-4be0-ba4f-c693906041ae): 
    * [build] jfeng45/k8sdemo-backend:1.0
    * [run] jfeng45/k8sdemo-backend:1.0
    
    Running on testpod-f754a7a4-6883-4be0-ba4f-c693906041ae-fjwqs-kbb7l in /home/jenkins/workspace/slave-test
    [Pipeline] {
    [Pipeline] stage[Pipeline] { (build a go project)
    [Pipeline] container[Pipeline] {
    [Pipeline] stage
    [Pipeline] { (Build a go project)[Pipeline] sh
    + echo heollo
    heollo
    
    [Pipeline] }
    [Pipeline] // stage
    [Pipeline] }
    [Pipeline] // container
    [Pipeline] }
    
    [Pipeline] // stage
    [Pipeline] stage
    [Pipeline] { (Run a Golang project)[Pipeline] container
    [Pipeline] {[Pipeline] stage[Pipeline] { (Run a Go project)
    [Pipeline] sh
    + /root/main.exe
    time="2019-11-03T01:56:59Z" level=debug msg="connect to database "
    time="2019-11-03T01:56:59Z" level=debug msg="dataSourceName::@tcp(:)/?charset=utf8"
    time="2019-11-03T01:56:59Z" level=debug msg="FindAll()"
    time="2019-11-03T01:56:59Z" level=debug msg="user registere failed:dial tcp :0: connect: connection refused"
    
    [Pipeline] }
    [Pipeline] // stage
    
    [Pipeline] }
    [Pipeline] // container
    [Pipeline] }
    
    [Pipeline] // stage
    [Pipeline] }
    [Pipeline] // node
    
    [Pipeline] }
    [Pipeline] // podTemplate
    
    [Pipeline] End of Pipeline
    Finished: SUCCESS
    

    运行成功,测试阶段就完成了。

    用脚本来写Pipeline有两种方法,“Scripted Pipleline”和“Declarative Pipleline”,这里用的是第一种方法。详情请见“Using a Jenkinsfile”. “Declarative Pipleline”是新的方法,我在以后的文章里会讲到。这里因为是测试,只要通过了就行。

    不必须的安装步骤:

    还有些安装步骤在某些文章中提到了,但它们只是锦上添花,不是必须的。如果你的配置出现了问题,不要怀疑是这些步骤没执行造成的。

    1. 配置名空间(namespace):
      有些安装步骤为Jenkins配置了单独的名空间,这样当然更好,但你即使没有配置也不会出现问题。
    2. Kubernetes server certificate key:
      有些安装步骤提到要配置“Kubernetes server certificate key ”,但我并没有设置它,也没有影响运行。

    第二部分: 常见问题

    1. Jenkins版本不对:

    最开始用的是jenkins:2.60.3-alpine(这个已经是Jenkins镜像的最高版本了),这个版本太低,在安装插件时基本上都不成功,如下图

    file

    后来换成jenkins:latest,这个应该是最新的吧,结果 版本还是一样的,只不过Linux不是Apline的。

    后来终于明白了是镜像错了(而不是版本的问题),是要用Jenkinsci, 而不是Jenkins。我用了当时排在第一位的jenkinsci/jenkins:2.150.1-slim,安装之后,上面的插件错误全部消失了,真不容易。

    2. 不支持Kubernetes Plugin

    但当安装Kubernetes Plugin插件时,提示需要 2.150.3(我的是2.150.1),这也太坑了。只好再次重装,这次用的是jenkinsci/jenkins:2.154-slim,还好终于成功了。不过这个其实还是以前的镜像,最新的在“jenkins/jenkins”。

    3. 不能访问Kubernetes

    错误信息如下:

    Forbidden!Configured service account doesn't have access. Service account may have been revoked. User "system:serviceaccount:default:default" cannot get services in the namespace "default"
    

    详情请参见Kubernetes log, User “system:serviceaccount:default:default” cannot get services in the namespace

    错误原因是没有建立service account。解决办法是先创建“service-account.yaml”文件,然后运行如下命令:

    kubectl create clusterrolebinding service-reader-pod --clusterrole=service-reader  --serviceaccount=default:default
    

    再次运行,错误消失。

    4. Jenkins URL地址不对

    在Jenkins主页面,进入Manage Jenkins-》System Log-》All Jenkins Logs, 错误信息如下。

    SEVERE: http://192.168.50.4:30080/ provided port:50000 is not reachable
    java.io.IOException: http://192.168.50.4:30080/ provided port:50000 is not reachable
         at org.jenkinsci.remoting.engine.JnlpAgentEndpointResolver.resolve(JnlpAgentEndpointResolver.java:303)
         at hudson.remoting.Engine.innerRun(Engine.java:527)
         at hudson.remoting.Engine.run(Engine.java:488)
    

    这个错误主要是和Kubernetes-plugin配置有关。在Jenkins主页面,进入Manage Jenkins-》Configure System》,在“http://192.168.50.4:30080/configure” 里有两个“Jenkins URL”,不要弄混了。
    第一个是“Jenkins Location”下的“Jenkins URL”, 它是宿主机访问Jenkins的地址。

    file

    第二个是“Cloud”下的“Jenkins URL”, 它是从虚拟机访问Jenkins的地址。

    file

    在上图中,我开始时用的是“http://192.168.50.4:30080/” ,但这个是从宿主机访问Jenkins的Url,不是从虚机内部访问的Url。
    你可以用如下命令,找到Kubernetes的“Jenkins Url”

    vagrant@ubuntu-xenial:~$  sudo minikube service k8sdemo-jenkins-service  --url
    http://10.0.2.15:30080
    http://10.0.2.15:32289
    

    键入如下命令测试URL。

    vagrant@ubuntu-xenial:~$ curl http://10.0.2.15:30080
    <html><head><meta http-equiv='refresh' content='1;url=/login?from=%2F'/><script>window.location.replace('/login?from=%2F');</script></head><body style='background-color:white; color:white;'>
    
    Authentication required
    <!--
    You are authenticated as: anonymous
    Groups that you are in:
    
    Permission you need to have (but didn't): hudson.model.Hudson.Read
    ... which is implied by: hudson.security.Permission.GenericRead
    ... which is implied by: hudson.model.Hudson.Administer
    -->
    
    </body></html> 
    

    这就说明URL是好的。

    5. 不能连接slave

    “Jenkins Url”改了之后,地址是对的,但还是不通。运行项目时,页面显示如下信息:

    file

    “Console Output”(在Jenkins->salve-test->#13中,其中#13是build #)显示如下信息:

    Running in Durability level: MAX_SURVIVABILITY
    [Pipeline] Start of Pipeline[Pipeline] podTemplate[Pipeline] {[Pipeline] node
    Still waiting to schedule task
    ‘testpod-d56038a0-45a2-41d1-922d-2879e3610900-0hr0m-sfv8s’ is offline
    

    后来发现还有一个参数要填写,就是“Jenkins tunnel”。如下图所示。

    file

    详情请见 Kubernetes Jenkins plugin - slaves always offline.

    填写之后原来的信息没有了,而且出现了“Agent discovery successful”,这个信息是原来没有的。但又有新的错误。
    可用如下方法查看系统日志,在Jenkins主页面,选择Manage Jenkins-》System Log-》All Jenkins Logs, 信息是这样的:

    INFO: Agent discovery successful
      Agent address: http://10.0.2.15
      Agent port:    50000
      Identity:      3e:1b:5f:48:f7:5b:f8:6d:ea:49:1d:b9:44:9a:2f:6c
    Oct 30, 2019 12:18:51 AM hudson.remoting.jnlp.Main$CuiListener status
    INFO: Handshaking
    Oct 30, 2019 12:18:51 AM hudson.remoting.jnlp.Main$CuiListener status
    INFO: Connecting to http://10.0.2.15:50000
    Oct 30, 2019 12:18:51 AM hudson.remoting.jnlp.Main$CuiListener error
    SEVERE: null
    java.nio.channels.UnresolvedAddressException
         at sun.nio.ch.Net.checkAddress(Net.java:101)
         at sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:622)
         at java.nio.channels.SocketChannel.open(SocketChannel.java:189)
         at org.jenkinsci.remoting.engine.JnlpAgentEndpoint.open(JnlpAgentEndpoint.java:203)
         at hudson.remoting.Engine.connectTcp(Engine.java:678)
         at hudson.remoting.Engine.innerRun(Engine.java:556)
         at hudson.remoting.Engine.run(Engine.java:488)
    

    它的原因是“JenkinsTunnel”的地址还是不对,可用如下方法找到“Jenkins tunnel”地址:

    vagrant@ubuntu-xenial:~$ docker ps -a
    CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS                      PORTS               NAMES
    d15e30169568        f793ea0abe00            "/sbin/tini -- /usr/…"   15 minutes ago      Up 15 minutes                                   k8s_k8sdemo-jenkins-container_k8sdemo-jenkins-deployment-675dd574cb-2thn2_default_fb10e438-0231-4fd2-8dbd-d9e2f0bb9d09_0
    
    vagrant@ubuntu-xenial:~$ docker inspect d15e |grep _8080
                    "K8SDEMO_JENKINS_SERVICE_PORT_8080_TCP_ADDR=10.100.3.79",
                    "K8SDEMO_JENKINS_SERVICE_PORT_8080_TCP=tcp://10.100.3.79:8080",
                    "K8SDEMO_JENKINS_SERVICE_PORT_8080_TCP_PROTO=tcp",
                    "K8SDEMO_JENKINS_SERVICE_PORT_8080_TCP_PORT=8080",
    

    根据上面信息,Jenkins容器地址是“tcp://10.100.3.79:8080”,把8080换成50000就可以了。最终结果是“10.100.3.79:50000”,注意不要添加“http”。
    详情请见 What setting to use for jenkins tunnel?

    6. 镜像问题

    当使用的镜像文件是“k8sdemo-backend:latest”或“k8sdemo-backend:1.0”时,“Console Output”显示错误如下:

    Running in Durability level: MAX_SURVIVABILITY
    [Pipeline] Start of Pipeline[Pipeline] podTemplate[Pipeline] {[Pipeline] nodeStill waiting to schedule task
    All nodes of label ‘testpod-2971e0ce-e023-475f-b0ec-6118c5699188’ are offline
    Aborted by admin[Pipeline] // node
    [Pipeline] }
    [Pipeline] // podTemplate
    [Pipeline] End of Pipeline
    Finished: ABORTED
    

    查看Pod, 错误是“ImagePullBackOff”:

    vagrant@ubuntu-xenial:~$ kubectl get pod
    NAME                                                       READY   STATUS             RESTARTS   AGE
    envar-demo                                                 1/1     Running            15         28d
    k8sdemo-backend-deployment-6b99dc6b8c-tbl4v                1/1     Running            7          12d
    k8sdemo-database-deployment-578fc88c88-mm6x8               1/1     Running            9          17d
    k8sdemo-jenkins-deployment-675dd574cb-bt7rx                1/1     Running            2          2d
    testpod-2971e0ce-e023-475f-b0ec-6118c5699188-xwwqq-vv59p   2/3     ImagePullBackOff   0          38s
    

    查看镜像:

    vagrant@ubuntu-xenial:~$ docker image ls
    REPOSITORY                                TAG                 IMAGE ID            CREATED             SIZE
    jfeng45/k8sdemo-backend                   1.0                 f48d362fdebf        11 days ago         14.4MB
    k8sdemo-backend                           1.0                 f48d362fdebf        11 days ago         14.4MB
    k8sdemo-backend                           latest              f48d362fdebf        11 days ago         14.4MB
    

    这里一共有三个“k8sdemo-backend”镜像,它们的“Image ID”都是一样的,之所以有三个是因为我用如下命令创建了tag

    docker tag k8sdemo-backend jfeng45/k8sdemo-backend:1.0
    

    但创建了之后,就只有“jfeng45/k8sdemo-backend:1.0”(最晚创建的)能够用在Jenkins的Pipeline脚本里,其他两个都会报错。修改了正确的镜像文件之后就运行成功了。

    7. pv和pvc删除慢

    当用以下命令删除pv时,命令迟迟不能返回。

    kubectl delete pv k8sdemo-jenkins-pv
    

    当你查看时,状态(status)显示一直是“Terminating”,但总是不能结束退出。pvc也是一样。

    vagrant@ubuntu-xenial:~$ kubectl get pv
    NAME                  CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS        CLAIM                              STORAGECLASS   REASON   AGE
    k8sdemo-backend-pv    1Gi        RWO            Retain           Bound         default/k8sdemo-backend-pvclaim    standard                13d
    k8sdemo-database-pv   1Gi        RWO            Retain           Bound         default/k8sdemo-database-pvclaim   standard                18d
    k8sdemo-jenkins-pv    1Gi        RWO            Retain           Terminating   default/k8sdemo-jenkins-pvclaim    standard                6d8h
    

    这个主要原因是用到它们的服务和部署还在运行,先把服务和部署删除之后,pv和pvc的删除操作就马上结束,顺利返回了。

    源码:

    完整源码的github链接

    注意,本文的程序在0.1(tag)下,这个程序的主分支以后还会修改。

    下面是程序的目录结构,黄色部分是与本文有关的配置文件。

    file

    索引:

    1. Kubernetes plugin for Jenkins
    2. 通过搭建MySQL掌握k8s(Kubernetes)重要概念(上):网络与持久卷
    3. Using a Jenkinsfile
    4. Kubernetes log, User “system:serviceaccount:default:default” cannot get services in the namespace
    5. Kubernetes Jenkins plugin - slaves always offline.
    6. What setting to use for jenkins tunnel?
    7. 初试 Jenkins 使用 Kubernetes Plugin 完成持续构建与发布

    本文由博客一文多发平台 OpenWrite 发布!

  • 相关阅读:
    Auto X2021 K Increasing Sequence
    拉普拉斯平滑处理 Laplace Smoothing
    博学之
    Python-生成音乐-pyshnth
    Python-Kivy ImportError: DLL load failed: 找不到指定的模块
    Python-Word模板填充-docxtpl
    Python-文字转语音-pyttsx3
    Virtual Box中Ubuntu使用"桥接网卡"不能联网而使用"网络地址转换(NAT)"却可以上网
    STM32的HAL库中的DMA_FLAG_TCIF3_7等几个宏定义的含义
    Linux下编写互相通信的驱动模块并将其加入到内核中
  • 原文地址:https://www.cnblogs.com/code-craftsman/p/11792635.html
Copyright © 2011-2022 走看看