Skip to content

Commit 97d6896

Browse files
committed
[Contour Gateway Provisioner] add imagepullsecret for envoy and contour (fixes #7138)
Signed-off-by: flbla <[email protected]>
1 parent 1db83a7 commit 97d6896

File tree

8 files changed

+102
-26
lines changed

8 files changed

+102
-26
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
add a new flag: --image-pull-secret-name, which allows users to specify a secret in the same namespace as the deployed contour control plane for pulling images from private registries. when set, it's used to pull Envoy and Contour images.

cmd/contour/gatewayprovisioner.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ func registerGatewayProvisioner(app *kingpin.Application) (*kingpin.CmdClause, *
4141
leaderElection: false,
4242
leaderElectionID: "0d879e31.projectcontour.io",
4343
gatewayControllerName: "projectcontour.io/gateway-controller",
44+
imagePullSecret: "",
4445
}
4546

4647
cmd.Flag("contour-image", "The container image used for the managed Contour.").
@@ -58,6 +59,10 @@ func registerGatewayProvisioner(app *kingpin.Application) (*kingpin.CmdClause, *
5859
Default(provisionerConfig.gatewayControllerName).
5960
StringVar(&provisionerConfig.gatewayControllerName)
6061

62+
cmd.Flag("image-pull-secret-name", "The image pull secret for the managed Envoy and Contour.").
63+
Default(provisionerConfig.imagePullSecret).
64+
StringVar(&provisionerConfig.imagePullSecret)
65+
6166
cmd.Flag("incluster", "Use in cluster configuration.").
6267
Default("true").
6368
BoolVar(&provisionerConfig.inCluster)
@@ -85,6 +90,10 @@ type gatewayProvisionerConfig struct {
8590
// by the gateway provisioner.
8691
envoyImage string
8792

93+
// imagePullSecret is the name of the image pull secret that will be used
94+
// to pull the Contour and Envoy images.
95+
imagePullSecret string
96+
8897
// metricsBindAddress is the TCP address that the gateway provisioner should bind to for
8998
// serving prometheus metrics. It can be set to "0" to disable the metrics serving.
9099
metricsBindAddress string
@@ -171,7 +180,7 @@ func createManager(restConfig *rest.Config, provisionerConfig *gatewayProvisione
171180
if _, err := controller.NewGatewayClassController(mgr, provisionerConfig.gatewayControllerName); err != nil {
172181
return nil, fmt.Errorf("failed to create gatewayclass controller: %w", err)
173182
}
174-
if _, err := controller.NewGatewayController(mgr, provisionerConfig.gatewayControllerName, provisionerConfig.contourImage, provisionerConfig.envoyImage); err != nil {
183+
if _, err := controller.NewGatewayController(mgr, provisionerConfig.gatewayControllerName, provisionerConfig.contourImage, provisionerConfig.envoyImage, provisionerConfig.imagePullSecret); err != nil {
175184
return nil, fmt.Errorf("failed to create gateway controller: %w", err)
176185
}
177186
return mgr, nil

internal/provisioner/controller/gateway.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,17 @@ type gatewayReconciler struct {
4949
gatewayController gatewayapi_v1.GatewayController
5050
contourImage string
5151
envoyImage string
52+
imagePullSecret string
5253
client client.Client
5354
log logr.Logger
5455
}
5556

56-
func NewGatewayController(mgr manager.Manager, gatewayController, contourImage, envoyImage string) (controller.Controller, error) {
57+
func NewGatewayController(mgr manager.Manager, gatewayController, contourImage, envoyImage, imagePullSecret string) (controller.Controller, error) {
5758
r := &gatewayReconciler{
5859
gatewayController: gatewayapi_v1.GatewayController(gatewayController),
5960
contourImage: contourImage,
6061
envoyImage: envoyImage,
62+
imagePullSecret: imagePullSecret,
6163
client: mgr.GetClient(),
6264
log: ctrl.Log.WithName("gateway-controller"),
6365
}
@@ -432,8 +434,8 @@ func (r *gatewayReconciler) ensureContour(ctx context.Context, contour *model.Co
432434

433435
handleResult("contour config", contourconfig.EnsureContourConfig(ctx, r.client, contour))
434436
handleResult("xDS TLS secrets", secret.EnsureXDSSecrets(ctx, r.client, contour, r.contourImage))
435-
handleResult("deployment", deployment.EnsureDeployment(ctx, r.client, contour, r.contourImage))
436-
handleResult("envoy data plane", dataplane.EnsureDataPlane(ctx, r.client, contour, r.contourImage, r.envoyImage))
437+
handleResult("deployment", deployment.EnsureDeployment(ctx, r.client, contour, r.contourImage, r.imagePullSecret))
438+
handleResult("envoy data plane", dataplane.EnsureDataPlane(ctx, r.client, contour, r.contourImage, r.envoyImage, r.imagePullSecret))
437439
handleResult("contour service", service.EnsureContourService(ctx, r.client, contour))
438440

439441
switch contour.Spec.NetworkPublishing.Envoy.Type {

internal/provisioner/equality/equality_test.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,11 @@ import (
3030
)
3131

3232
var (
33-
testName = "test"
34-
testNs = testName + "-ns"
35-
testImage = "test-image:main"
36-
cntr = &model.Contour{
33+
testName = "test"
34+
testNs = testName + "-ns"
35+
testImage = "test-image:main"
36+
testImagePullSecret = ""
37+
cntr = &model.Contour{
3738
ObjectMeta: meta_v1.ObjectMeta{
3839
Name: testName,
3940
Namespace: testNs,
@@ -122,7 +123,7 @@ func TestDaemonSetConfigChanged(t *testing.T) {
122123

123124
for _, tc := range testCases {
124125
t.Run(tc.description, func(t *testing.T) {
125-
original := dataplane.DesiredDaemonSet(cntr, testImage, testImage)
126+
original := dataplane.DesiredDaemonSet(cntr, testImage, testImage, testImagePullSecret)
126127

127128
mutated := original.DeepCopy()
128129
tc.mutate(mutated)
@@ -218,7 +219,7 @@ func TestDeploymentConfigChanged(t *testing.T) {
218219
}
219220

220221
for _, tc := range testCases {
221-
original := deployment.DesiredDeployment(cntr, testImage)
222+
original := deployment.DesiredDeployment(cntr, testImage, testImagePullSecret)
222223
mutated := original.DeepCopy()
223224
tc.mutate(mutated)
224225
if updated, changed := equality.DeploymentConfigChanged(original, mutated); changed != tc.expect {

internal/provisioner/objects/dataplane/dataplane.go

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,11 @@ var defContainerResources = core_v1.ResourceRequirements{
7575
}
7676

7777
// EnsureDataPlane ensures an Envoy data plane (daemonset or deployment) exists for the given contour.
78-
func EnsureDataPlane(ctx context.Context, cli client.Client, contour *model.Contour, contourImage, envoyImage string) error {
78+
func EnsureDataPlane(ctx context.Context, cli client.Client, contour *model.Contour, contourImage, envoyImage, imagePullSecret string) error {
7979
switch contour.Spec.EnvoyWorkloadType {
8080
// If a Deployment was specified, provision a Deployment.
8181
case model.WorkloadTypeDeployment:
82-
desired := desiredDeployment(contour, contourImage, envoyImage)
82+
desired := desiredDeployment(contour, contourImage, envoyImage, imagePullSecret)
8383

8484
updater := func(ctx context.Context, cli client.Client, current, desired *apps_v1.Deployment) error {
8585
differ := equality.DeploymentSelectorsDiffer(current, desired)
@@ -94,7 +94,7 @@ func EnsureDataPlane(ctx context.Context, cli client.Client, contour *model.Cont
9494

9595
// The default workload type is a DaemonSet.
9696
default:
97-
desired := DesiredDaemonSet(contour, contourImage, envoyImage)
97+
desired := DesiredDaemonSet(contour, contourImage, envoyImage, imagePullSecret)
9898

9999
updater := func(ctx context.Context, cli client.Client, current, desired *apps_v1.DaemonSet) error {
100100
differ := equality.DaemonSetSelectorsDiffer(current, desired)
@@ -335,7 +335,7 @@ func desiredContainers(contour *model.Contour, contourImage, envoyImage string)
335335
// DesiredDaemonSet returns the desired DaemonSet for the provided contour using
336336
// contourImage as the shutdown-manager/envoy-initconfig container images and
337337
// envoyImage as Envoy's container image.
338-
func DesiredDaemonSet(contour *model.Contour, contourImage, envoyImage string) *apps_v1.DaemonSet {
338+
func DesiredDaemonSet(contour *model.Contour, contourImage, envoyImage, imagePullSecret string) *apps_v1.DaemonSet {
339339
initContainers, containers := desiredContainers(contour, contourImage, envoyImage)
340340

341341
ds := &apps_v1.DaemonSet{
@@ -403,10 +403,18 @@ func DesiredDaemonSet(contour *model.Contour, contourImage, envoyImage string) *
403403
ds.Spec.Template.Spec.Tolerations = contour.Spec.NodePlacement.Envoy.Tolerations
404404
}
405405

406+
if imagePullSecret != "" {
407+
ds.Spec.Template.Spec.ImagePullSecrets = []core_v1.LocalObjectReference{
408+
{
409+
Name: imagePullSecret,
410+
},
411+
}
412+
}
413+
406414
return ds
407415
}
408416

409-
func desiredDeployment(contour *model.Contour, contourImage, envoyImage string) *apps_v1.Deployment {
417+
func desiredDeployment(contour *model.Contour, contourImage, envoyImage, imagePullSecret string) *apps_v1.Deployment {
410418
initContainers, containers := desiredContainers(contour, contourImage, envoyImage)
411419

412420
deployment := &apps_v1.Deployment{
@@ -488,6 +496,14 @@ func desiredDeployment(contour *model.Contour, contourImage, envoyImage string)
488496
deployment.Spec.Template.Spec.Tolerations = contour.Spec.NodePlacement.Envoy.Tolerations
489497
}
490498

499+
if imagePullSecret != "" {
500+
deployment.Spec.Template.Spec.ImagePullSecrets = []core_v1.LocalObjectReference{
501+
{
502+
Name: imagePullSecret,
503+
},
504+
}
505+
}
506+
491507
return deployment
492508
}
493509

internal/provisioner/objects/dataplane/dataplane_test.go

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ func TestDesiredDaemonSet(t *testing.T) {
311311

312312
testContourImage := "ghcr.io/projectcontour/contour:test"
313313
testEnvoyImage := "docker.io/envoyproxy/envoy:test"
314+
testImagePullSecret := ""
314315
testLogLevelArg := "--log-level debug"
315316
testBaseIDArg := "--base-id 1"
316317
testEnvoyMaxHeapSize := "--overload-max-heap=8000000000"
@@ -343,7 +344,7 @@ func TestDesiredDaemonSet(t *testing.T) {
343344
cntr.Spec.EnvoyMaxHeapSizeBytes = 8000000000
344345
cntr.Spec.EnvoyMaxDownstreamConnections = 42
345346

346-
ds := DesiredDaemonSet(cntr, testContourImage, testEnvoyImage)
347+
ds := DesiredDaemonSet(cntr, testContourImage, testEnvoyImage, testImagePullSecret)
347348
container := checkDaemonSetHasContainer(t, ds, EnvoyContainerName, true)
348349
checkContainerHasArg(t, container, testLogLevelArg)
349350
checkContainerHasArg(t, container, testBaseIDArg)
@@ -386,7 +387,8 @@ func TestDesiredDeployment(t *testing.T) {
386387

387388
testContourImage := "ghcr.io/projectcontour/contour:test"
388389
testEnvoyImage := "docker.io/envoyproxy/envoy:test"
389-
deploy := desiredDeployment(cntr, testContourImage, testEnvoyImage)
390+
testImagePullSecret := ""
391+
deploy := desiredDeployment(cntr, testContourImage, testEnvoyImage, testImagePullSecret)
390392
checkDeploymentHasStrategy(t, deploy, cntr.Spec.EnvoyDeploymentStrategy)
391393
checkEnvoyDeploymentHasAffinity(t, deploy, cntr)
392394
}
@@ -414,7 +416,8 @@ func TestNodePlacementDaemonSet(t *testing.T) {
414416

415417
testContourImage := "ghcr.io/projectcontour/contour:test"
416418
testEnvoyImage := "docker.io/envoyproxy/envoy:test"
417-
ds := DesiredDaemonSet(cntr, testContourImage, testEnvoyImage)
419+
testImagePullSecret := ""
420+
ds := DesiredDaemonSet(cntr, testContourImage, testEnvoyImage, testImagePullSecret)
418421
checkDaemonSetHasNodeSelector(t, ds, selectors)
419422
checkDaemonSetHasTolerations(t, ds, tolerations)
420423
}
@@ -436,9 +439,28 @@ func TestEnvoyCustomPorts(t *testing.T) {
436439

437440
testContourImage := "ghcr.io/projectcontour/contour:test"
438441
testEnvoyImage := "docker.io/envoyproxy/envoy:test"
439-
ds := DesiredDaemonSet(cntr, testContourImage, testEnvoyImage)
442+
testImagePullSecret := ""
443+
ds := DesiredDaemonSet(cntr, testContourImage, testEnvoyImage, testImagePullSecret)
440444
checkContainerHasPort(t, ds, int32(metricPort))
441445

442446
container := checkDaemonSetHasContainer(t, ds, EnvoyContainerName, true)
443447
checkContainerHasReadinessPort(t, container, 8020)
444448
}
449+
450+
func TestDesiredDaemonSetWithImagePullSecret(t *testing.T) {
451+
name := "ds-test"
452+
cntr := model.Default(fmt.Sprintf("%s-ns", name), name)
453+
cntr.Spec.NetworkPublishing.Envoy.Ports = []model.Port{
454+
{Name: "http", ServicePort: 80, ContainerPort: 8080},
455+
}
456+
testContourImage := "ghcr.io/projectcontour/contour:test"
457+
testEnvoyImage := "docker.io/envoyproxy/envoy:test"
458+
testImagePullSecret := "my-secret"
459+
460+
ds := DesiredDaemonSet(cntr, testContourImage, testEnvoyImage, testImagePullSecret)
461+
462+
require.NotNil(t, ds)
463+
require.NotNil(t, ds.Spec.Template.Spec.ImagePullSecrets)
464+
require.Len(t, ds.Spec.Template.Spec.ImagePullSecrets, 1)
465+
require.Equal(t, testImagePullSecret, ds.Spec.Template.Spec.ImagePullSecrets[0].Name)
466+
}

internal/provisioner/objects/deployment/deployment.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ const (
5252
)
5353

5454
// EnsureDeployment ensures a deployment using image exists for the given contour.
55-
func EnsureDeployment(ctx context.Context, cli client.Client, contour *model.Contour, image string) error {
56-
desired := DesiredDeployment(contour, image)
55+
func EnsureDeployment(ctx context.Context, cli client.Client, contour *model.Contour, image, imagePullSecret string) error {
56+
desired := DesiredDeployment(contour, image, imagePullSecret)
5757

5858
updater := func(ctx context.Context, cli client.Client, current, desired *apps_v1.Deployment) error {
5959
differ := equality.DeploymentSelectorsDiffer(current, desired)
@@ -82,7 +82,7 @@ func EnsureDeploymentDeleted(ctx context.Context, cli client.Client, contour *mo
8282

8383
// DesiredDeployment returns the desired deployment for the provided contour using
8484
// image as Contour's container image.
85-
func DesiredDeployment(contour *model.Contour, image string) *apps_v1.Deployment {
85+
func DesiredDeployment(contour *model.Contour, image, imagePullSecret string) *apps_v1.Deployment {
8686
xdsPort := objects.XDSPort
8787
args := []string{
8888
"serve",
@@ -276,6 +276,14 @@ func DesiredDeployment(contour *model.Contour, image string) *apps_v1.Deployment
276276
deploy.Spec.Template.Spec.Tolerations = contour.Spec.NodePlacement.Contour.Tolerations
277277
}
278278

279+
if imagePullSecret != "" {
280+
deploy.Spec.Template.Spec.ImagePullSecrets = []core_v1.LocalObjectReference{
281+
{
282+
Name: imagePullSecret,
283+
},
284+
}
285+
}
286+
279287
return deploy
280288
}
281289

internal/provisioner/objects/deployment/deployment_test.go

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,8 @@ func TestDesiredDeployment(t *testing.T) {
178178
}
179179

180180
testContourImage := "ghcr.io/projectcontour/contour:test"
181-
deploy := DesiredDeployment(cntr, testContourImage)
181+
testImagePullSecret := ""
182+
deploy := DesiredDeployment(cntr, testContourImage, testImagePullSecret)
182183

183184
container := checkDeploymentHasContainer(t, deploy, contourContainerName, true)
184185
checkContainerHasImage(t, container, testContourImage)
@@ -239,7 +240,7 @@ func TestDesiredDeploymentWhenSettingWatchNamespaces(t *testing.T) {
239240
cntr.Spec.IngressClassName = &icName
240241
// Change the Contour watch namespaces flag
241242
cntr.Spec.WatchNamespaces = tc.namespaces
242-
deploy := DesiredDeployment(cntr, "ghcr.io/projectcontour/contour:test")
243+
deploy := DesiredDeployment(cntr, "ghcr.io/projectcontour/contour:test", "")
243244
container := checkDeploymentHasContainer(t, deploy, contourContainerName, true)
244245
arg := fmt.Sprintf("--watch-namespaces=%s", strings.Join(append(model.NamespacesToStrings(tc.namespaces), cntr.Namespace), ","))
245246
checkContainerHasArg(t, container, arg)
@@ -268,7 +269,7 @@ func TestNodePlacementDeployment(t *testing.T) {
268269
},
269270
}
270271

271-
deploy := DesiredDeployment(cntr, "ghcr.io/projectcontour/contour:test")
272+
deploy := DesiredDeployment(cntr, "ghcr.io/projectcontour/contour:test", "")
272273

273274
checkDeploymentHasNodeSelector(t, deploy, selectors)
274275
checkDeploymentHasTolerations(t, deploy, tolerations)
@@ -297,7 +298,7 @@ func TestDesiredDeploymentWhenSettingDisabledFeature(t *testing.T) {
297298
cntr.Spec.IngressClassName = &icName
298299
cntr.Spec.DisabledFeatures = tc.disabledFeatures
299300
// Change the Contour watch namespaces flag
300-
deploy := DesiredDeployment(cntr, "ghcr.io/projectcontour/contour:test")
301+
deploy := DesiredDeployment(cntr, "ghcr.io/projectcontour/contour:test", "")
301302
container := checkDeploymentHasContainer(t, deploy, contourContainerName, true)
302303
for _, f := range tc.disabledFeatures {
303304
arg := fmt.Sprintf("--disable-feature=%s", string(f))
@@ -306,3 +307,19 @@ func TestDesiredDeploymentWhenSettingDisabledFeature(t *testing.T) {
306307
})
307308
}
308309
}
310+
311+
func TestDesiredDeploymentWithImagePullSecret(t *testing.T) {
312+
name := "deploy-test"
313+
cntr := model.Default(fmt.Sprintf("%s-ns", name), name)
314+
icName := "test-ic"
315+
cntr.Spec.IngressClassName = &icName
316+
317+
testContourImage := "ghcr.io/projectcontour/contour:test"
318+
testImagePullSecret := "my-secret"
319+
deploy := DesiredDeployment(cntr, testContourImage, testImagePullSecret)
320+
321+
require.NotNil(t, deploy)
322+
require.NotNil(t, deploy.Spec.Template.Spec.ImagePullSecrets)
323+
require.Len(t, deploy.Spec.Template.Spec.ImagePullSecrets, 1)
324+
require.Equal(t, testImagePullSecret, deploy.Spec.Template.Spec.ImagePullSecrets[0].Name)
325+
}

0 commit comments

Comments
 (0)