Jenkins kubernetes 代理结帐 scm 未使用配置的密钥

Posted

技术标签:

【中文标题】Jenkins kubernetes 代理结帐 scm 未使用配置的密钥【英文标题】:Jenkins kubernetes agent checkout scm not using configured key 【发布时间】:2021-05-03 14:44:40 【问题描述】:

由于两个问题,我在管道中使用 checkout scm 时遇到错误。

设置:

私有 Kubernetes 集群 - 1 个控制器,2 个工作器,在 Ubuntu 20.04 虚拟机上 在 Kubernetes pod 中运行的 Jenkins 用于实例化 Jenkins 构建代理的 Kubernetes 插件 集群外控制器 VM 上的私有 GIT 服务器,ssh 访问 在 Jenkins 凭据中配置的 GIT 的 ssh 私钥 Jenkins 项目“hello”配置为使用此私有 GIT 和关联的 ssh 密钥 要构建的 Jenkinsfile(管道)

我想在 Jenkinsfile 中使用一个简单的checkout scm 步骤。

问题 1 构建失败并显示 Host key verification failed.,因为 Kubernetes 代理 pod 在其 known_hosts 中没有 GIT 服务器。

问题 2 如果我将控制器证书强制输入 known_hosts(例如,将 echo 硬编码到 Jenkinsfile 中,然后添加 git ls-remote 步骤),它会失败并显示 Permission denied因为代理 pod 中不存在配置的 ssh 私钥。

我已经找到了解决这两个问题的方法:

podTemplate(
...

  node(POD_LABEL) 
    stage('Checkout') 
      withCredentials([sshUserPrivateKey(
          credentialsId: 'private_git', 
          keyFileVariable: 'PRIVATE_GIT_KEY',
          passphraseVariable: '',
          usernameVariable: ''
      )]) 
        sh 'mkdir -p ~/.ssh'
        sh 'cp $PRIVATE_GIT_KEY ~/.ssh/id_rsa'
        sh '/usr/bin/ssh-keyscan -t rsa kube-master.cluster.dev >> ~/.ssh/known_hosts'
        sh 'chown -R $USER:$USER ~/.ssh'
        sh '/usr/bin/git ls-remote ssh://git@kube-master.cluster.dev:/git/hello.git'
      
      checkout scm
    
  ...
  

我需要什么来避免这种变通方法并按预期使用checkout scm

失败日志示例:

Running on build-pod-xdh86-53wh7 in /home/jenkins/agent/workspace/hello
[Pipeline] 
[Pipeline] stage
[Pipeline]  (Checkout)
[Pipeline] checkout
Selected Git installation does not exist. Using Default
The recommended git tool is: NONE
using credential private_git
Cloning the remote Git repository
ERROR: Error cloning remote repo 'origin'
hudson.plugins.git.GitException: Command "git fetch --tags --force --progress -- ssh://git@kube-master.cluster.dev/git/hello.git +refs/heads/*:refs/remotes/origin/*" returned status code 128:
stdout: 
stderr: Host key verification failed.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

【问题讨论】:

【参考方案1】:

一个合理的解决方案是将密钥放在 Kubernetes secrets 中,并将 secrets 挂载到 Jenkins pod 中。

在您的控制器机器上:

    创建一个临时用户帐户并进入其中

    制作秘密(典型的 ssh-keygen)

    id_rsa.pub添加到git服务器authorized_users

    连接git ssh一次,产生known_hosts,例如

    git ls-remote ssh://git@kube-master.cluster.dev:/git/hello.git

    将scratch用户的~/.ssh/id_rsa私钥和~/.ssh/known_hosts文件复制到kubectl可以读取的地方,比如/tmp/scratchuser

    退出临时用户帐户并将其删除

    sudo chown -R $USER:$USER /tmp/scratchuser/

    id_rsaknown_hosts 添加到Kubernetes,使用类似的命令

    kubectl create secret -n jenkins generic private-git --from-file=id_rsa=/tmp/scratchuser/.ssh/id_rsa --from-file=known_hosts=/tmp/scratchuser/.ssh/known_hosts

    使用包含一些特定内容的 yaml 部署 Jenkins:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: jenkins
      namespace: jenkins
    spec:
      ... your other options such as replicas, selector, etc ...
      template:
        metadata: ... your metadata section ...
        spec:
          securityContext:
            fsGroup: 1000
          containers:
          - name: jenkins
            image: jenkins/jenkins:lts
            ports:
              ... standard jenkins ports ...
            volumeMounts:
              - name: jenkins-vol
                mountPath: /var/jenkins_home
              - name: private-git-vol
                mountPath: "/var/jenkins_home/.ssh"
                readOnly: true
          volumes:
            - name: jenkins-vol
              ... your persistent volume details ...
            - name: private-git-vol
              secret:
                secretName: private-git
                defaultMode: 0600
          ... your other options such as dnsPolicy, etc. ...
    

上述yaml中的关键点是fsGroup,以便pod用户jenkins可以访问挂载的秘密卷,private-git-vol挂载将秘密文件放入.ssh路径,private-git-vol引用上面使用kubectl 创建的秘密的定义。

还有一个提示。有关实例化构建代理 pod 的 Jenkinsfile,请参阅 Declarative Pipeline。您可能需要放弃 podTemplate() 并完全指定代理 pod yaml:

pipeline 
  agent 
    kubernetes 
      yamlFile 'KubernetesPod.yaml'
    
  ... your build steps ...

KubernetesPod.yaml 中,将jnlp 容器(jenkins/inbound-agent 映像)包含在您自己的 yaml 中,而不是 Kubernetes 插件。这将允许您在构建代理中使用fsGroup,就像上面针对 Jenkins 主服务器所描述的那样。

【讨论】:

以上是关于Jenkins kubernetes 代理结帐 scm 未使用配置的密钥的主要内容,如果未能解决你的问题,请参考以下文章

Jenkins- Jenkins的代理

Jenkins-Kubernetes插件实现使用Pod作为 Agent-超详细

带有 git 私有仓库的 Jenkins kubernetes 插件

使用 DB 运行 Spring Boot 测试时,Jenkins 代理作业被终止

Kubernets traefik代理ws wss应用

Jenkins Pipeline第一次演进