diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml index e173604eb..231a53bae 100644 --- a/.github/workflows/integration_tests.yml +++ b/.github/workflows/integration_tests.yml @@ -12,6 +12,7 @@ permissions: contents: read env: GH_ANNOTATION: true + DOCKER_REGISTRY: ghcr.io/linkerd jobs: docker_build: runs-on: ubuntu-20.04 @@ -28,9 +29,6 @@ jobs: run: | . bin/_tag.sh echo "TAG=$(CI_FORCE_CLEAN=1 bin/root-tag)" >> $GITHUB_ENV - - . bin/_docker.sh - echo "DOCKER_REGISTRY=cr.l5d.io/linkerd" >> $GITHUB_ENV echo "DOCKER_BUILDKIT_CACHE=${{ runner.temp }}/.buildx-cache" >> $GITHUB_ENV - name: Cache docker layers uses: actions/cache@c64c572235d810460d0d6876e9c705ad5002b353 @@ -54,7 +52,7 @@ jobs: ARCHIVES: /home/runner/archives run: | mkdir -p $ARCHIVES - docker save "cr.l5d.io/linkerd/${{ matrix.target }}:$TAG" > $ARCHIVES/${{ matrix.target }}.tar + docker save "$DOCKER_REGISTRY/${{ matrix.target }}:$TAG" > $ARCHIVES/${{ matrix.target }}.tar # `with.path` values do not support environment variables yet, so an # absolute path is used here. # @@ -99,9 +97,6 @@ jobs: run: | . bin/_tag.sh echo "TAG=$(CI_FORCE_CLEAN=1 bin/root-tag)" >> $GITHUB_ENV - - . bin/_docker.sh - echo "DOCKER_REGISTRY=cr.l5d.io/linkerd" >> $GITHUB_ENV - name: Download image archives uses: actions/download-artifact@3be87be14a055c47b01d3bd88f8fe02320a9bb60 with: @@ -112,11 +107,13 @@ jobs: - name: Install CLI run: | # Copy the CLI out of the local cli-bin container. - container_id=$(docker create "cr.l5d.io/linkerd/cli-bin:$TAG") + container_id=$(docker create "$DOCKER_REGISTRY/cli-bin:$TAG") docker cp $container_id:/out/linkerd-linux-amd64 "$HOME/.linkerd" # Validate the CLI version matches the current build tag. [[ "$TAG" == "$($HOME/.linkerd version --short --client)" ]] - name: Run integration tests + env: + LINKERD_DOCKER_REGISTRY: ${{ env.DOCKER_REGISTRY }} run: | bin/tests --images archive --cleanup-docker --name ${{ matrix.integration_test }} "$HOME/.linkerd" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cb5ec6e9b..089de9664 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,6 +7,7 @@ permissions: contents: read env: GH_ANNOTATION: true + DOCKER_REGISTRY: cr.l5d.io/linkerd jobs: docker_build: runs-on: ubuntu-20.04 @@ -23,9 +24,6 @@ jobs: run: | . bin/_tag.sh echo "TAG=$(CI_FORCE_CLEAN=1 bin/root-tag)" >> $GITHUB_ENV - - . bin/_docker.sh - echo "DOCKER_REGISTRY=ghcr.io/linkerd" >> $GITHUB_ENV echo "DOCKER_BUILDKIT_CACHE=${{ runner.temp }}/.buildx-cache" >> $GITHUB_ENV - name: Cache docker layers uses: actions/cache@c64c572235d810460d0d6876e9c705ad5002b353 @@ -90,7 +88,7 @@ jobs: echo "${{ secrets.DOCKER_GHCR_PAT }}" | docker login ghcr.io -u "${{ secrets.DOCKER_GHCR_USERNAME }}" --password-stdin docker buildx build --push ./policy-controller/ \ -f ./policy-controller/${{ matrix.arch }}.dockerfile \ - -t ghcr.io/linkerd/policy-controller:$TAG-${{ matrix.arch }} + -t $DOCKER_REGISTRY/policy-controller:$TAG-${{ matrix.arch }} policy_controller_manifest: runs-on: ubuntu-20.04 @@ -105,22 +103,22 @@ jobs: echo "TAG=$(CI_FORCE_CLEAN=1 bin/root-tag)" >> $GITHUB_ENV - name: Create multiarch manifest run: | - docker manifest create ghcr.io/linkerd/policy-controller:${TAG} \ - ghcr.io/linkerd/policy-controller:${TAG}-amd64 \ - ghcr.io/linkerd/policy-controller:${TAG}-arm64 \ - ghcr.io/linkerd/policy-controller:${TAG}-arm + docker manifest create $DOCKER_REGISTRY/policy-controller:$TAG \ + $DOCKER_REGISTRY/policy-controller:$TAG-amd64 \ + $DOCKER_REGISTRY/policy-controller:$TAG-arm64 \ + $DOCKER_REGISTRY/policy-controller:$TAG-arm - name: Annotate multiarch manifest run: | - docker manifest annotate ghcr.io/linkerd/policy-controller:$TAG \ - ghcr.io/linkerd/policy-controller:${TAG}-amd64 --os=linux --arch=amd64 - docker manifest annotate ghcr.io/linkerd/policy-controller:$TAG \ - ghcr.io/linkerd/policy-controller:${TAG}-arm64 --os=linux --arch=arm64 - docker manifest annotate ghcr.io/linkerd/policy-controller:$TAG \ - ghcr.io/linkerd/policy-controller:${TAG}-arm --os=linux --arch=arm + docker manifest annotate $DOCKER_REGISTRY/policy-controller:$TAG \ + $DOCKER_REGISTRY/policy-controller:${TAG}-amd64 --os=linux --arch=amd64 + docker manifest annotate $DOCKER_REGISTRY/policy-controller:$TAG \ + $DOCKER_REGISTRY/policy-controller:${TAG}-arm64 --os=linux --arch=arm64 + docker manifest annotate $DOCKER_REGISTRY/policy-controller:$TAG \ + $DOCKER_REGISTRY/policy-controller:${TAG}-arm --os=linux --arch=arm - name: Push multiarch manifest run: | echo "${{ secrets.DOCKER_GHCR_PAT }}" | docker login ghcr.io -u "${{ secrets.DOCKER_GHCR_USERNAME }}" --password-stdin - docker manifest push ghcr.io/linkerd/policy-controller:$TAG + docker manifest push $DOCKER_REGISTRY/policy-controller:$TAG # todo: Keep in sync with `integration_tests.yml` windows_static_cli_tests: @@ -180,6 +178,8 @@ jobs: echo "CMD=$CMD" >> $GITHUB_ENV echo "TAG=$TAG" >> $GITHUB_ENV - name: Run integration tests + env: + LINKERD_DOCKER_REGISTRY: ${{ env.DOCKER_REGISTRY }} run: | bin/docker-pull-binaries $TAG # Validate the CLI version matches the current build tag. @@ -220,6 +220,7 @@ jobs: - name: Run integration tests env: RUN_ARM_TEST: 1 + LINKERD_DOCKER_REGISTRY: ${{ env.DOCKER_REGISTRY }} run: bin/tests --name deep --images preload --skip-cluster-create "$CMD" - name: CNI tests run: | diff --git a/cli/cmd/inject_test.go b/cli/cmd/inject_test.go index 12c1ca104..772ec5af7 100644 --- a/cli/cmd/inject_test.go +++ b/cli/cmd/inject_test.go @@ -12,6 +12,7 @@ import ( "testing" "github.com/linkerd/linkerd2/pkg/charts/linkerd2" + "github.com/linkerd/linkerd2/pkg/cmd" "github.com/linkerd/linkerd2/pkg/k8s" "github.com/linkerd/linkerd2/testutil" ) @@ -760,7 +761,7 @@ func TestOverwriteRegistry(t *testing.T) { for i, tc := range testCases { tc := tc // pin t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { - actual := registryOverride(tc.image, tc.registry) + actual := cmd.RegistryOverride(tc.image, tc.registry) if actual != tc.expected { t.Fatalf("expected %q, but got %q", tc.expected, actual) } diff --git a/cli/cmd/install-cni-plugin.go b/cli/cmd/install-cni-plugin.go index 51d3811c2..16980e854 100644 --- a/cli/cmd/install-cni-plugin.go +++ b/cli/cmd/install-cni-plugin.go @@ -9,6 +9,8 @@ import ( "github.com/linkerd/linkerd2/pkg/charts" cnicharts "github.com/linkerd/linkerd2/pkg/charts/cni" "github.com/linkerd/linkerd2/pkg/charts/static" + "github.com/linkerd/linkerd2/pkg/cmd" + "github.com/linkerd/linkerd2/pkg/flags" "github.com/linkerd/linkerd2/pkg/version" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -66,8 +68,12 @@ func (options *cniPluginOptions) validate() error { } func (options *cniPluginOptions) pluginImage() string { + // env var overrides CLI flag + if override := os.Getenv(flags.EnvOverrideDockerRegistry); override != "" { + return cmd.RegistryOverride(options.cniPluginImage, override) + } if options.dockerRegistry != defaultDockerRegistry { - return registryOverride(options.cniPluginImage, options.dockerRegistry) + return cmd.RegistryOverride(options.cniPluginImage, options.dockerRegistry) } return options.cniPluginImage } @@ -95,7 +101,8 @@ assumes that the 'linkerd install' command will be executed with the } cmd.PersistentFlags().StringVarP(&options.linkerdVersion, "linkerd-version", "v", options.linkerdVersion, "Tag to be used for Linkerd images") - cmd.PersistentFlags().StringVar(&options.dockerRegistry, "registry", options.dockerRegistry, "Docker registry to pull images from") + cmd.PersistentFlags().StringVar(&options.dockerRegistry, "registry", options.dockerRegistry, + fmt.Sprintf("Docker registry to pull images from ($%s)", flags.EnvOverrideDockerRegistry)) cmd.PersistentFlags().Int64Var(&options.proxyUID, "proxy-uid", options.proxyUID, "Run the proxy under this user ID") cmd.PersistentFlags().UintVar(&options.inboundPort, "inbound-port", options.inboundPort, "Proxy port to use for inbound traffic") cmd.PersistentFlags().UintVar(&options.outboundPort, "outbound-port", options.outboundPort, "Proxy port to use for outbound traffic") diff --git a/cli/cmd/options.go b/cli/cmd/options.go index 6c2b0d600..24c383e1a 100644 --- a/cli/cmd/options.go +++ b/cli/cmd/options.go @@ -3,6 +3,7 @@ package cmd import ( "context" "errors" + "os" "fmt" "io/ioutil" @@ -12,6 +13,8 @@ import ( "github.com/linkerd/linkerd2/cli/flag" l5dcharts "github.com/linkerd/linkerd2/pkg/charts/linkerd2" + "github.com/linkerd/linkerd2/pkg/cmd" + flagspkg "github.com/linkerd/linkerd2/pkg/flags" "github.com/linkerd/linkerd2/pkg/inject" "github.com/linkerd/linkerd2/pkg/issuercerts" "github.com/linkerd/linkerd2/pkg/k8s" @@ -305,15 +308,6 @@ func makeProxyFlags(defaults *l5dcharts.Values) ([]flag.Flag, *pflag.FlagSet) { return nil }), - flag.NewStringFlag(proxyFlags, "registry", defaultDockerRegistry, "Docker registry to pull images from", - func(values *l5dcharts.Values, value string) error { - values.ControllerImage = registryOverride(values.ControllerImage, value) - values.DebugContainer.Image.Name = registryOverride(values.DebugContainer.Image.Name, value) - values.Proxy.Image.Name = registryOverride(values.Proxy.Image.Name, value) - values.ProxyInit.Image.Name = registryOverride(values.ProxyInit.Image.Name, value) - return nil - }), - flag.NewStringFlag(proxyFlags, "image-pull-policy", defaults.ImagePullPolicy, "Docker image pull policy", func(values *l5dcharts.Values, value string) error { values.ImagePullPolicy = value @@ -425,6 +419,21 @@ func makeProxyFlags(defaults *l5dcharts.Values) ([]flag.Flag, *pflag.FlagSet) { }), } + registryFlag := flag.NewStringFlag(proxyFlags, "registry", defaultDockerRegistry, + fmt.Sprintf("Docker registry to pull images from ($%s)", flagspkg.EnvOverrideDockerRegistry), + func(values *l5dcharts.Values, value string) error { + values.ControllerImage = cmd.RegistryOverride(values.ControllerImage, value) + values.PolicyController.Image.Name = cmd.RegistryOverride(values.PolicyController.Image.Name, value) + values.DebugContainer.Image.Name = cmd.RegistryOverride(values.DebugContainer.Image.Name, value) + values.Proxy.Image.Name = cmd.RegistryOverride(values.Proxy.Image.Name, value) + values.ProxyInit.Image.Name = cmd.RegistryOverride(values.ProxyInit.Image.Name, value) + return nil + }) + if reg := os.Getenv(flagspkg.EnvOverrideDockerRegistry); reg != "" { + registryFlag.Set(reg) + } + flags = append(flags, registryFlag) + proxyFlags.MarkDeprecated("proxy-memory", "use --proxy-memory-request instead") proxyFlags.MarkDeprecated("proxy-cpu", "use --proxy-cpu-request instead") diff --git a/cli/cmd/root.go b/cli/cmd/root.go index 05f834170..27a8f704e 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -11,6 +11,7 @@ import ( jaeger "github.com/linkerd/linkerd2/jaeger/cmd" multicluster "github.com/linkerd/linkerd2/multicluster/cmd" pkgcmd "github.com/linkerd/linkerd2/pkg/cmd" + "github.com/linkerd/linkerd2/pkg/flags" "github.com/linkerd/linkerd2/pkg/healthcheck" viz "github.com/linkerd/linkerd2/viz/cmd" log "github.com/sirupsen/logrus" @@ -79,7 +80,7 @@ var RootCmd = &cobra.Command{ log.SetLevel(log.PanicLevel) } - controlPlaneNamespaceFromEnv := os.Getenv("LINKERD_NAMESPACE") + controlPlaneNamespaceFromEnv := os.Getenv(flags.EnvOverrideNamespace) if controlPlaneNamespace == defaultLinkerdNamespace && controlPlaneNamespaceFromEnv != "" { controlPlaneNamespace = controlPlaneNamespaceFromEnv } @@ -93,7 +94,9 @@ var RootCmd = &cobra.Command{ } func init() { - RootCmd.PersistentFlags().StringVarP(&controlPlaneNamespace, "linkerd-namespace", "L", defaultLinkerdNamespace, "Namespace in which Linkerd is installed ($LINKERD_NAMESPACE)") + RootCmd.PersistentFlags().StringVarP(&controlPlaneNamespace, "linkerd-namespace", "L", + defaultLinkerdNamespace, + fmt.Sprintf("Namespace in which Linkerd is installed ($%s)", flags.EnvOverrideNamespace)) RootCmd.PersistentFlags().StringVarP(&cniNamespace, "cni-namespace", "", defaultCNINamespace, "Namespace in which the Linkerd CNI plugin is installed") RootCmd.PersistentFlags().StringVar(&kubeconfigPath, "kubeconfig", "", "Path to the kubeconfig file to use for CLI requests") RootCmd.PersistentFlags().StringVar(&kubeContext, "context", "", "Name of the kubeconfig context to use") @@ -143,22 +146,6 @@ func deprecateCmd(cmd *cobra.Command) *cobra.Command { return cmd } -// registryOverride replaces the registry-portion of the provided image with the provided registry. -func registryOverride(image, newRegistry string) string { - if image == "" { - return image - } - registry := newRegistry - if registry != "" && !strings.HasSuffix(registry, slash) { - registry += slash - } - imageName := image - if strings.Contains(image, slash) { - imageName = image[strings.LastIndex(image, slash)+1:] - } - return registry + imageName -} - func flattenFlags(flags ...[]flag.Flag) []flag.Flag { out := []flag.Flag{} for _, f := range flags { diff --git a/cli/cmd/testdata/install_custom_registry.golden b/cli/cmd/testdata/install_custom_registry.golden index 5bf8c2ee8..f2eaa398e 100644 --- a/cli/cmd/testdata/install_custom_registry.golden +++ b/cli/cmd/testdata/install_custom_registry.golden @@ -1099,7 +1099,7 @@ data: policyController: defaultAllowPolicy: all-unauthenticated image: - name: cr.l5d.io/linkerd/policy-controller + name: my.custom.registry/linkerd-io/policy-controller pullPolicy: "" version: install-control-plane-version logLevel: linkerd=info,warn @@ -1832,7 +1832,7 @@ spec: env: - name: RUST_LOG value: "linkerd=info,warn" - image: cr.l5d.io/linkerd/policy-controller:install-control-plane-version + image: my.custom.registry/linkerd-io/policy-controller:install-control-plane-version imagePullPolicy: IfNotPresent livenessProbe: httpGet: @@ -2221,7 +2221,7 @@ spec: --- apiVersion: v1 data: - linkerd-config-overrides: Y29udHJvbGxlckltYWdlOiBteS5jdXN0b20ucmVnaXN0cnkvbGlua2VyZC1pby9jb250cm9sbGVyCmNvbnRyb2xsZXJJbWFnZVZlcnNpb246IGluc3RhbGwtY29udHJvbC1wbGFuZS12ZXJzaW9uCmRlYnVnQ29udGFpbmVyOgogIGltYWdlOgogICAgbmFtZTogbXkuY3VzdG9tLnJlZ2lzdHJ5L2xpbmtlcmQtaW8vZGVidWcKICAgIHZlcnNpb246IGluc3RhbGwtZGVidWctdmVyc2lvbgpoZWFydGJlYXRTY2hlZHVsZTogMSAyIDMgNCA1CmlkZW50aXR5OgogIGlzc3VlcjoKICAgIGNydEV4cGlyeTogIjIwMzAtMDgtMjZUMDc6MTM6NDdaIgogICAgdGxzOgogICAgICBjcnRQRU06IHwKICAgICAgICAtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KICAgICAgICBNSUlCd0RDQ0FXZWdBd0lCQWdJUkFKUklnWjhSdE84RXdnMVhlcGY4VDQ0d0NnWUlLb1pJemowRUF3SXdLVEVuCiAgICAgICAgTUNVR0ExVUVBeE1lYVdSbGJuUnBkSGt1YkdsdWEyVnlaQzVqYkhWemRHVnlMbXh2WTJGc01CNFhEVEl3TURneQogICAgICAgIE9EQTNNVE0wTjFvWERUTXdNRGd5TmpBM01UTTBOMW93S1RFbk1DVUdBMVVFQXhNZWFXUmxiblJwZEhrdWJHbHUKICAgICAgICBhMlZ5WkM1amJIVnpkR1Z5TG14dlkyRnNNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUUxL0ZwCiAgICAgICAgZmNSbkRjZWRMNkFqVWFYWVB2NERJTUJhSnVmT0k1Tld0eStYU1g3SmpYZ1p0TTcyZFF2UmFZYW51eEQzNkR0MQogICAgICAgIDIvSnh5aVNneEtXUmRvYXkrYU53TUc0d0RnWURWUjBQQVFIL0JBUURBZ0VHTUJJR0ExVWRFd0VCL3dRSU1BWUIKICAgICAgICBBZjhDQVFBd0hRWURWUjBPQkJZRUZJMVducnFNWUthSEhPbyt6cHlpaURxMnBPMEtNQ2tHQTFVZEVRUWlNQ0NDCiAgICAgICAgSG1sa1pXNTBhWFI1TG14cGJtdGxjbVF1WTJ4MWMzUmxjaTVzYjJOaGJEQUtCZ2dxaGtqT1BRUURBZ05IQURCRQogICAgICAgIEFpQXR1b0k1WHVDdHJHVlJ6U21SVGwycmEyOGFWOU15VFU3ZDVxblRBRkhLU2dJZ1JLQ3ZsdU9TZ0E1TzIxcDUKICAgICAgICA1MXRkcm1rSEVaUnIwcWxMU0pkSFlnRWZNems9CiAgICAgICAgLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQogICAgICBrZXlQRU06IHwKICAgICAgICAtLS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KICAgICAgICBNSGNDQVFFRUlBQWU4bmZielp1OWMvT0IyKzh4Sk0wRno3TlV3VFFhenVsa0ZOczRUSTUrb0FvR0NDcUdTTTQ5CiAgICAgICAgQXdFSG9VUURRZ0FFMS9GcGZjUm5EY2VkTDZBalVhWFlQdjRESU1CYUp1Zk9JNU5XdHkrWFNYN0pqWGdadE03MgogICAgICAgIGRRdlJhWWFudXhEMzZEdDEyL0p4eWlTZ3hLV1Jkb2F5K1E9PQogICAgICAgIC0tLS0tRU5EIEVDIFBSSVZBVEUgS0VZLS0tLS0KaWRlbnRpdHlUcnVzdEFuY2hvcnNQRU06IHwKICAtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KICBNSUlCd1RDQ0FXYWdBd0lCQWdJUWVEWnA1bERhSXlnUTVVZk1LWnJGQVRBS0JnZ3Foa2pPUFFRREFqQXBNU2N3CiAgSlFZRFZRUURFeDVwWkdWdWRHbDBlUzVzYVc1clpYSmtMbU5zZFhOMFpYSXViRzlqWVd3d0hoY05NakF3T0RJNAogIE1EY3hNalEzV2hjTk16QXdPREkyTURjeE1qUTNXakFwTVNjd0pRWURWUVFERXg1cFpHVnVkR2wwZVM1c2FXNXIKICBaWEprTG1Oc2RYTjBaWEl1Ykc5allXd3dXVEFUQmdjcWhrak9QUUlCQmdncWhrak9QUU1CQndOQ0FBUnFjNzBaCiAgbDF2Z3c3OXJqQjV1U0lUSUNVQTZHeWZ2U0ZmY3VJaXM3Qi9YRlNra3dBSFU1Uy9zMUFBUCtSMFRYN0hCV1VDNAogIHVhRzRXV3Npd0pLTm43bWdvM0F3YmpBT0JnTlZIUThCQWY4RUJBTUNBUVl3RWdZRFZSMFRBUUgvQkFnd0JnRUIKICAvd0lCQVRBZEJnTlZIUTRFRmdRVTVZdGpWVlBmZDdJN05MSHNuMkMyNkVCeUdWMHdLUVlEVlIwUkJDSXdJSUllCiAgYVdSbGJuUnBkSGt1YkdsdWEyVnlaQzVqYkhWemRHVnlMbXh2WTJGc01Bb0dDQ3FHU000OUJBTUNBMGtBTUVZQwogIElRQ043bEJGTEREdmp4NlYwK1hranBLRVJSc0pZZjVhZE12bmxvRmw0OGlsSmdJaEFOdHhobmRjcitRSlB1QzgKICB2Z1VDMGQyLzlGTXVlSVZNYis0NldUQ09qc3FyCiAgLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQpwb2xpY3lDb250cm9sbGVyOgogIGltYWdlOgogICAgdmVyc2lvbjogaW5zdGFsbC1jb250cm9sLXBsYW5lLXZlcnNpb24KcG9saWN5VmFsaWRhdG9yOgogIGNhQnVuZGxlOiBwb2xpY3kgdmFsaWRhdG9yIENBIGJ1bmRsZQogIGNydFBFTTogcG9saWN5IHZhbGlkYXRvciBjcnQKICBrZXlQRU06IHBvbGljeSB2YWxpZGF0b3Iga2V5CnByb2ZpbGVWYWxpZGF0b3I6CiAgY2FCdW5kbGU6IHByb2ZpbGUgdmFsaWRhdG9yIENBIGJ1bmRsZQogIGNydFBFTTogcHJvZmlsZSB2YWxpZGF0b3IgY3J0CiAga2V5UEVNOiBwcm9maWxlIHZhbGlkYXRvciBrZXkKcHJveHk6CiAgaW1hZ2U6CiAgICBuYW1lOiBteS5jdXN0b20ucmVnaXN0cnkvbGlua2VyZC1pby9wcm94eQogICAgdmVyc2lvbjogaW5zdGFsbC1wcm94eS12ZXJzaW9uCnByb3h5SW5pdDoKICBpbWFnZToKICAgIG5hbWU6IG15LmN1c3RvbS5yZWdpc3RyeS9saW5rZXJkLWlvL3Byb3h5LWluaXQKcHJveHlJbmplY3RvcjoKICBjYUJ1bmRsZTogcHJveHkgaW5qZWN0b3IgQ0EgYnVuZGxlCiAgY3J0UEVNOiBwcm94eSBpbmplY3RvciBjcnQKICBrZXlQRU06IHByb3h5IGluamVjdG9yIGtleQo= + linkerd-config-overrides: Y29udHJvbGxlckltYWdlOiBteS5jdXN0b20ucmVnaXN0cnkvbGlua2VyZC1pby9jb250cm9sbGVyCmNvbnRyb2xsZXJJbWFnZVZlcnNpb246IGluc3RhbGwtY29udHJvbC1wbGFuZS12ZXJzaW9uCmRlYnVnQ29udGFpbmVyOgogIGltYWdlOgogICAgbmFtZTogbXkuY3VzdG9tLnJlZ2lzdHJ5L2xpbmtlcmQtaW8vZGVidWcKICAgIHZlcnNpb246IGluc3RhbGwtZGVidWctdmVyc2lvbgpoZWFydGJlYXRTY2hlZHVsZTogMSAyIDMgNCA1CmlkZW50aXR5OgogIGlzc3VlcjoKICAgIGNydEV4cGlyeTogIjIwMzAtMDgtMjZUMDc6MTM6NDdaIgogICAgdGxzOgogICAgICBjcnRQRU06IHwKICAgICAgICAtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KICAgICAgICBNSUlCd0RDQ0FXZWdBd0lCQWdJUkFKUklnWjhSdE84RXdnMVhlcGY4VDQ0d0NnWUlLb1pJemowRUF3SXdLVEVuCiAgICAgICAgTUNVR0ExVUVBeE1lYVdSbGJuUnBkSGt1YkdsdWEyVnlaQzVqYkhWemRHVnlMbXh2WTJGc01CNFhEVEl3TURneQogICAgICAgIE9EQTNNVE0wTjFvWERUTXdNRGd5TmpBM01UTTBOMW93S1RFbk1DVUdBMVVFQXhNZWFXUmxiblJwZEhrdWJHbHUKICAgICAgICBhMlZ5WkM1amJIVnpkR1Z5TG14dlkyRnNNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUUxL0ZwCiAgICAgICAgZmNSbkRjZWRMNkFqVWFYWVB2NERJTUJhSnVmT0k1Tld0eStYU1g3SmpYZ1p0TTcyZFF2UmFZYW51eEQzNkR0MQogICAgICAgIDIvSnh5aVNneEtXUmRvYXkrYU53TUc0d0RnWURWUjBQQVFIL0JBUURBZ0VHTUJJR0ExVWRFd0VCL3dRSU1BWUIKICAgICAgICBBZjhDQVFBd0hRWURWUjBPQkJZRUZJMVducnFNWUthSEhPbyt6cHlpaURxMnBPMEtNQ2tHQTFVZEVRUWlNQ0NDCiAgICAgICAgSG1sa1pXNTBhWFI1TG14cGJtdGxjbVF1WTJ4MWMzUmxjaTVzYjJOaGJEQUtCZ2dxaGtqT1BRUURBZ05IQURCRQogICAgICAgIEFpQXR1b0k1WHVDdHJHVlJ6U21SVGwycmEyOGFWOU15VFU3ZDVxblRBRkhLU2dJZ1JLQ3ZsdU9TZ0E1TzIxcDUKICAgICAgICA1MXRkcm1rSEVaUnIwcWxMU0pkSFlnRWZNems9CiAgICAgICAgLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQogICAgICBrZXlQRU06IHwKICAgICAgICAtLS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KICAgICAgICBNSGNDQVFFRUlBQWU4bmZielp1OWMvT0IyKzh4Sk0wRno3TlV3VFFhenVsa0ZOczRUSTUrb0FvR0NDcUdTTTQ5CiAgICAgICAgQXdFSG9VUURRZ0FFMS9GcGZjUm5EY2VkTDZBalVhWFlQdjRESU1CYUp1Zk9JNU5XdHkrWFNYN0pqWGdadE03MgogICAgICAgIGRRdlJhWWFudXhEMzZEdDEyL0p4eWlTZ3hLV1Jkb2F5K1E9PQogICAgICAgIC0tLS0tRU5EIEVDIFBSSVZBVEUgS0VZLS0tLS0KaWRlbnRpdHlUcnVzdEFuY2hvcnNQRU06IHwKICAtLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KICBNSUlCd1RDQ0FXYWdBd0lCQWdJUWVEWnA1bERhSXlnUTVVZk1LWnJGQVRBS0JnZ3Foa2pPUFFRREFqQXBNU2N3CiAgSlFZRFZRUURFeDVwWkdWdWRHbDBlUzVzYVc1clpYSmtMbU5zZFhOMFpYSXViRzlqWVd3d0hoY05NakF3T0RJNAogIE1EY3hNalEzV2hjTk16QXdPREkyTURjeE1qUTNXakFwTVNjd0pRWURWUVFERXg1cFpHVnVkR2wwZVM1c2FXNXIKICBaWEprTG1Oc2RYTjBaWEl1Ykc5allXd3dXVEFUQmdjcWhrak9QUUlCQmdncWhrak9QUU1CQndOQ0FBUnFjNzBaCiAgbDF2Z3c3OXJqQjV1U0lUSUNVQTZHeWZ2U0ZmY3VJaXM3Qi9YRlNra3dBSFU1Uy9zMUFBUCtSMFRYN0hCV1VDNAogIHVhRzRXV3Npd0pLTm43bWdvM0F3YmpBT0JnTlZIUThCQWY4RUJBTUNBUVl3RWdZRFZSMFRBUUgvQkFnd0JnRUIKICAvd0lCQVRBZEJnTlZIUTRFRmdRVTVZdGpWVlBmZDdJN05MSHNuMkMyNkVCeUdWMHdLUVlEVlIwUkJDSXdJSUllCiAgYVdSbGJuUnBkSGt1YkdsdWEyVnlaQzVqYkhWemRHVnlMbXh2WTJGc01Bb0dDQ3FHU000OUJBTUNBMGtBTUVZQwogIElRQ043bEJGTEREdmp4NlYwK1hranBLRVJSc0pZZjVhZE12bmxvRmw0OGlsSmdJaEFOdHhobmRjcitRSlB1QzgKICB2Z1VDMGQyLzlGTXVlSVZNYis0NldUQ09qc3FyCiAgLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQpwb2xpY3lDb250cm9sbGVyOgogIGltYWdlOgogICAgbmFtZTogbXkuY3VzdG9tLnJlZ2lzdHJ5L2xpbmtlcmQtaW8vcG9saWN5LWNvbnRyb2xsZXIKICAgIHZlcnNpb246IGluc3RhbGwtY29udHJvbC1wbGFuZS12ZXJzaW9uCnBvbGljeVZhbGlkYXRvcjoKICBjYUJ1bmRsZTogcG9saWN5IHZhbGlkYXRvciBDQSBidW5kbGUKICBjcnRQRU06IHBvbGljeSB2YWxpZGF0b3IgY3J0CiAga2V5UEVNOiBwb2xpY3kgdmFsaWRhdG9yIGtleQpwcm9maWxlVmFsaWRhdG9yOgogIGNhQnVuZGxlOiBwcm9maWxlIHZhbGlkYXRvciBDQSBidW5kbGUKICBjcnRQRU06IHByb2ZpbGUgdmFsaWRhdG9yIGNydAogIGtleVBFTTogcHJvZmlsZSB2YWxpZGF0b3Iga2V5CnByb3h5OgogIGltYWdlOgogICAgbmFtZTogbXkuY3VzdG9tLnJlZ2lzdHJ5L2xpbmtlcmQtaW8vcHJveHkKICAgIHZlcnNpb246IGluc3RhbGwtcHJveHktdmVyc2lvbgpwcm94eUluaXQ6CiAgaW1hZ2U6CiAgICBuYW1lOiBteS5jdXN0b20ucmVnaXN0cnkvbGlua2VyZC1pby9wcm94eS1pbml0CnByb3h5SW5qZWN0b3I6CiAgY2FCdW5kbGU6IHByb3h5IGluamVjdG9yIENBIGJ1bmRsZQogIGNydFBFTTogcHJveHkgaW5qZWN0b3IgY3J0CiAga2V5UEVNOiBwcm94eSBpbmplY3RvciBrZXkK kind: Secret metadata: creationTimestamp: null diff --git a/cli/flag/flag.go b/cli/flag/flag.go index 46311df55..c44bb1fe4 100644 --- a/cli/flag/flag.go +++ b/cli/flag/flag.go @@ -186,6 +186,11 @@ func (flag *StringFlag) Apply(values *charts.Values) error { return flag.apply(values, flag.Value) } +// Set sets the given value to the underlying Flag +func (flag *StringFlag) Set(value string) error { + return flag.flagSet.Set(flag.name, value) +} + // IsSet returns true if and only if the Flag has been explicitly set with a value. func (flag *StringFlag) IsSet() bool { return flag.flagSet.Changed(flag.name) diff --git a/jaeger/cmd/install.go b/jaeger/cmd/install.go index 231d4ddb2..6fd228fe5 100644 --- a/jaeger/cmd/install.go +++ b/jaeger/cmd/install.go @@ -2,6 +2,7 @@ package cmd import ( "bytes" + "fmt" "io" "os" "path" @@ -10,6 +11,7 @@ import ( "github.com/linkerd/linkerd2/jaeger/static" "github.com/linkerd/linkerd2/pkg/charts" partials "github.com/linkerd/linkerd2/pkg/charts/static" + "github.com/linkerd/linkerd2/pkg/cmd" "github.com/linkerd/linkerd2/pkg/flags" "github.com/linkerd/linkerd2/pkg/healthcheck" api "github.com/linkerd/linkerd2/pkg/public" @@ -31,6 +33,7 @@ var ( ) func newCmdInstall() *cobra.Command { + var registry string var skipChecks bool var wait time.Duration var options values.Options @@ -62,10 +65,12 @@ A full list of configurable values can be found at https://www.github.com/linker }) } - return install(os.Stdout, options) + return install(os.Stdout, options, registry) }, } + cmd.Flags().StringVar(®istry, "registry", "cr.l5d.io/linkerd", + fmt.Sprintf("Docker registry to pull jaeger-webhook image from ($%s)", flags.EnvOverrideDockerRegistry)) cmd.Flags().BoolVar(&skipChecks, "skip-checks", false, `Skip checks for linkerd core control-plane existence`) cmd.Flags().DurationVar(&wait, "wait", 300*time.Second, "Wait for core control-plane components to be available") @@ -74,7 +79,7 @@ A full list of configurable values can be found at https://www.github.com/linker return cmd } -func install(w io.Writer, options values.Options) error { +func install(w io.Writer, options values.Options, registry string) error { // Create values override valuesOverrides, err := options.MergeValues(nil) @@ -84,10 +89,10 @@ func install(w io.Writer, options values.Options) error { // TODO: Add any validation logic here - return render(w, valuesOverrides) + return render(w, valuesOverrides, registry) } -func render(w io.Writer, valuesOverrides map[string]interface{}) error { +func render(w io.Writer, valuesOverrides map[string]interface{}, registry string) error { files := []*loader.BufferedFile{ {Name: chartutil.ChartfileName}, @@ -133,6 +138,15 @@ func render(w io.Writer, valuesOverrides map[string]interface{}) error { return err } + regOrig := vals["webhook"].(map[string]interface{})["image"].(map[string]interface{})["name"].(string) + if registry != "" { + vals["webhook"].(map[string]interface{})["image"].(map[string]interface{})["name"] = cmd.RegistryOverride(regOrig, registry) + } + // env var overrides CLI flag + if override := os.Getenv(flags.EnvOverrideDockerRegistry); override != "" { + vals["webhook"].(map[string]interface{})["image"].(map[string]interface{})["name"] = cmd.RegistryOverride(regOrig, override) + } + // Attach the final values into the `Values` field for rendering to work renderedTemplates, err := engine.Render(chart, map[string]interface{}{"Values": vals}) if err != nil { diff --git a/jaeger/cmd/install_test.go b/jaeger/cmd/install_test.go index e54daed8a..3c7e03b57 100644 --- a/jaeger/cmd/install_test.go +++ b/jaeger/cmd/install_test.go @@ -46,7 +46,7 @@ func TestRender(t *testing.T) { t.Run(fmt.Sprintf("%d: %s", i, tc.goldenFileName), func(t *testing.T) { var buf bytes.Buffer // Merge overrides with default - if err := render(&buf, charts.MergeMaps(defaultValues, tc.values)); err != nil { + if err := render(&buf, charts.MergeMaps(defaultValues, tc.values), ""); err != nil { t.Fatalf("Failed to render templates: %v", err) } testDataDiffer.DiffTestdata(t, tc.goldenFileName, buf.String()) diff --git a/multicluster/cmd/link.go b/multicluster/cmd/link.go index 55edae876..6c472e39e 100644 --- a/multicluster/cmd/link.go +++ b/multicluster/cmd/link.go @@ -327,7 +327,8 @@ A full list of configurable values can be found at https://github.com/linkerd/li cmd.Flags().StringVar(&opts.gatewayNamespace, "gateway-namespace", defaultMulticlusterNamespace, "The namespace of the gateway service") cmd.Flags().Uint32Var(&opts.serviceMirrorRetryLimit, "service-mirror-retry-limit", opts.serviceMirrorRetryLimit, "The number of times a failed update from the target cluster is allowed to be retried") cmd.Flags().StringVar(&opts.logLevel, "log-level", opts.logLevel, "Log level for the Multicluster components") - cmd.Flags().StringVar(&opts.dockerRegistry, "registry", opts.dockerRegistry, "Docker registry to pull service mirror controller image from") + cmd.Flags().StringVar(&opts.dockerRegistry, "registry", opts.dockerRegistry, + fmt.Sprintf("Docker registry to pull service mirror controller image from ($%s)", flags.EnvOverrideDockerRegistry)) cmd.Flags().StringVarP(&opts.selector, "selector", "l", opts.selector, "Selector (label query) to filter which services in the target cluster to mirror") cmd.Flags().StringVar(&opts.gatewayAddresses, "gateway-addresses", opts.gatewayAddresses, "If specified, overwrites gateway addresses when gateway service is not type LoadBalancer (comma separated list)") cmd.Flags().Uint32Var(&opts.gatewayPort, "gateway-port", opts.gatewayPort, "If specified, overwrites gateway port when gateway service is not type LoadBalancer") @@ -379,6 +380,10 @@ func buildServiceMirrorValues(opts *linkOptions) (*multicluster.Values, error) { return nil, err } + if reg := os.Getenv(flags.EnvOverrideDockerRegistry); reg != "" { + opts.dockerRegistry = reg + } + defaults.TargetClusterName = opts.clusterName defaults.Namespace = opts.namespace defaults.ServiceMirrorRetryLimit = opts.serviceMirrorRetryLimit diff --git a/pkg/cmd/cmd.go b/pkg/cmd/cmd.go index 8f1e32d1c..2b0808298 100644 --- a/pkg/cmd/cmd.go +++ b/pkg/cmd/cmd.go @@ -146,3 +146,19 @@ func GetLabelSelector(labelKey string, labelValues ...string) (string, error) { selector := labels.NewSelector().Add(*labelRequirement) return selector.String(), nil } + +// RegistryOverride replaces the registry-portion of the provided image with the provided registry. +func RegistryOverride(image, newRegistry string) string { + if image == "" { + return image + } + registry := newRegistry + if registry != "" && !strings.HasSuffix(registry, "/") { + registry += "/" + } + imageName := image + if strings.Contains(image, "/") { + imageName = image[strings.LastIndex(image, "/")+1:] + } + return registry + imageName +} diff --git a/pkg/flags/flags.go b/pkg/flags/flags.go index 82ca13b0b..71f66d736 100644 --- a/pkg/flags/flags.go +++ b/pkg/flags/flags.go @@ -12,6 +12,18 @@ import ( klog "k8s.io/klog/v2" ) +const ( + + // EnvOverrideNamespace is the environment variable used in the CLI to + // overidde the control-plane's namespace + EnvOverrideNamespace = "LINKERD_NAMESPACE" + + // EnvOverrideDockerRegistry is the environment variable used in the + // CLI to override the docker images' registry in the control-plane + // manifests + EnvOverrideDockerRegistry = "LINKERD_DOCKER_REGISTRY" +) + // ConfigureAndParse adds flags that are common to all go processes. This // func calls flag.Parse(), so it should be called after all other flags have // been configured. diff --git a/test/integration/inject/inject_test.go b/test/integration/inject/inject_test.go index de2fb644e..a63aca79d 100644 --- a/test/integration/inject/inject_test.go +++ b/test/integration/inject/inject_test.go @@ -10,6 +10,7 @@ import ( "time" "github.com/linkerd/linkerd2/controller/gen/client/clientset/versioned/scheme" + "github.com/linkerd/linkerd2/pkg/flags" "github.com/linkerd/linkerd2/pkg/k8s" "github.com/linkerd/linkerd2/pkg/version" "github.com/linkerd/linkerd2/testutil" @@ -52,12 +53,16 @@ func parseDeployment(yamlString string) (*appsv1.Deployment, error) { } func TestInjectManualParams(t *testing.T) { + reg := "cr.l5d.io/linkerd" + if override := os.Getenv(flags.EnvOverrideDockerRegistry); reg != "" { + reg = override + } injectionValidator := testutil.InjectValidator{ DisableIdentity: true, Version: "proxy-version", - Image: "proxy-image", - InitImage: "init-image", + Image: reg + "/proxy-image", + InitImage: reg + "/init-image", ImagePullPolicy: "Never", ControlPort: 123, SkipInboundPorts: "234,345", @@ -380,9 +385,13 @@ func TestInjectAutoPod(t *testing.T) { truthy := true falsy := false zero := int64(0) + reg := "cr.l5d.io/linkerd" + if override := os.Getenv(flags.EnvOverrideDockerRegistry); override != "" { + reg = override + } expectedInitContainer := v1.Container{ Name: k8s.InitContainerName, - Image: "cr.l5d.io/linkerd/proxy-init:" + version.ProxyInitVersion, + Image: reg + "/proxy-init:" + version.ProxyInitVersion, Args: []string{ "--incoming-proxy-port", "4143", "--outgoing-proxy-port", "4140", diff --git a/test/integration/install_test.go b/test/integration/install_test.go index 7bb75937b..a53929d5e 100644 --- a/test/integration/install_test.go +++ b/test/integration/install_test.go @@ -13,6 +13,8 @@ import ( "text/template" "time" + "github.com/linkerd/linkerd2/pkg/cmd" + "github.com/linkerd/linkerd2/pkg/flags" "github.com/linkerd/linkerd2/pkg/healthcheck" "github.com/linkerd/linkerd2/pkg/k8s" "github.com/linkerd/linkerd2/pkg/tls" @@ -511,6 +513,24 @@ func helmOverridesEdge(root *tls.CA) ([]string, []string) { "--set", "linkerdVersion=" + TestHelper.GetVersion(), "--set", "namespace=" + TestHelper.GetVizNamespace(), } + + if override := os.Getenv(flags.EnvOverrideDockerRegistry); override != "" { + coreArgs = append(coreArgs, + "--set", "policyController.image.name="+cmd.RegistryOverride("cr.l5d.io/linkerd/policy-controller", override), + "--set", "proxy.image.name="+cmd.RegistryOverride("cr.l5d.io/linkerd/proxy", override), + "--set", "proxyInit.image.name="+cmd.RegistryOverride("cr.l5d.io/linkerd/proxy-init", override), + "--set", "controllerImage="+cmd.RegistryOverride("cr.l5d.io/linkerd/controller", override), + "--set", "debugContainer.image.name="+cmd.RegistryOverride("cr.l5d.io/linkerd/debug", override), + ) + vizArgs = append(vizArgs, + "--set", "metricsAPI.image.registry="+override, + "--set", "tap.image.registry="+override, + "--set", "tapInjector.image.registry="+override, + "--set", "dashboard.image.registry="+override, + "--set", "grafana.image.registry="+override, + ) + } + return coreArgs, vizArgs } @@ -757,18 +777,40 @@ func TestOverridesSecret(t *testing.T) { knownKeys := tree.Tree{ "controllerLogLevel": "debug", "heartbeatSchedule": "1 2 3 4 5", - "identity": map[string]interface{}{ - "issuer": map[string]interface{}{}, + "identity": tree.Tree{ + "issuer": tree.Tree{}, }, "identityTrustAnchorsPEM": extractValue(t, "identityTrustAnchorsPEM"), - "proxyInit": map[string]interface{}{ + "proxyInit": tree.Tree{ "ignoreInboundPorts": skippedInboundPorts, }, } + if reg := os.Getenv(flags.EnvOverrideDockerRegistry); reg != "" { + knownKeys["controllerImage"] = reg + "/controller" + knownKeys["debugContainer"] = tree.Tree{ + "image": tree.Tree{ + "name": reg + "/debug", + }, + } + knownKeys["policyController"] = tree.Tree{ + "image": tree.Tree{ + "name": reg + "/policy-controller", + }, + } + knownKeys["proxy"] = tree.Tree{ + "image": tree.Tree{ + "name": reg + "/proxy", + }, + } + knownKeys["proxyInit"].(tree.Tree)["image"] = tree.Tree{ + "name": reg + "/proxy-init", + } + } + // Check for fields that were added during upgrade if TestHelper.UpgradeFromVersion() != "" { - knownKeys["proxyInit"].(map[string]interface{})["ignoreOutboundPorts"] = skippedOutboundPorts + knownKeys["proxyInit"].(tree.Tree)["ignoreOutboundPorts"] = skippedOutboundPorts } if TestHelper.GetClusterDomain() != "cluster.local" { @@ -776,13 +818,13 @@ func TestOverridesSecret(t *testing.T) { } if TestHelper.ExternalIssuer() { - knownKeys["identity"].(map[string]interface{})["issuer"].(map[string]interface{})["issuanceLifetime"] = "15s" - knownKeys["identity"].(map[string]interface{})["issuer"].(map[string]interface{})["scheme"] = "kubernetes.io/tls" + knownKeys["identity"].(tree.Tree)["issuer"].(tree.Tree)["issuanceLifetime"] = "15s" + knownKeys["identity"].(tree.Tree)["issuer"].(tree.Tree)["scheme"] = "kubernetes.io/tls" } else { if !TestHelper.Multicluster() { - knownKeys["identity"].(map[string]interface{})["issuer"].(map[string]interface{})["crtExpiry"] = extractValue(t, "identity", "issuer", "crtExpiry") + knownKeys["identity"].(tree.Tree)["issuer"].(tree.Tree)["crtExpiry"] = extractValue(t, "identity", "issuer", "crtExpiry") } - knownKeys["identity"].(map[string]interface{})["issuer"].(map[string]interface{})["tls"] = map[string]interface{}{ + knownKeys["identity"].(tree.Tree)["issuer"].(tree.Tree)["tls"] = tree.Tree{ "crtPEM": extractValue(t, "identity", "issuer", "tls", "crtPEM"), "keyPEM": extractValue(t, "identity", "issuer", "tls", "keyPEM"), } diff --git a/viz/cmd/install.go b/viz/cmd/install.go index 82d78f70a..ea67f9f0f 100644 --- a/viz/cmd/install.go +++ b/viz/cmd/install.go @@ -92,11 +92,13 @@ func install(w io.Writer, options values.Options, ha bool) error { return err } - // if using -L to specify a non-standard CP namespace, make sure - // the linkerdNamespace Helm value is synced + // sync values overrides with Helm values if controlPlaneNamespace != defaultLinkerdNamespace { valuesOverrides["linkerdNamespace"] = controlPlaneNamespace } + if reg := os.Getenv(flags.EnvOverrideDockerRegistry); reg != "" { + valuesOverrides["defaultRegistry"] = reg + } if ha { valuesOverrides, err = charts.OverrideFromFile(valuesOverrides, static.Templates, vizChartName, "values-ha.yaml")