GoogleContainerTools / kaniko

Build Container Images In Kubernetes
Apache License 2.0
14.88k stars 1.44k forks source link

Registry map doesn't work on air-gapped environments #3182

Open joaojacome opened 5 months ago

joaojacome commented 5 months ago

Actual behavior Whenever pulling images from a mapped registry, Kaniko is trying to access the original registry. This makes the build on air-gapped environments fail.

2.199 INFO[0001] Retrieving image manifest alpine:latest      
2.199 INFO[0001] Retrieving image alpine:latest from mapped registry my-registry.io 
2.201 WARN[0001] Failed to retrieve image alpine:latest from remapped registry my-registry.io: unable to complete operation after 0 attempts, last error: Get "https://index.docker.io/v2/": dial tcp 127.0.0.1:443: connect: connection refused. Will try with the next registry, or fallback to the original registry. 
2.201 INFO[0001] Retrieving image alpine:latest from registry index.docker.io 
2.201 error building image: unable to complete operation after 0 attempts, last error: Get "https://index.docker.io/v2/": dial tcp 127.0.0.1:443: connect: connection refused

Expected behavior

I'd expect the original registry not to be called.

To Reproduce Steps to reproduce the behavior:

  1. Create a Dockerfile with

    FROM gcr.io/kaniko-project/executor:debug as kaniko
    RUN echo "FROM alpine:latest" >> /workspace/Dockerfile
    RUN /kaniko/executor --registry-map "index.docker.io=my-registry.io/docker.io" --destination my-registry.io/my-image:latest
  2. Build it with docker build . --add-host=index.docker.io:127.0.0.1

Additional Information

joaojacome commented 5 months ago

This change here fixed it for me, but it doesn't look good, and it was done in a trial-and-error basis. I'm not familiar with the code base (or golang), so I'd refrain myself from submitting a PR.

diff --git a/pkg/image/remote/remote.go b/pkg/image/remote/remote.go
index 787c5381..7ac8fe13 100644
--- a/pkg/image/remote/remote.go
+++ b/pkg/image/remote/remote.go
@@ -57,11 +57,13 @@ func RetrieveRemoteImage(image string, opts config.RegistryOptions, customPlatfo
            regToMapTo, repositoryPrefix := parseRegistryMapping(registryMapping)

            insecurePull := opts.InsecurePull || opts.InsecureRegistries.Contains(regToMapTo)
+           ref, err := name.ParseReference(repositoryPrefix+image, name.WeakValidation)

            remappedRepository, err := remapRepository(ref.Context(), regToMapTo, repositoryPrefix, insecurePull)
            if err != nil {
                return nil, err
            }
+           remappedRepository.Registry, err = name.NewRegistry(regToMapTo, name.WeakValidation, name.Insecure)

            remappedRef := setNewRepository(ref, remappedRepository)
joaojacome commented 5 months ago

I found out this has been caused by having docker.io or gcr.io as part of the mapped registry URL. This doesn't work:

/kaniko/executor --registry-map "index.docker.io=my-registry.io/docker.io" --destination my-registry.io/my-image:latest

This works:

/kaniko/executor --registry-map "index.docker.io=my-registry.io/dockerio" --destination my-registry.io/my-image:latest

next-jesusmanuelnavarro commented 5 months ago

I found out this has been caused by having docker.io or gcr.io as part of the mapped registry URL. This doesn't work:

/kaniko/executor --registry-map "index.docker.io=my-registry.io/docker.io" --destination my-registry.io/my-image:latest

This works:

/kaniko/executor --registry-map "index.docker.io=my-registry.io/dockerio" --destination my-registry.io/my-image:latest

What do you exactly mean? Did you just drop the dots from your registry-map or did you create a new mirror without the dots and then used the new mirror with registry-map?

joaojacome commented 5 months ago

I created a new mirror without the dots

next-jesusmanuelnavarro commented 5 months ago

I created a new mirror without the dots

Yes, it makes sense. I stepped onto this same problem and it seems in fact it is the dots (my private mirror requires authentication).

  1. Trying to pull from a mirror with dashes and dots:

kaniko blah, blah... --registry-map index.docker.io=[my.server]:443/hub.docker.com-remote

kaniko fails with "...Failed to retrieve image alpine:3.17.2 from remapped registry [my.server]:443: unable to complete operation after 0 attempts, last error: Get "https://hub.docker.com-remote/v2/": Forbidden."

  1. If I naively take out the dots from the repo name (but no new mirror created to suite that name):

kaniko blah, blah... --registry-map index.docker.io=[my.server]:443/hubdockercom-remote

Then kaniko fails with a different error: "...Failed to retrieve image alpine:3.17.2 from remapped registry [my.server]:443: unable to complete operation after 0 attempts, last error: GET (...)=repository%3Ahubdockercom-remote%2Flibrary%2Falpine%3Apull&service=[my.server]%3A443): : Bad credentials

(sorry for the heavily redacted output)

The interesting part is that when using a mirror with dots within its repository name, kaniko tries to pull from the resulting suffix as if it were the server itself. I.e.: with [my.server]:443/hub.docker.com-remote it will wrongly try to find the API server at https://hub.docker.com-remote.

Without the dots, it tries to pull from the proper mirror (it's only that in my case it fails because the requested repository doesn't exist).