如何从一个私有注册表中提取Docker映像并将其推送到Jenkins管道中的另一个不同的私有注册表

如何从一个私有注册表中提取Docker映像并将其推送到Jenkins管道中的另一个不同的私有注册表,docker,jenkins,jenkins-pipeline,Docker,Jenkins,Jenkins Pipeline,我可以从Jenkins连接到两个私有注册中心,我可以提取我想要的映像,但是我不知道如何将同一映像推送到不同的回购协议 注意,我使用脚本管道语法,因为据我所知,声明性语法不支持推/拉或自定义注册表。我也不熟悉Groovy语法 以下是我到目前为止为我的Jenkins文件得到的信息: node { checkout scm docker.withRegistry('https://private-registry-1', 'credentials-1') { def

我可以从Jenkins连接到两个私有注册中心,我可以提取我想要的映像,但是我不知道如何将同一映像推送到不同的回购协议

注意,我使用脚本管道语法,因为据我所知,声明性语法不支持推/拉或自定义注册表。我也不熟悉Groovy语法

以下是我到目前为止为我的Jenkins文件得到的信息:

node {
    checkout scm

    docker.withRegistry('https://private-registry-1', 'credentials-1') {
        def image = docker.image('my-image:tag')
        image.pull()

        docker.withRegistry('https://private-registry-2', 'credentials-2') {
            image.push()
        }
    }
}
我将第二个“withRegistry()”方法放在第一个方法中,以便使用已定义的“image”变量

我成功连接到第一个注册表并提取最新的映像。从Jenkins控制台输出:

Login Succeeded
[Pipeline] {
[Pipeline] sh
+ docker pull private-registry-1/my-image:tag
tag: Pulling from my-image
Digest: sha256:XXXXX
Status: Image is up to date for private-registry-1/my-image:tag
但是,以下是连接到第二个注册表后的相关错误片段:

...
Login Succeeded
[Pipeline] {
[Pipeline] sh
+ docker tag my-image:tag private-registry-2/my-image:tag
Error response from daemon: No such image: my-image:tag
...
我正在本地Windows计算机上使用Jenkins容器。它通过我的Ubuntu终端(Linux的Windows子系统)连接到Docker for Windows


解决方案是在推送图像之前标记图像,最终代码:

node {
    checkout scm

    stage 'Pull latest image from private-registry-1'

    def image
    docker.withRegistry('https://private-registry-1', 'credentials-1') {
        image = docker.image('my-image:tag')
        image.pull()
    }

    stage 'Push image to private-registry-2'

    // SOLUTION START
    sh 'docker tag private-registry-1/my-image:tag private-registry-2/my-image:tag'
    image = docker.image('private-registry-2/my-image:tag')
    // SOLUTION END

    docker.withRegistry('https://private-registry-2', 'credentials-2') {
        image.push()
    }
}

我不喜欢通过“sh”手动完成标记,但我找不到通过内置Docker语法完成标记的方法。我还需要参数化图像名称和标签(我的图像:标签),以备将来使用。

多亏了VictoryShoe的回答

有一件事很重要,我花了很长时间才发现错误:

  • “docker.withRegistry('https://private-registry-x',credentials-x')”->不要忘记在注册表URL前面添加“https://”
  • 在命令行“sh'docker tag private-registry-1/my image:tag private-registry-2/my image:tag”中,请不要在注册表URL前面添加任何“https://”
以下文件对我有效:

PS:在我的用例中,我从DockerHub中提取一个源映像,标记这个映像,然后将这个目标映像推送到一个私有公司映像注册表

def registryCredentials1 = "cridentialIdOfJenkinsForRegistry1"
def registryCredentials2 = "cridentialIdOfJenkinsForRegistry2"
def protocol = "https://"
def registryURL1 = "registry.hub.docker.com"
def registryURL2= "harbor.mycompany.xx.yy.com"

pipeline {
    agent any

    parameters {
         string(name: 'sourceImageName', defaultValue: '', description: 'Source-Image-Name, name-schema is like user/foo, e.g. jenkins/jenkins')
         string(name: 'sourceImageTag', defaultValue: '', description: 'Source-Image-Tag, e.g. lts')
         string(name: 'targetImageName', defaultValue: '', description: 'Target-Image-Name, name-schema is like user/foo, e.g. jenkins/jenkins')
         string(name: 'targetImageTag', defaultValue: '', description: 'Target-Image-Tag, e.g. lts')
    }

    stages {

        stage('Pull source-image from Registry 1 & tag the image') {
            steps {
                script {
                    //pull source-image from registry 1
                    docker.withRegistry(protocol + registryURL1, registryCredentials1) {
                        docker.image("${params.sourceImageName}:${params.sourceImageTag}").pull()
                    }

                    //tag the image
                    sh "docker tag ${registryURL1}/${params.sourceImageName}:${params.sourceImageTag} ${registryURL2}/${params.targetImageName}:${params.targetImageTag}"
                }
            }
        }

        stage('push target-image to Registry 2') {
            steps {
                script {
                    //push target-image to registry 2
                    docker.withRegistry(protocol + registryURL2, registryCredentials2) {
                        sh "docker push ${registryURL2}/${params.targetImageName}:${params.targetImageTag}"
                    }
                }
            }
        }
    }
}

对于声明性语法,以下内容适用于我:

pipeline {
    agent {
        docker {
            label 'service'
            alwaysPull false
            registryUrl "${my-private-docker-registry_url_with_https}"
            registryCredentialsId "${jenkins_credential_id_for_login}"
            image 'lambci/lambda:build-python3.7'
            args '-v /var/run/docker.sock:/var/run/docker.sock --network host'
        }
    }

需要使用切换注册表时应用于现有映像的新标记更新映像对象。感谢您的帮助!您还知道我如何在不使用
sh“docker tag…”的情况下标记图像吗?
?因此我认为全局var文档可以在线获得,但显然不行,因此我不得不放弃以前的工作。您可以通过两种方式使用示例执行此操作:
image.tag('private-registry-2/my image:tag')
,但您可能更喜欢像
image.push('private-registry-2/my image:tag')
,它指定了与生成图像时使用的标记不同的标记,如有必要,还可以在推送之前先用新标签标记图像。e、 g.
image.push('my-tag:1.0')
本质上是在推之前用
my-tag:1.0
重新标记它。似乎
image.tag()
不是这样工作的。它没有替换现有标记,而是将其追加,例如:当我使用
image.tag('private-registry-2/my image:tag')
时,管道脚本将其作为
docker-tag-my-image:tag-my-image:private-registry-2/my-image:tag
运行。这在
image.push()
中也会发生,您可以将标记名传递给image.push()方法调用,例如直接在eshotJenkins上的“image.push('private-registry-2/my image:tag')”有时非常粗糙。我试图在没有任何运气的情况下传递标签以推动功能。似乎它试图将这两个标记附加在一起。