diff --git a/charts/woodpecker-agent/values.yaml b/charts/woodpecker-agent/values.yaml index 36b19eece..433a8f84a 100644 --- a/charts/woodpecker-agent/values.yaml +++ b/charts/woodpecker-agent/values.yaml @@ -14,6 +14,8 @@ env: WOODPECKER_BACKEND_K8S_STORAGE_CLASS: "" WOODPECKER_BACKEND_K8S_VOLUME_SIZE: 10G WOODPECKER_BACKEND_K8S_STORAGE_RWX: true + WOODPECKER_BACKEND_K8S_POD_LABELS: "" + WOODPECKER_BACKEND_K8S_POD_ANNOTATIONS: "" # Docker-in-Docker is normally not needed as Woodpecker natively supports Kubernetes dind: diff --git a/cli/exec/flags.go b/cli/exec/flags.go index 0d68e0fc8..9d5d52cdb 100644 --- a/cli/exec/flags.go +++ b/cli/exec/flags.go @@ -295,4 +295,16 @@ var flags = []cli.Flag{ Usage: "backend k8s storage access mode, should ReadWriteMany (RWX) instead of ReadWriteOnce (RWO) be used? (default: true)", Value: true, }, + &cli.StringFlag{ + EnvVars: []string{"WOODPECKER_BACKEND_K8S_POD_LABELS"}, + Name: "backend-k8s-pod-labels", + Usage: "backend k8s additional worker pod labels", + Value: "", + }, + &cli.StringFlag{ + EnvVars: []string{"WOODPECKER_BACKEND_K8S_POD_ANNOTATIONS"}, + Name: "backend-k8s-pod-annotations", + Usage: "backend k8s additional worker pod annotations", + Value: "", + }, } diff --git a/cmd/agent/flags.go b/cmd/agent/flags.go index 8740d71e9..fbb956955 100644 --- a/cmd/agent/flags.go +++ b/cmd/agent/flags.go @@ -141,4 +141,16 @@ var flags = []cli.Flag{ Usage: "backend k8s storage access mode, should ReadWriteMany (RWX) instead of ReadWriteOnce (RWO) be used? (default: true)", Value: true, }, + &cli.StringFlag{ + EnvVars: []string{"WOODPECKER_BACKEND_K8S_POD_LABELS"}, + Name: "backend-k8s-pod-labels", + Usage: "backend k8s additional worker pod labels", + Value: "", + }, + &cli.StringFlag{ + EnvVars: []string{"WOODPECKER_BACKEND_K8S_POD_ANNOTATIONS"}, + Name: "backend-k8s-pod-annotations", + Usage: "backend k8s additional worker pod annotations", + Value: "", + }, } diff --git a/pipeline/backend/kubernetes/kubernetes.go b/pipeline/backend/kubernetes/kubernetes.go index 5cd1087c0..0ae4688cc 100644 --- a/pipeline/backend/kubernetes/kubernetes.go +++ b/pipeline/backend/kubernetes/kubernetes.go @@ -11,6 +11,7 @@ import ( "github.com/rs/zerolog/log" "github.com/woodpecker-ci/woodpecker/pipeline/backend/types" + "gopkg.in/yaml.v3" "github.com/urfave/cli/v2" v1 "k8s.io/api/core/v1" @@ -39,21 +40,35 @@ type kube struct { } type Config struct { - Namespace string - StorageClass string - VolumeSize string - StorageRwx bool + Namespace string + StorageClass string + VolumeSize string + PodLabels map[string]string + PodAnnotations map[string]string + StorageRwx bool } func configFromCliContext(ctx context.Context) (*Config, error) { if ctx != nil { if c, ok := ctx.Value(types.CliContext).(*cli.Context); ok { - return &Config{ + 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"), - }, nil + } + // Unmarshal label and annotation settings here to ensure they're valid on startup + err := yaml.Unmarshal([]byte(c.String("backend-k8s-pod-labels")), &config.PodLabels) + if err != nil { + log.Error().Msgf("could not unmarshal pod labels '%s': %s", c.String("backend-k8s-pod-labels"), err) + return nil, err + } + err = yaml.Unmarshal([]byte(c.String("backend-k8s-pod-annotations")), &config.PodAnnotations) + if err != nil { + log.Error().Msgf("could not unmarshal pod annotations '%s': %s", c.String("backend-k8s-pod-annotations"), err) + return nil, err + } + return &config, nil } } @@ -147,7 +162,7 @@ func (e *kube) Setup(ctx context.Context, conf *types.Config) error { // Start the pipeline step. func (e *kube) Exec(ctx context.Context, step *types.Step) error { - pod := Pod(e.config.Namespace, step) + pod := Pod(e.config.Namespace, step, e.config.PodLabels, e.config.PodAnnotations) log.Trace().Msgf("Creating pod: %s", pod.Name) _, err := e.client.CoreV1().Pods(e.config.Namespace).Create(ctx, pod, metav1.CreateOptions{}) return err @@ -232,7 +247,8 @@ func (e *kube) Tail(ctx context.Context, step *types.Step) (io.ReadCloser, error <-up opts := &v1.PodLogOptions{ - Follow: true, + Follow: true, + Container: podName, } logs, err := e.client.CoreV1().RESTClient().Get(). diff --git a/pipeline/backend/kubernetes/pod.go b/pipeline/backend/kubernetes/pod.go index 044a8d76c..1099f7c1a 100644 --- a/pipeline/backend/kubernetes/pod.go +++ b/pipeline/backend/kubernetes/pod.go @@ -10,7 +10,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func Pod(namespace string, step *types.Step) *v1.Pod { +func Pod(namespace string, step *types.Step, labels, annotations map[string]string) *v1.Pod { var ( vols []v1.Volume volMounts []v1.VolumeMount @@ -88,13 +88,14 @@ func Pod(namespace string, step *types.Step) *v1.Pod { }, } + labels["step"] = podName(step) + return &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ - Name: podName(step), - Namespace: namespace, - Labels: map[string]string{ - "step": podName(step), - }, + Name: podName(step), + Namespace: namespace, + Labels: labels, + Annotations: annotations, }, Spec: v1.PodSpec{ RestartPolicy: v1.RestartPolicyNever,