Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flexible image pull secret reference #3016

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions docs/versioned_docs/version-2.1/91-migrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 6 additions & 0 deletions pipeline/backend/kubernetes/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
qwerty287 marked this conversation as resolved.
Show resolved Hide resolved
Value: cli.NewStringSlice("regcred"),
},
}
32 changes: 19 additions & 13 deletions pipeline/backend/kubernetes/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,14 @@
}

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
Expand All @@ -80,16 +81,21 @@
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"),

Check warning on line 90 in pipeline/backend/kubernetes/kubernetes.go

View check run for this annotation

Codecov / codecov/patch

pipeline/backend/kubernetes/kubernetes.go#L84-L90

Added lines #L84 - L90 were not covered by tests
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.")
}

Check warning on line 98 in pipeline/backend/kubernetes/kubernetes.go

View check run for this annotation

Codecov / codecov/patch

pipeline/backend/kubernetes/kubernetes.go#L95-L98

Added lines #L95 - L98 were not covered by tests
// 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 {
Expand Down
27 changes: 22 additions & 5 deletions pipeline/backend/kubernetes/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@

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,
Expand All @@ -45,7 +45,8 @@

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
}
Expand Down Expand Up @@ -85,15 +86,15 @@
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) {
var err error
spec := v1.PodSpec{
RestartPolicy: v1.RestartPolicyNever,
ServiceAccountName: serviceAccountName,
ImagePullSecrets: []v1.LocalObjectReference{{Name: "regcred"}},
ImagePullSecrets: imagePullSecretsReferences(pullSecretNames),
}

spec.HostAliases = hostAliases(extraHosts)
Expand Down Expand Up @@ -211,6 +212,22 @@
}
}

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{}
Expand Down Expand Up @@ -357,7 +374,7 @@

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,

Check warning on line 377 in pipeline/backend/kubernetes/pod.go

View check run for this annotation

Codecov / codecov/patch

pipeline/backend/kubernetes/pod.go#L377

Added line #L377 was not covered by tests
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 {
Expand Down
14 changes: 6 additions & 8 deletions pipeline/backend/kubernetes/pod_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{},
Expand Down Expand Up @@ -213,6 +208,9 @@ func TestFullPod(t *testing.T) {
"imagePullSecrets": [
{
"name": "regcred"
},
{
"name": "another-pull-secret"
}
],
"tolerations": [
Expand Down Expand Up @@ -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"}},
Expand Down