Allows to disable the fallback to the default registry on image pull (#2637)
* Allow to disable the fallback to the default registry on image pull When one or more registry mirror(s) are deffined with the 'registry-mirror' argument, if none of those mirrors include the image, the current behavior is to fallback to the default registry. If a whitelist (or some image restriction) is applied at the mirror side, fallbacking to the default registry makes that restriction useless. This new argument allows to skip the fallback and abort the build if the mirror rejects an image. If it is not set, is completelly transparent. * fix typo on command help
This commit is contained in:
parent
885ff5f57b
commit
c2445c76da
|
|
@ -96,6 +96,7 @@ _If you are interested in contributing to kaniko, see
|
||||||
- [Flag `--registry-certificate`](#flag---registry-certificate)
|
- [Flag `--registry-certificate`](#flag---registry-certificate)
|
||||||
- [Flag `--registry-client-cert`](#flag---registry-client-cert)
|
- [Flag `--registry-client-cert`](#flag---registry-client-cert)
|
||||||
- [Flag `--registry-mirror`](#flag---registry-mirror)
|
- [Flag `--registry-mirror`](#flag---registry-mirror)
|
||||||
|
- [Flag `--skip-default-registry-fallback`](#flag---skip-default-registry-fallback)
|
||||||
- [Flag `--reproducible`](#flag---reproducible)
|
- [Flag `--reproducible`](#flag---reproducible)
|
||||||
- [Flag `--single-snapshot`](#flag---single-snapshot)
|
- [Flag `--single-snapshot`](#flag---single-snapshot)
|
||||||
- [Flag `--skip-tls-verify`](#flag---skip-tls-verify)
|
- [Flag `--skip-tls-verify`](#flag---skip-tls-verify)
|
||||||
|
|
@ -992,6 +993,12 @@ are:
|
||||||
- `192.168.0.1:5000`
|
- `192.168.0.1:5000`
|
||||||
- `mycompany-docker-virtual.jfrog.io`
|
- `mycompany-docker-virtual.jfrog.io`
|
||||||
|
|
||||||
|
#### Flag `--skip-default-registry-fallback`
|
||||||
|
|
||||||
|
Set this flag if you want the build process to fail if none of the mirrors listed in flag [registry-mirror](#flag---registry-mirror) can pull some image. This should be used with mirrors that implements a whitelist or some image restrictions.
|
||||||
|
|
||||||
|
If [registry-mirror](#flag---registry-mirror) is not set or is empty, this flag is ignored.
|
||||||
|
|
||||||
#### Flag `--reproducible`
|
#### Flag `--reproducible`
|
||||||
|
|
||||||
Set this flag to strip timestamps out of the built image and make it
|
Set this flag to strip timestamps out of the built image and make it
|
||||||
|
|
|
||||||
|
|
@ -238,6 +238,7 @@ func addKanikoOptionsFlags() {
|
||||||
opts.RegistriesClientCertificates = make(map[string]string)
|
opts.RegistriesClientCertificates = make(map[string]string)
|
||||||
RootCmd.PersistentFlags().VarP(&opts.RegistriesClientCertificates, "registry-client-cert", "", "Use the provided client certificate for mutual TLS (mTLS) communication with the given registry. Expected format is 'my.registry.url=/path/to/client/cert,/path/to/client/key'.")
|
RootCmd.PersistentFlags().VarP(&opts.RegistriesClientCertificates, "registry-client-cert", "", "Use the provided client certificate for mutual TLS (mTLS) communication with the given registry. Expected format is 'my.registry.url=/path/to/client/cert,/path/to/client/key'.")
|
||||||
RootCmd.PersistentFlags().VarP(&opts.RegistryMirrors, "registry-mirror", "", "Registry mirror to use as pull-through cache instead of docker.io. Set it repeatedly for multiple mirrors.")
|
RootCmd.PersistentFlags().VarP(&opts.RegistryMirrors, "registry-mirror", "", "Registry mirror to use as pull-through cache instead of docker.io. Set it repeatedly for multiple mirrors.")
|
||||||
|
RootCmd.PersistentFlags().BoolVarP(&opts.SkipDefaultRegistryFallback, "skip-default-registry-fallback", "", false, "If an image is not found on any mirrors (defined with registry-mirror) do not fallback to the default registry. If registry-mirror is not defined, this flag is ignored.")
|
||||||
RootCmd.PersistentFlags().BoolVarP(&opts.IgnoreVarRun, "ignore-var-run", "", true, "Ignore /var/run directory when taking image snapshot. Set it to false to preserve /var/run/ in destination image.")
|
RootCmd.PersistentFlags().BoolVarP(&opts.IgnoreVarRun, "ignore-var-run", "", true, "Ignore /var/run directory when taking image snapshot. Set it to false to preserve /var/run/ in destination image.")
|
||||||
RootCmd.PersistentFlags().VarP(&opts.Labels, "label", "", "Set metadata for an image. Set it repeatedly for multiple labels.")
|
RootCmd.PersistentFlags().VarP(&opts.Labels, "label", "", "Set metadata for an image. Set it repeatedly for multiple labels.")
|
||||||
RootCmd.PersistentFlags().BoolVarP(&opts.SkipUnusedStages, "skip-unused-stages", "", false, "Build only used stages if defined to true. Otherwise it builds by default all stages, even the unnecessaries ones until it reaches the target stage / end of Dockerfile")
|
RootCmd.PersistentFlags().BoolVarP(&opts.SkipUnusedStages, "skip-unused-stages", "", false, "Build only used stages if defined to true. Otherwise it builds by default all stages, even the unnecessaries ones until it reaches the target stage / end of Dockerfile")
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,7 @@ func addKanikoOptionsFlags() {
|
||||||
opts.RegistriesClientCertificates = make(map[string]string)
|
opts.RegistriesClientCertificates = make(map[string]string)
|
||||||
RootCmd.PersistentFlags().VarP(&opts.RegistriesClientCertificates, "registry-client-cert", "", "Use the provided client certificate for mutual TLS (mTLS) communication with the given registry. Expected format is 'my.registry.url=/path/to/client/cert,/path/to/client/key'.")
|
RootCmd.PersistentFlags().VarP(&opts.RegistriesClientCertificates, "registry-client-cert", "", "Use the provided client certificate for mutual TLS (mTLS) communication with the given registry. Expected format is 'my.registry.url=/path/to/client/cert,/path/to/client/key'.")
|
||||||
RootCmd.PersistentFlags().VarP(&opts.RegistryMirrors, "registry-mirror", "", "Registry mirror to use as pull-through cache instead of docker.io. Set it repeatedly for multiple mirrors.")
|
RootCmd.PersistentFlags().VarP(&opts.RegistryMirrors, "registry-mirror", "", "Registry mirror to use as pull-through cache instead of docker.io. Set it repeatedly for multiple mirrors.")
|
||||||
|
RootCmd.PersistentFlags().BoolVarP(&opts.SkipDefaultRegistryFallback, "skip-default-registry-fallback", "", false, "If an image is not found on any mirrors (defined with registry-mirror) do not fallback to the default registry. If registry-mirror is not defined, this flag is ignored.")
|
||||||
RootCmd.PersistentFlags().StringVarP(&opts.CustomPlatform, "customPlatform", "", "", "Specify the build platform if different from the current host")
|
RootCmd.PersistentFlags().StringVarP(&opts.CustomPlatform, "customPlatform", "", "", "Specify the build platform if different from the current host")
|
||||||
RootCmd.PersistentFlags().StringVarP(&opts.DockerfilePath, "dockerfile", "d", "", "Path to the dockerfile to be cached. The kaniko warmer will parse and write out each stage's base image layers to the cache-dir. Using the same dockerfile path as what you plan to build in the kaniko executor is the expected usage.")
|
RootCmd.PersistentFlags().StringVarP(&opts.DockerfilePath, "dockerfile", "d", "", "Path to the dockerfile to be cached. The kaniko warmer will parse and write out each stage's base image layers to the cache-dir. Using the same dockerfile path as what you plan to build in the kaniko executor is the expected usage.")
|
||||||
RootCmd.PersistentFlags().VarP(&opts.BuildArgs, "build-arg", "", "This flag should be used in conjunction with the dockerfile flag for scenarios where dynamic replacement of the base image is required.")
|
RootCmd.PersistentFlags().VarP(&opts.BuildArgs, "build-arg", "", "This flag should be used in conjunction with the dockerfile flag for scenarios where dynamic replacement of the base image is required.")
|
||||||
|
|
|
||||||
|
|
@ -395,6 +395,29 @@ func TestBuildViaRegistryMirrors(t *testing.T) {
|
||||||
checkContainerDiffOutput(t, diff, expected)
|
checkContainerDiffOutput(t, diff, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBuildSkipFallback(t *testing.T) {
|
||||||
|
repo := getGitRepo(false)
|
||||||
|
dockerfile := fmt.Sprintf("%s/%s/Dockerfile_registry_mirror", integrationPath, dockerfilesPath)
|
||||||
|
|
||||||
|
// Build with kaniko
|
||||||
|
kanikoImage := GetKanikoImage(config.imageRepo, "Dockerfile_registry_mirror")
|
||||||
|
dockerRunFlags := []string{"run", "--net=host"}
|
||||||
|
dockerRunFlags = addServiceAccountFlags(dockerRunFlags, config.serviceAccount)
|
||||||
|
dockerRunFlags = append(dockerRunFlags, ExecutorImage,
|
||||||
|
"-f", dockerfile,
|
||||||
|
"-d", kanikoImage,
|
||||||
|
"--registry-mirror", "doesnotexist.example.com",
|
||||||
|
"--skip-default-registry-fallback",
|
||||||
|
"-c", fmt.Sprintf("git://%s", repo))
|
||||||
|
|
||||||
|
kanikoCmd := exec.Command("docker", dockerRunFlags...)
|
||||||
|
|
||||||
|
_, err := RunCommandWithoutTest(kanikoCmd)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Build should fail after using skip-default-registry-fallback and registry-mirror fail to pull")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestKanikoDir tests that a build that sets --kaniko-dir produces the same output as the equivalent docker build.
|
// TestKanikoDir tests that a build that sets --kaniko-dir produces the same output as the equivalent docker build.
|
||||||
func TestKanikoDir(t *testing.T) {
|
func TestKanikoDir(t *testing.T) {
|
||||||
repo := getGitRepo(false)
|
repo := getGitRepo(false)
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ type RegistryOptions struct {
|
||||||
SkipTLSVerifyRegistries multiArg
|
SkipTLSVerifyRegistries multiArg
|
||||||
RegistriesCertificates keyValueArg
|
RegistriesCertificates keyValueArg
|
||||||
RegistriesClientCertificates keyValueArg
|
RegistriesClientCertificates keyValueArg
|
||||||
|
SkipDefaultRegistryFallback bool
|
||||||
Insecure bool
|
Insecure bool
|
||||||
SkipTLSVerify bool
|
SkipTLSVerify bool
|
||||||
InsecurePull bool
|
InsecurePull bool
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||||
package remote
|
package remote
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/GoogleContainerTools/kaniko/pkg/config"
|
"github.com/GoogleContainerTools/kaniko/pkg/config"
|
||||||
|
|
@ -31,7 +32,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
manifestCache = make(map[string]v1.Image)
|
manifestCache = make(map[string]v1.Image)
|
||||||
|
remoteImageFunc = remote.Image
|
||||||
)
|
)
|
||||||
|
|
||||||
// RetrieveRemoteImage retrieves the manifest for the specified image from the specified registry
|
// RetrieveRemoteImage retrieves the manifest for the specified image from the specified registry
|
||||||
|
|
@ -68,7 +70,7 @@ func RetrieveRemoteImage(image string, opts config.RegistryOptions, customPlatfo
|
||||||
ref := setNewRegistry(ref, newReg)
|
ref := setNewRegistry(ref, newReg)
|
||||||
|
|
||||||
logrus.Infof("Retrieving image %s from registry mirror %s", ref, registryMirror)
|
logrus.Infof("Retrieving image %s from registry mirror %s", ref, registryMirror)
|
||||||
remoteImage, err := remote.Image(ref, remoteOptions(registryMirror, opts, customPlatform)...)
|
remoteImage, err := remoteImageFunc(ref, remoteOptions(registryMirror, opts, customPlatform)...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Warnf("Failed to retrieve image %s from registry mirror %s: %s. Will try with the next mirror, or fallback to the default registry.", ref, registryMirror, err)
|
logrus.Warnf("Failed to retrieve image %s from registry mirror %s: %s. Will try with the next mirror, or fallback to the default registry.", ref, registryMirror, err)
|
||||||
continue
|
continue
|
||||||
|
|
@ -78,6 +80,10 @@ func RetrieveRemoteImage(image string, opts config.RegistryOptions, customPlatfo
|
||||||
|
|
||||||
return remoteImage, nil
|
return remoteImage, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(opts.RegistryMirrors) > 0 && opts.SkipDefaultRegistryFallback {
|
||||||
|
return nil, errors.New("image not found on any configured mirror(s)")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
registryName := ref.Context().RegistryStr()
|
registryName := ref.Context().RegistryStr()
|
||||||
|
|
@ -91,7 +97,7 @@ func RetrieveRemoteImage(image string, opts config.RegistryOptions, customPlatfo
|
||||||
|
|
||||||
logrus.Infof("Retrieving image %s from registry %s", ref, registryName)
|
logrus.Infof("Retrieving image %s from registry %s", ref, registryName)
|
||||||
|
|
||||||
remoteImage, err := remote.Image(ref, remoteOptions(registryName, opts, customPlatform)...)
|
remoteImage, err := remoteImageFunc(ref, remoteOptions(registryName, opts, customPlatform)...)
|
||||||
|
|
||||||
if remoteImage != nil {
|
if remoteImage != nil {
|
||||||
manifestCache[image] = remoteImage
|
manifestCache[image] = remoteImage
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,13 @@ limitations under the License.
|
||||||
package remote
|
package remote
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/GoogleContainerTools/kaniko/pkg/config"
|
"github.com/GoogleContainerTools/kaniko/pkg/config"
|
||||||
"github.com/google/go-containerregistry/pkg/name"
|
"github.com/google/go-containerregistry/pkg/name"
|
||||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||||
|
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||||
"github.com/google/go-containerregistry/pkg/v1/types"
|
"github.com/google/go-containerregistry/pkg/v1/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -108,3 +110,33 @@ func Test_RetrieveRemoteImage_manifestCache(t *testing.T) {
|
||||||
t.Fatal("Expected call to succeed because there is a manifest for this image in the cache.")
|
t.Fatal("Expected call to succeed because there is a manifest for this image in the cache.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_RetrieveRemoteImage_skipFallback(t *testing.T) {
|
||||||
|
image := "debian"
|
||||||
|
registryMirror := "some-registry"
|
||||||
|
|
||||||
|
opts := config.RegistryOptions{
|
||||||
|
RegistryMirrors: []string{registryMirror},
|
||||||
|
SkipDefaultRegistryFallback: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteImageFunc = func(ref name.Reference, options ...remote.Option) (v1.Image, error) {
|
||||||
|
if ref.Context().Registry.Name() == registryMirror {
|
||||||
|
return nil, errors.New("no image found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &mockImage{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := RetrieveRemoteImage(image, opts, ""); err != nil {
|
||||||
|
t.Fatal("Expected call to succeed because fallback to default registry")
|
||||||
|
}
|
||||||
|
|
||||||
|
opts.SkipDefaultRegistryFallback = true
|
||||||
|
//clean cached image
|
||||||
|
manifestCache = make(map[string]v1.Image)
|
||||||
|
|
||||||
|
if _, err := RetrieveRemoteImage(image, opts, ""); err == nil {
|
||||||
|
t.Fatal("Expected call to fail because fallback to default registry is skipped")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue