Allow adding additional labels/annotations to kubernetes worker pods (#1510)

Example agent environment configuration using the new value:
```yaml
  - env:
    - name: WOODPECKER_BACKEND
      value: kubernetes
    - name: WOODPECKER_BACKEND_K8S_NAMESPACE
      value: default
    - name: WOODPECKER_BACKEND_K8S_POD_LABELS
      value: '{"sidecar.istio.io/inject":"false"}'
```
This commit is contained in:
Stephen Muth 2022-12-30 19:37:09 -05:00 committed by GitHub
parent 0923aa2624
commit 1816f6c715
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 57 additions and 14 deletions

View file

@ -14,6 +14,8 @@ env:
WOODPECKER_BACKEND_K8S_STORAGE_CLASS: "" WOODPECKER_BACKEND_K8S_STORAGE_CLASS: ""
WOODPECKER_BACKEND_K8S_VOLUME_SIZE: 10G WOODPECKER_BACKEND_K8S_VOLUME_SIZE: 10G
WOODPECKER_BACKEND_K8S_STORAGE_RWX: true 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 # Docker-in-Docker is normally not needed as Woodpecker natively supports Kubernetes
dind: dind:

View file

@ -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)", Usage: "backend k8s storage access mode, should ReadWriteMany (RWX) instead of ReadWriteOnce (RWO) be used? (default: true)",
Value: 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: "",
},
} }

View file

@ -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)", Usage: "backend k8s storage access mode, should ReadWriteMany (RWX) instead of ReadWriteOnce (RWO) be used? (default: true)",
Value: 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: "",
},
} }

View file

@ -11,6 +11,7 @@ import (
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/woodpecker-ci/woodpecker/pipeline/backend/types" "github.com/woodpecker-ci/woodpecker/pipeline/backend/types"
"gopkg.in/yaml.v3"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
@ -39,21 +40,35 @@ type kube struct {
} }
type Config struct { type Config struct {
Namespace string Namespace string
StorageClass string StorageClass string
VolumeSize string VolumeSize string
StorageRwx bool PodLabels map[string]string
PodAnnotations map[string]string
StorageRwx bool
} }
func configFromCliContext(ctx context.Context) (*Config, error) { func configFromCliContext(ctx context.Context) (*Config, error) {
if ctx != nil { if ctx != nil {
if c, ok := ctx.Value(types.CliContext).(*cli.Context); ok { if c, ok := ctx.Value(types.CliContext).(*cli.Context); ok {
return &Config{ config := Config{
Namespace: c.String("backend-k8s-namespace"), Namespace: c.String("backend-k8s-namespace"),
StorageClass: c.String("backend-k8s-storage-class"), StorageClass: c.String("backend-k8s-storage-class"),
VolumeSize: c.String("backend-k8s-volume-size"), VolumeSize: c.String("backend-k8s-volume-size"),
StorageRwx: c.Bool("backend-k8s-storage-rwx"), 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. // Start the pipeline step.
func (e *kube) Exec(ctx context.Context, step *types.Step) error { 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) log.Trace().Msgf("Creating pod: %s", pod.Name)
_, err := e.client.CoreV1().Pods(e.config.Namespace).Create(ctx, pod, metav1.CreateOptions{}) _, err := e.client.CoreV1().Pods(e.config.Namespace).Create(ctx, pod, metav1.CreateOptions{})
return err return err
@ -232,7 +247,8 @@ func (e *kube) Tail(ctx context.Context, step *types.Step) (io.ReadCloser, error
<-up <-up
opts := &v1.PodLogOptions{ opts := &v1.PodLogOptions{
Follow: true, Follow: true,
Container: podName,
} }
logs, err := e.client.CoreV1().RESTClient().Get(). logs, err := e.client.CoreV1().RESTClient().Get().

View file

@ -10,7 +10,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 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 ( var (
vols []v1.Volume vols []v1.Volume
volMounts []v1.VolumeMount volMounts []v1.VolumeMount
@ -88,13 +88,14 @@ func Pod(namespace string, step *types.Step) *v1.Pod {
}, },
} }
labels["step"] = podName(step)
return &v1.Pod{ return &v1.Pod{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: podName(step), Name: podName(step),
Namespace: namespace, Namespace: namespace,
Labels: map[string]string{ Labels: labels,
"step": podName(step), Annotations: annotations,
},
}, },
Spec: v1.PodSpec{ Spec: v1.PodSpec{
RestartPolicy: v1.RestartPolicyNever, RestartPolicy: v1.RestartPolicyNever,