You've already forked woodpecker
							
							
				mirror of
				https://github.com/woodpecker-ci/woodpecker.git
				synced 2025-10-30 23:27:39 +02:00 
			
		
		
		
	Flexible image pull secret reference (#3016)
Co-authored-by: pat-s <patrick.schratz@gmail.com>
This commit is contained in:
		| @@ -46,6 +46,10 @@ agent: | ||||
|  | ||||
|   Determines if containers must be required to run as non-root users. | ||||
|  | ||||
| - `WOODPECKER_BACKEND_K8S_PULL_SECRET_NAMES` (default: empty) | ||||
|  | ||||
|   Secret names to pull images from private repositories. | ||||
|  | ||||
| ## Job specific configuration | ||||
|  | ||||
| ### Resources | ||||
|   | ||||
| @@ -7,6 +7,7 @@ Some versions need some changes to the server configuration or the pipeline conf | ||||
| - Deprecated `steps.[name].group` in favor of `steps.[name].depends_on` (see [workflow syntax](./20-usage/20-workflow-syntax.md#depends_on) to learn how to set dependencies) | ||||
| - Removed `WOODPECKER_ROOT_PATH` and `WOODPECKER_ROOT_URL` config variables. Use `WOODPECKER_HOST` with a path instead | ||||
| - Pipelines without a config file will now be skipped instead of failing | ||||
| - Deprecated implicitly defined `regcred` image pull secret. Set it explicitly via `WOODPECKER_BACKEND_K8S_PULL_SECRET_NAMES`. | ||||
|  | ||||
| ## 2.0.0 | ||||
|  | ||||
|   | ||||
| @@ -74,4 +74,10 @@ var Flags = []cli.Flag{ | ||||
| 		Usage:   "duration to wait before retrying to connect to the server", | ||||
| 		Value:   time.Second * 2, | ||||
| 	}, | ||||
| 	&cli.StringSliceFlag{ | ||||
| 		EnvVars: []string{"WOODPECKER_BACKEND_K8S_PULL_SECRET_NAMES"}, | ||||
| 		Name:    "backend-k8s-pod-image-pull-secret-names", | ||||
| 		Usage:   "backend k8s pull secret names for private registries", | ||||
| 		Value:   cli.NewStringSlice("regcred"), | ||||
| 	}, | ||||
| } | ||||
|   | ||||
| @@ -54,13 +54,14 @@ type kube struct { | ||||
| } | ||||
|  | ||||
| type config struct { | ||||
| 	Namespace       string | ||||
| 	StorageClass    string | ||||
| 	VolumeSize      string | ||||
| 	StorageRwx      bool | ||||
| 	PodLabels       map[string]string | ||||
| 	PodAnnotations  map[string]string | ||||
| 	SecurityContext SecurityContextConfig | ||||
| 	Namespace            string | ||||
| 	StorageClass         string | ||||
| 	VolumeSize           string | ||||
| 	StorageRwx           bool | ||||
| 	PodLabels            map[string]string | ||||
| 	PodAnnotations       map[string]string | ||||
| 	ImagePullSecretNames []string | ||||
| 	SecurityContext      SecurityContextConfig | ||||
| } | ||||
| type SecurityContextConfig struct { | ||||
| 	RunAsNonRoot bool | ||||
| @@ -80,16 +81,21 @@ func configFromCliContext(ctx context.Context) (*config, error) { | ||||
| 	if ctx != nil { | ||||
| 		if c, ok := ctx.Value(types.CliContext).(*cli.Context); ok { | ||||
| 			config := config{ | ||||
| 				Namespace:      c.String("backend-k8s-namespace"), | ||||
| 				StorageClass:   c.String("backend-k8s-storage-class"), | ||||
| 				VolumeSize:     c.String("backend-k8s-volume-size"), | ||||
| 				StorageRwx:     c.Bool("backend-k8s-storage-rwx"), | ||||
| 				PodLabels:      make(map[string]string), // just init empty map to prevent nil panic | ||||
| 				PodAnnotations: make(map[string]string), // just init empty map to prevent nil panic | ||||
| 				Namespace:            c.String("backend-k8s-namespace"), | ||||
| 				StorageClass:         c.String("backend-k8s-storage-class"), | ||||
| 				VolumeSize:           c.String("backend-k8s-volume-size"), | ||||
| 				StorageRwx:           c.Bool("backend-k8s-storage-rwx"), | ||||
| 				PodLabels:            make(map[string]string), // just init empty map to prevent nil panic | ||||
| 				PodAnnotations:       make(map[string]string), // just init empty map to prevent nil panic | ||||
| 				ImagePullSecretNames: c.StringSlice("backend-k8s-pod-image-pull-secret-names"), | ||||
| 				SecurityContext: SecurityContextConfig{ | ||||
| 					RunAsNonRoot: c.Bool("backend-k8s-secctx-nonroot"), | ||||
| 				}, | ||||
| 			} | ||||
| 			// TODO: remove in next major | ||||
| 			if len(config.ImagePullSecretNames) == 1 && config.ImagePullSecretNames[0] == "regcred" { | ||||
| 				log.Warn().Msg("WOODPECKER_BACKEND_K8S_PULL_SECRET_NAMES is set to the default ('regcred'). It will default to empty in Woodpecker 3.0. Set it explicitly before then.") | ||||
| 			} | ||||
| 			// Unmarshal label and annotation settings here to ensure they're valid on startup | ||||
| 			if labels := c.String("backend-k8s-pod-labels"); labels != "" { | ||||
| 				if err := yaml.Unmarshal([]byte(labels), &config.PodLabels); err != nil { | ||||
|   | ||||
| @@ -36,7 +36,7 @@ const ( | ||||
|  | ||||
| func mkPod(namespace, name, image, workDir, goos, serviceAccountName string, | ||||
| 	pool, privileged bool, | ||||
| 	commands, vols []string, | ||||
| 	commands, vols, pullSecretNames []string, | ||||
| 	labels, annotations, env, nodeSelector map[string]string, | ||||
| 	extraHosts []types.HostAlias, tolerations []types.Toleration, resources types.Resources, | ||||
| 	securityContext *types.SecurityContext, securityContextConfig SecurityContextConfig, | ||||
| @@ -45,7 +45,8 @@ func mkPod(namespace, name, image, workDir, goos, serviceAccountName string, | ||||
|  | ||||
| 	meta := podMeta(name, namespace, labels, annotations) | ||||
|  | ||||
| 	spec, err := podSpec(serviceAccountName, vols, env, nodeSelector, extraHosts, tolerations, securityContext, securityContextConfig) | ||||
| 	spec, err := podSpec(serviceAccountName, vols, pullSecretNames, env, nodeSelector, extraHosts, tolerations, | ||||
| 		securityContext, securityContextConfig) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @@ -85,7 +86,7 @@ func podMeta(name, namespace string, labels, annotations map[string]string) meta | ||||
| 	return meta | ||||
| } | ||||
|  | ||||
| func podSpec(serviceAccountName string, vols []string, env, backendNodeSelector map[string]string, | ||||
| func podSpec(serviceAccountName string, vols, pullSecretNames []string, env, backendNodeSelector map[string]string, | ||||
| 	extraHosts []types.HostAlias, backendTolerations []types.Toleration, | ||||
| 	securityContext *types.SecurityContext, securityContextConfig SecurityContextConfig, | ||||
| ) (v1.PodSpec, error) { | ||||
| @@ -93,7 +94,7 @@ func podSpec(serviceAccountName string, vols []string, env, backendNodeSelector | ||||
| 	spec := v1.PodSpec{ | ||||
| 		RestartPolicy:      v1.RestartPolicyNever, | ||||
| 		ServiceAccountName: serviceAccountName, | ||||
| 		ImagePullSecrets:   []v1.LocalObjectReference{{Name: "regcred"}}, | ||||
| 		ImagePullSecrets:   imagePullSecretsReferences(pullSecretNames), | ||||
| 	} | ||||
|  | ||||
| 	spec.HostAliases = hostAliases(extraHosts) | ||||
| @@ -211,6 +212,22 @@ func hostAlias(extraHost types.HostAlias) v1.HostAlias { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func imagePullSecretsReferences(imagePullSecretNames []string) []v1.LocalObjectReference { | ||||
| 	log.Trace().Msgf("Using the image pull secrets: %v", imagePullSecretNames) | ||||
|  | ||||
| 	secretReferences := make([]v1.LocalObjectReference, len(imagePullSecretNames)) | ||||
| 	for i, imagePullSecretName := range imagePullSecretNames { | ||||
| 		secretReferences[i] = imagePullSecretsReference(imagePullSecretName) | ||||
| 	} | ||||
| 	return secretReferences | ||||
| } | ||||
|  | ||||
| func imagePullSecretsReference(imagePullSecretName string) v1.LocalObjectReference { | ||||
| 	return v1.LocalObjectReference{ | ||||
| 		Name: imagePullSecretName, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func resourceRequirements(resources types.Resources) (v1.ResourceRequirements, error) { | ||||
| 	var err error | ||||
| 	requirements := v1.ResourceRequirements{} | ||||
| @@ -357,7 +374,7 @@ func startPod(ctx context.Context, engine *kube, step *types.Step) (*v1.Pod, err | ||||
|  | ||||
| 	pod, err := mkPod(engine.config.Namespace, podName, step.Image, step.WorkingDir, engine.goos, step.BackendOptions.Kubernetes.ServiceAccountName, | ||||
| 		step.Pull, step.Privileged, | ||||
| 		step.Commands, step.Volumes, | ||||
| 		step.Commands, step.Volumes, engine.config.ImagePullSecretNames, | ||||
| 		engine.config.PodLabels, engine.config.PodAnnotations, step.Environment, step.BackendOptions.Kubernetes.NodeSelector, | ||||
| 		step.ExtraHosts, step.BackendOptions.Kubernetes.Tolerations, step.BackendOptions.Kubernetes.Resources, step.BackendOptions.Kubernetes.SecurityContext, engine.config.SecurityContext) | ||||
| 	if err != nil { | ||||
|   | ||||
| @@ -96,19 +96,14 @@ func TestTinyPod(t *testing.T) { | ||||
| 					] | ||||
| 				} | ||||
| 			], | ||||
| 			"restartPolicy": "Never", | ||||
| 			"imagePullSecrets": [ | ||||
| 				{ | ||||
| 					"name": "regcred" | ||||
| 				} | ||||
| 			] | ||||
| 			"restartPolicy": "Never" | ||||
| 		}, | ||||
| 		"status": {} | ||||
| 	}` | ||||
|  | ||||
| 	pod, err := mkPod("woodpecker", "wp-01he8bebctabr3kgk0qj36d2me-0", "gradle:8.4.0-jdk21", "/woodpecker/src", "linux/amd64", "", | ||||
| 		false, false, | ||||
| 		[]string{"gradle build"}, []string{"workspace:/woodpecker/src"}, | ||||
| 		[]string{"gradle build"}, []string{"workspace:/woodpecker/src"}, nil, | ||||
| 		nil, nil, map[string]string{"CI": "woodpecker"}, nil, | ||||
| 		nil, nil, | ||||
| 		types.Resources{Requests: nil, Limits: nil}, nil, SecurityContextConfig{}, | ||||
| @@ -213,6 +208,9 @@ func TestFullPod(t *testing.T) { | ||||
| 			"imagePullSecrets": [ | ||||
| 				{ | ||||
| 					"name": "regcred" | ||||
| 				}, | ||||
| 				{ | ||||
| 					"name": "another-pull-secret" | ||||
| 				} | ||||
| 			], | ||||
| 			"tolerations": [ | ||||
| @@ -246,7 +244,7 @@ func TestFullPod(t *testing.T) { | ||||
| 	} | ||||
| 	pod, err := mkPod("woodpecker", "wp-01he8bebctabr3kgk0qj36d2me-0", "meltwater/drone-cache", "/woodpecker/src", "linux/amd64", "wp-svc-acc", | ||||
| 		true, true, | ||||
| 		[]string{"go get", "go test"}, []string{"woodpecker-cache:/woodpecker/src/cache"}, | ||||
| 		[]string{"go get", "go test"}, []string{"woodpecker-cache:/woodpecker/src/cache"}, []string{"regcred", "another-pull-secret"}, | ||||
| 		map[string]string{"app": "test"}, map[string]string{"apparmor.security": "runtime/default"}, map[string]string{"CGO": "0"}, map[string]string{"storage": "ssd"}, | ||||
| 		hostAliases, []types.Toleration{{Key: "net-port", Value: "100Mbit", Effect: types.TaintEffectNoSchedule}}, | ||||
| 		types.Resources{Requests: map[string]string{"memory": "128Mi", "cpu": "1000m"}, Limits: map[string]string{"memory": "256Mi", "cpu": "2"}}, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user