azure-devopsazure-pipelinesazure-container-registry

Build image from one registry, push to different ACR registry


Due to my CI/CD pipeline hitting dockerhubs throttling (429 - too many requests) I am trying to build an image in one step (base image is comming from dockerhub) and push that image to my ACR in another step, but I am always running into this error

An image does not exist locally with the tag: ***/myimage.

My pipeline:

    - task: Docker@2
      displayName: 'Build image'
      inputs:
        containerRegistry: '$(container.registry_dockerhub)'
        repository: '$(container.name)'
        Dockerfile: '**/Dockerfile'
        command: 'build'
        tags: |
          latest
          $(projectversion)
        arguments: --build-arg PIP_EXTRA_INDEX_URL=$(PIP_EXTRA_INDEX_URL)
    - task: Docker@2
      displayName: 'Push image'
      inputs:
        containerRegistry: '$(container.registry_acr)'
        repository: '$(container.name)'
        command: 'push'
        tags: |
          latest
          $(projectversion)

How can I structure my pipeline to make this push work?


Solution

  • When building the Docker image with an authorized registry, the full name of the built image will contain the server URL of the registry. For example, docker.io/{namespace}/{repository}:{tag} (can be shorted as {namespace}/{repository}:{tag}) for authorized Docker Hub registry, {acr-name}.azurecr.io/{repository}:{tag} for authorized ACR registry.

    You cannot directly push an image which is authorized for Docker Hub to ACR or other registries. You need to re-tag the image to generate a new image that contains the registry which you want to push to.

    See below sample as reference:

    # Replace '{namespace}' and '{repository}' with the acutal names on your side.
    # And provide the acutal names of the service connections and ACR.
    variables:
      DockerHub_Connection: 'xxxx'
      DockerHub_Repository: '{namespace}/{repository}'
      ACR_Connection: 'xxxx'
      ACR_Name: 'xxxx'
      ACR_Repository: '{repository}'
      . . .
    
    steps:
    - task: Docker@2
      displayName: 'Build image'
      inputs:
        containerRegistry: '$(DockerHub_Connection)'
        repository: '$(DockerHub_Repository)'
        Dockerfile: '**/Dockerfile'
        command: 'build'
        tags: |
          latest
          $(projectversion)
        arguments: --build-arg PIP_EXTRA_INDEX_URL=$(PIP_EXTRA_INDEX_URL)
    
    - bash: |
        docker tag $(DockerHub_Repository):latest $(ACR_Name).azurecr.io/$(ACR_Repository):latest
        docker tag $(DockerHub_Repository):$(projectversion) $(ACR_Name).azurecr.io/$(ACR_Repository):$(projectversion)
      displayName: 'Tag image'
    
    - task: Docker@2
      displayName: 'Push image To ACR'
      inputs:
        containerRegistry: '$(ACR_Connection)'
        repository: '$(ACR_Repository)'
        command: 'push'
        tags: |
          latest
          $(projectversion)
    

    If the base image set in your Dockerfile is public on Docker Hub, you also can directly build the image for ACR registry, instead of building it for Docker Hub registry.

    variables:
      ACR_Connection: 'xxxx'
      ACR_Repository: '{repository}'
      . . .
    
    steps:
    - task: Docker@2
      displayName: 'Build Image'
      inputs:
        containerRegistry: '$(ACR_Connection)'
        repository: '$(ACR_Repository)'
        command: 'build'
        Dockerfile: '**/Dockerfile'
        tags: |
          latest
          $(projectversion)
        arguments: '--build-arg PIP_EXTRA_INDEX_URL=$(PIP_EXTRA_INDEX_URL)'
    
    - task: Docker@2
      displayName: 'Push Image'
      inputs:
        containerRegistry: '$(ACR_Connection)'
        repository: '$(ACR_Repository)'
        command: 'push'
        tags: |
          latest
          $(projectversion)
    

    EDIT:

    You need to set up two Docker Registry service connection:

    enter image description here