Allow registry to be configured at build time

This adds a new `buildinfo` variable `ImageRegistry` that can set at
build time like the `Version` variable. This allows us to customise the
Velero binary to use different registries.

If the variable is set, this variable wille be used when creating the
URIs for both the main `velero` and `velero-restic-restore-helper`
images. If it is not set, default to using Dockerhub (`velero/velero`,
`velero/velero-restic-restore-helper`).

There are numerous ways in which the Velero binary can be built so all
of them have been updated to add the new link time flag to set the
variable:
* `make local` (used for local developer builds to build for the local
  OS and ARCH)
* `make build` (used by developers and also VMware internal builds to
  build a specific OS and ARCH)
* Goreleaser config (used when creating OSS release binaries)
* Dockerfile (used to build the Velero binary used within the image)

All of these workflows are currently triggered from our Makefile where
the variable `REGISTRY` is already available with the default value of
`velero` and used to build the image tag. Where the new `ImageRegistry`
build variable is needed, we pass through this Makefile variable to
those tasks so it can be used accordingly.

The GitHub action and the `./hack/docker-push.sh` script used to push
container images has not been modified. This will continue to use the
default registry specified in the Makefile and will not explicitly pass
it in.

Signed-off-by: Bridget McErlean <bmcerlean@vmware.com>
This commit is contained in:
Bridget McErlean
2021-07-14 15:42:53 -04:00
parent 02f3f5cd60
commit 198ea57407
16 changed files with 273 additions and 66 deletions
@@ -1,5 +1,5 @@
/*
Copyright 2017 the Velero contributors.
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -31,6 +31,10 @@ var (
// GitTreeState indicates if the git tree is clean or dirty, set by the go linker's -X flag at build
// time.
GitTreeState string
// ImageRegistry is the image registry that this build of Velero should use by default to pull the
// Velero and Restic Restore Helper images from.
ImageRegistry string
)
// FormattedGitSHA renders the Git SHA with an indicator of the tree state.
+3 -2
View File
@@ -1,5 +1,5 @@
/*
Copyright 2020 the Velero contributors.
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@ import (
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"github.com/vmware-tanzu/velero/internal/velero"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/client"
"github.com/vmware-tanzu/velero/pkg/cmd"
@@ -111,7 +112,7 @@ func (o *InstallOptions) BindFlags(flags *pflag.FlagSet) {
func NewInstallOptions() *InstallOptions {
return &InstallOptions{
Namespace: velerov1api.DefaultNamespace,
Image: install.DefaultImage,
Image: velero.DefaultVeleroImage(),
BackupStorageConfig: flag.NewMap(),
VolumeSnapshotConfig: flag.NewMap(),
PodAnnotations: flag.NewMap(),
+4 -2
View File
@@ -1,5 +1,5 @@
/*
Copyright 2018, 2019, 2020 the Velero contributors.
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -23,11 +23,13 @@ import (
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/vmware-tanzu/velero/internal/velero"
)
func DaemonSet(namespace string, opts ...podTemplateOption) *appsv1.DaemonSet {
c := &podTemplateConfig{
image: DefaultImage,
image: velero.DefaultVeleroImage(),
}
for _, opt := range opts {
+3 -2
View File
@@ -1,5 +1,5 @@
/*
Copyright 2020 the Velero contributors.
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/vmware-tanzu/velero/internal/velero"
"github.com/vmware-tanzu/velero/pkg/builder"
)
@@ -117,7 +118,7 @@ func WithDefaultVolumesToRestic() podTemplateOption {
func Deployment(namespace string, opts ...podTemplateOption) *appsv1.Deployment {
// TODO: Add support for server args
c := &podTemplateConfig{
image: DefaultImage,
image: velero.DefaultVeleroImage(),
}
for _, opt := range opts {
-11
View File
@@ -29,20 +29,9 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"github.com/vmware-tanzu/velero/config/crd/crds"
"github.com/vmware-tanzu/velero/pkg/buildinfo"
)
// Use "latest" if the build process didn't supply a version
func imageVersion() string {
if buildinfo.Version == "" {
return "latest"
}
return buildinfo.Version
}
// DefaultImage is the default image to use for the Velero deployment and restic daemonset containers.
var (
DefaultImage = "velero/velero:" + imageVersion()
DefaultVeleroPodCPURequest = "500m"
DefaultVeleroPodMemRequest = "128Mi"
DefaultVeleroPodCPULimit = "1000m"
+11 -19
View File
@@ -1,5 +1,5 @@
/*
Copyright 2018, 2019, 2020 the Velero contributors.
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -29,9 +29,9 @@ import (
"k8s.io/apimachinery/pkg/runtime"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
veleroimage "github.com/vmware-tanzu/velero/internal/velero"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/builder"
"github.com/vmware-tanzu/velero/pkg/buildinfo"
velerov1client "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1"
"github.com/vmware-tanzu/velero/pkg/label"
"github.com/vmware-tanzu/velero/pkg/plugin/framework"
@@ -41,7 +41,6 @@ import (
)
const (
defaultImageBase = "velero/velero-restic-restore-helper"
defaultCPURequestLimit = "100m"
defaultMemRequestLimit = "128Mi"
defaultCommand = "/velero-restic-restore-helper"
@@ -193,13 +192,13 @@ func getCommand(log logrus.FieldLogger, config *corev1.ConfigMap) []string {
func getImage(log logrus.FieldLogger, config *corev1.ConfigMap) string {
if config == nil {
log.Debug("No config found for plugin")
return initContainerImage(defaultImageBase)
return veleroimage.DefaultResticRestoreHelperImage()
}
image := config.Data["image"]
if image == "" {
log.Debugf("No custom image configured")
return initContainerImage(defaultImageBase)
return veleroimage.DefaultResticRestoreHelperImage()
}
log = log.WithField("image", image)
@@ -207,15 +206,17 @@ func getImage(log logrus.FieldLogger, config *corev1.ConfigMap) string {
parts := strings.Split(image, "/")
if len(parts) == 1 {
defaultImage := veleroimage.DefaultResticRestoreHelperImage()
// Image supplied without registry part
log.Debugf("Plugin config contains image name without registry name. Return defaultImageBase")
return initContainerImage(defaultImageBase)
log.Debugf("Plugin config contains image name without registry name. Using default init container image: %q", defaultImage)
return defaultImage
}
if !(strings.Contains(parts[len(parts)-1], ":")) {
// tag-less image name: add tag
log.Debugf("Plugin config contains image name without tag. Adding tag.")
return initContainerImage(image)
tag := veleroimage.ImageTag()
// tag-less image name: add default image tag for this version of Velero
log.Debugf("Plugin config contains image name without tag. Adding tag: %q", tag)
return fmt.Sprintf("%s:%s", image, tag)
} else {
// tagged image name
log.Debugf("Plugin config contains image name with tag")
@@ -306,12 +307,3 @@ func newResticInitContainerBuilder(image, restoreUID string) *builder.ContainerB
},
}...)
}
func initContainerImage(imageBase string) string {
tag := buildinfo.Version
if tag == "" {
tag = "latest"
}
return fmt.Sprintf("%s:%s", imageBase, tag)
}
+34 -26
View File
@@ -1,5 +1,5 @@
/*
Copyright 2019 the Velero contributors.
Copyright the Velero contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@ package restore
import (
"context"
"fmt"
"sort"
"testing"
@@ -31,6 +30,7 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/fake"
veleroimage "github.com/vmware-tanzu/velero/internal/velero"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/builder"
"github.com/vmware-tanzu/velero/pkg/buildinfo"
@@ -49,41 +49,40 @@ func TestGetImage(t *testing.T) {
}
}
originalVersion := buildinfo.Version
buildinfo.Version = "buildinfo-version"
defer func() {
buildinfo.Version = originalVersion
}()
defaultImage := veleroimage.DefaultResticRestoreHelperImage()
tests := []struct {
name string
configMap *corev1api.ConfigMap
want string
name string
configMap *corev1api.ConfigMap
buildInfoVersion string
want string
}{
{
name: "nil config map returns default image with buildinfo.Version as tag",
name: "nil config map returns default image",
configMap: nil,
want: fmt.Sprintf("%s:%s", defaultImageBase, buildinfo.Version),
want: defaultImage,
},
{
name: "config map without 'image' key returns default image with buildinfo.Version as tag",
name: "config map without 'image' key returns default image",
configMap: configMapWithData("non-matching-key", "val"),
want: fmt.Sprintf("%s:%s", defaultImageBase, buildinfo.Version),
want: defaultImage,
},
{
name: "config map without '/' in image name returns default image with buildinfo.Version as tag",
name: "config map without '/' in image name returns default image",
configMap: configMapWithData("image", "my-image"),
want: fmt.Sprintf("%s:%s", defaultImageBase, buildinfo.Version),
want: defaultImage,
},
{
name: "config map with untagged image returns image with buildinfo.Version as tag",
configMap: configMapWithData("image", "myregistry.io/my-image"),
want: fmt.Sprintf("%s:%s", "myregistry.io/my-image", buildinfo.Version),
name: "config map with untagged image returns image with buildinfo.Version as tag",
configMap: configMapWithData("image", "myregistry.io/my-image"),
buildInfoVersion: "buildinfo-version",
want: "myregistry.io/my-image:buildinfo-version",
},
{
name: "config map with untagged image and custom registry port with ':' returns image with buildinfo.Version as tag",
configMap: configMapWithData("image", "myregistry.io:34567/my-image"),
want: fmt.Sprintf("%s:%s", "myregistry.io:34567/my-image", buildinfo.Version),
name: "config map with untagged image and custom registry port with ':' returns image with buildinfo.Version as tag",
configMap: configMapWithData("image", "myregistry.io:34567/my-image"),
buildInfoVersion: "buildinfo-version",
want: "myregistry.io:34567/my-image:buildinfo-version",
},
{
name: "config map with tagged image returns tagged image",
@@ -99,6 +98,13 @@ func TestGetImage(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if test.buildInfoVersion != "" {
originalVersion := buildinfo.Version
buildinfo.Version = test.buildInfoVersion
defer func() {
buildinfo.Version = originalVersion
}()
}
assert.Equal(t, test.want, getImage(velerotest.NewLogger(), test.configMap))
})
}
@@ -119,6 +125,8 @@ func TestResticRestoreActionExecute(t *testing.T) {
veleroNs = "velero"
)
defaultResticRestoreHelperImage := veleroimage.DefaultResticRestoreHelperImage()
tests := []struct {
name string
pod *corev1api.Pod
@@ -135,7 +143,7 @@ func TestResticRestoreActionExecute(t *testing.T) {
ObjectMeta(
builder.WithAnnotations("snapshot.velero.io/myvol", "")).
InitContainers(
newResticInitContainerBuilder(initContainerImage(defaultImageBase), "").
newResticInitContainerBuilder(defaultResticRestoreHelperImage, "").
Resources(&resourceReqs).
SecurityContext(&securityContext).
VolumeMounts(builder.ForVolumeMount("myvol", "/restores/myvol").Result()).
@@ -152,7 +160,7 @@ func TestResticRestoreActionExecute(t *testing.T) {
ObjectMeta(
builder.WithAnnotations("snapshot.velero.io/myvol", "")).
InitContainers(
newResticInitContainerBuilder(initContainerImage(defaultImageBase), "").
newResticInitContainerBuilder(defaultResticRestoreHelperImage, "").
Resources(&resourceReqs).
SecurityContext(&securityContext).
VolumeMounts(builder.ForVolumeMount("myvol", "/restores/myvol").Result()).
@@ -195,7 +203,7 @@ func TestResticRestoreActionExecute(t *testing.T) {
ObjectMeta(
builder.WithAnnotations("snapshot.velero.io/not-used", "")).
InitContainers(
newResticInitContainerBuilder(initContainerImage(defaultImageBase), "").
newResticInitContainerBuilder(defaultResticRestoreHelperImage, "").
Resources(&resourceReqs).
SecurityContext(&securityContext).
VolumeMounts(builder.ForVolumeMount("vol-1", "/restores/vol-1").Result(), builder.ForVolumeMount("vol-2", "/restores/vol-2").Result()).
@@ -239,7 +247,7 @@ func TestResticRestoreActionExecute(t *testing.T) {
builder.ForVolume("vol-2").PersistentVolumeClaimSource("pvc-2").Result(),
).
InitContainers(
newResticInitContainerBuilder(initContainerImage(defaultImageBase), "").
newResticInitContainerBuilder(defaultResticRestoreHelperImage, "").
Resources(&resourceReqs).
SecurityContext(&securityContext).
VolumeMounts(builder.ForVolumeMount("vol-1", "/restores/vol-1").Result(), builder.ForVolumeMount("vol-2", "/restores/vol-2").Result()).