如何在Jenkins流水线中使用多个Docker仓库

13

我有一个Jenkins流水线,需要登录两个不同的Docker仓库。我知道如何使用以下命令对一个仓库进行身份验证:

docker.withRegistry('https://registry.example.com', 'credentials-id')

但是不知道如何对超过1个代码库执行此操作?


您可以在管道的不同阶段之间切换这两个选项。 - Matt Schuchard
你能举个例子详细说明一下吗? - HHH
他想在进行Docker构建时从两个Docker仓库中拉取内容。(请注意,这与两个Git存储库无关) - Lee Meador
嗨,你找到解决方案了吗? - jhagege
4个回答

6
嵌套 docker.withRegistry 调用实际上可以按预期工作。每次调用都会添加提供的凭据到 /home/jenkins/.dockercfg 文件中。
// Empty registry ('') means default Docker Hub `https://index.docker.io/v1/`
docker.withRegistry('', 'dockerhub-credentials-id') {
  docker.withRegistry('https://private-registry.example.com', 'private-credentials-id') {
    // your build steps ...
  }
}

这使您可以在使用提供的凭据时从Docker Hub拉取基础镜像以避免最近引入的拉取限制,并将结果推送到另一个Docker注册表。


3
这个不再起作用了,调用withRegistry会创建一个临时的docker配置文件,每次调用都会更改。例如,“警告!您的密码将以未加密的形式存储在/home/ubuntu/workspace/test@tmp/af4e4211-ee8e-4510-9efe-734d6329990d/config.json中。”https://issues.jenkins.io/browse/JENKINS-58837 - RyanD
如果这个方法不起作用,那么应该推荐使用什么方法来解决? - Eddy Hernandez

2
虽然其他答案提供了一些使用脚本化流水线语法来运行多个Docker仓库的好选择,但也有内置支持声明性语法的支持。
Jenkins的声明性pipeline syntax支持在来自自定义注册表(仓库)的Docker代理上运行作业,或者使用动态构建的Dockerfile,该Dockerfile可以基于来自自定义注册表的镜像。
以下是有关这两个选项的更多信息:
1. Docker代理
执行给定容器的流水线或阶段,该容器将在预先配置为接受基于Docker的流水线的节点上动态配置,或者在与可选定义的标签参数匹配的节点上动态配置。 docker还可选择接受registryUrl和registryCredentialsId参数,这将有助于指定要使用的Docker注册表及其凭据。参数registryCredentialsId可以单独用于docker hub中的私有仓库。例如:
agent {
    docker {
        image 'myregistry.com/node'
        label 'my-defined-label'
        registryUrl 'https://myregistry.com/'
        registryCredentialsId 'myPredefinedCredentialsInJenkins'
    }
}
  1. dockerfile

使用源代码库中的Dockerfile构建一个容器,执行Pipeline或阶段。要使用此选项,Jenkinsfile必须从多分支Pipeline或SCM Pipeline中加载。
dockerfile还可以选择接受registryUrl和registryCredentialsId参数,用于指定要使用的Docker Registry及其凭据。例如:

agent {
    dockerfile {
        filename 'Dockerfile.build'
        dir 'build'
        label 'my-defined-label'
        registryUrl 'https://myregistry.com/'
        registryCredentialsId 'myPredefinedCredentialsInJenkins'
    }
}

您可以在每个阶段使用这两个选项,这意味着在每个阶段使用不同的图像和注册表。
pipeline {
   stages {
      stage('First') {
         agent {
            docker {
               ...  // First registry
            }
         }
         steps {
            ...
         }
      }
      stage('Second') {
         agent {
            docker {
               ...  // Second registry
            }
         }
         steps {
            ...
         }
      }
   }
}

如果需要,可以通过在阶段中使用script块将声明性语法与脚本语法结合使用,其中可以使用脚本语法。例如:
pipeline {
    agent {
        docker {
            image 'myregistry.com/node'
            registryUrl 'https://myregistry.com/'
            registryCredentialsId 'myPredefinedCredentialsInJenkins'
        }
    }
    stages {
        stage("Build") {
            steps {
                script {
                    echo 'Using custom registry https://myregistry2.com/'
                    docker.withRegistry('https://myregistry2.com/', 'myPredefinedCredentialsInJenkins2') {
                        // Use the second registry here
                    }
                }
            }
        }
    }
}



如果所有内置的方法都不能按照您的预期工作,您可以随时创建自己的实现,并通过共享库在整个流水线中使用它。
例如,您可以在一个名为useDockerRegistry.groovy的文件中创建以下共享库方法:
def call(String registry, String credentialsId, Closure body) {
    println "Log in to ${registry}"
    withCredentials([usernamePassword(credentialsId: 'credentialsId', usernameVariable: 'DOCKER_USERNAME', passwordVariable: 'DOCKER_PASSWORD')]) {
        sh "docker login -u \$DOCKER_USERNAME -p \$DOCKER_PASSWORD ${registry}"
    }
    try {
        body()
    }
    finally {
        println "Log out from ${registry}"
        sh "docker logout ${registry}"     // clean up the session
    }
}

然后在您的管道中,您可以将其用于单个注册表或多个嵌套注册表。
例如:
library "myLib"

pipeline {
   agent any
   stages {
      stage('Single Registry') { 
         steps {
            useDockerRegistry('https://myregistry.com/', 'registryCredentials') {
               ... // code using myregistry
            }
         }
      }
      stage('Multiple Registries') {
         steps {
            useDockerRegistry('https://myregistry.com/', 'registryCredentials') {
                useDockerRegistry('https://myregistry2.com/', 'registry2Credentials') {
                ... // code using myregistry & myregistry2
                }
            }
         }
      }
   }
}

你可以嵌套任意多个useDockerRegistry调用。
此外,根据你的需求,你可以轻松修改函数的逻辑。

2

当您正在使用两个注册表但只需要一个注册表的凭据时,可以使用此部分答案。您可以嵌套调用,因为它们基本上只执行保持活动状态的docker登录,并将注册表域名添加到docker推送等操作中。

在脚本化的Jenkins pipeline或声明性Jenkins pipeline的脚本{ }部分中使用此代码:

docker.withRegistry('https://registry.example1.com') { // no credentials here
    docker.withRegistry('https://registry.example2.com', 'credentials-id') { // credentials needed
        def container = docker.build('myImage')
        container.inside() {
            sh "ls -al" // example to run on the newly built 
        }
    }
}

有时候你可以连续使用两个不嵌套的docker.withRegistry()调用,但在构建过程中却不能这样做。比如,如果Dockerfile中第一个FROM所需的基础镜像位于一个仓库,而第二个FROM所需的基础镜像位于另一个仓库,则无法连续使用两次。

-1
以下是一个使用多个Docker仓库的Jenkins流水线,用于身份验证、构建和推送它们。
pipeline {
    agent any
    
    environment {
        DOCKER_REGISTRY_1 = 'https://first.registry.com'
        DOCKER_REGISTRY_2 = 'https://second.registry.com'
        CREDENTIALS_ID_1 = 'credentials-id-1'
        CREDENTIALS_ID_2 = 'credentials-id-2'
    }

    stages {
        stage('Build and Push Image to Registry 1') {
            steps {
                script {
                    // Authenticate with the first Docker registry
                    docker.withRegistry(DOCKER_REGISTRY_1, CREDENTIALS_ID_1) {
                        // Build and push your Docker image to the first registry
                        docker.build('your-image-name:tag').push()
                    }
                }
            }
        }

        stage('Build and Push Image to Registry 2') {
            steps {
                script {
                    // Authenticate with the second Docker registry
                    docker.withRegistry(DOCKER_REGISTRY_2, CREDENTIALS_ID_2) {
                        // Build and push your Docker image to the second registry
                        docker.build('your-image-name:tag').push()
                    }
                }
            }
        }

        // Add more stages if required
    }
}

使用上述流程应该能解决您的问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接