Skip to content

Commit

Permalink
feat: add defaults configurable runtimeClassName
Browse files Browse the repository at this point in the history
allow the setting of Pod RuntimeClassName via defaults
  • Loading branch information
BobyMCbobs committed Jun 5, 2024
1 parent 3e53acc commit f63e7f9
Show file tree
Hide file tree
Showing 6 changed files with 339 additions and 1 deletion.
17 changes: 16 additions & 1 deletion config/core/configmaps/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ metadata:
app.kubernetes.io/component: controller
app.kubernetes.io/version: devel
annotations:
knative.dev/example-checksum: "ed77183a"
knative.dev/example-checksum: "022a770f"
data:
# This is the Go import path for the binary that is containerized
# and substituted here.
Expand Down Expand Up @@ -91,3 +91,18 @@ data:
# Sets rootCA for the queue proxy - used by QPOptions
# If omitted, or empty, no rootCA is added to the golang rootCAs
queue-sidecar-rootca: ""
# runtime-class-name contains the selector for which runtimeClassName
# is selected to put in a revision.
# By default, it is not set by Knative.
#
# Example:
# runtime-class-name: |
# "":
# selector:
# use-default-runc: "yes"
# kata: {}
# gvisor:
# selector:
# use-gvisor: "please"
runtime-class-name: ""
55 changes: 55 additions & 0 deletions pkg/deployment/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ package deployment
import (
"errors"
"fmt"
"strings"
"time"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/util/sets"
"sigs.k8s.io/yaml"

cm "knative.dev/pkg/configmap"
"knative.dev/pkg/ptr"
)

const (
Expand Down Expand Up @@ -103,6 +106,7 @@ func defaultConfig() *Config {
DigestResolutionTimeout: digestResolutionTimeoutDefault,
RegistriesSkippingTagResolving: sets.New("kind.local", "ko.local", "dev.local"),
QueueSidecarCPURequest: &QueueSidecarCPURequestDefault,
RuntimeClassName: "",
}
// The following code is needed for ConfigMap testing.
// defaultConfig must match the example in deployment.yaml which includes: `queue-sidecar-token-audiences: ""`
Expand All @@ -113,6 +117,52 @@ func defaultConfig() *Config {
return cfg
}

func (d Config) PodRuntimeClassName(lbs map[string]string) *string {
cfg := map[string]RuntimeClassNameLabelSelector{}
if err := yaml.Unmarshal([]byte(d.RuntimeClassName), &cfg); err != nil {
return nil
}
runtimeClassName := ""
specificity := -1
for k, v := range cfg {
if !v.Matches(lbs) || v.specificity() < specificity {
continue
}
if v.specificity() > specificity || strings.Compare(k, runtimeClassName) < 0 {
runtimeClassName = k
specificity = v.specificity()
}
}
if runtimeClassName == "" {
return nil
}
return ptr.String(runtimeClassName)
}

type RuntimeClassNameLabelSelector struct {
Selector map[string]string `json:"selector,omitempty"`
}

func (s *RuntimeClassNameLabelSelector) specificity() int {
if s.Selector == nil {
return 0
}
return len(s.Selector)
}

func (s *RuntimeClassNameLabelSelector) Matches(labels map[string]string) bool {
if s.Selector == nil {
return true
}
for label, expectedValue := range s.Selector {
value, ok := labels[label]
if !ok || expectedValue != value {
return false
}
}
return true
}

// NewConfigFromMap creates a DeploymentConfig from the supplied Map.
func NewConfigFromMap(configMap map[string]string) (*Config, error) {
nc := defaultConfig()
Expand Down Expand Up @@ -144,6 +194,8 @@ func NewConfigFromMap(configMap map[string]string) (*Config, error) {

cm.AsStringSet(queueSidecarTokenAudiencesKey, &nc.QueueSidecarTokenAudiences),
cm.AsString(queueSidecarRooCAKey, &nc.QueueSidecarRootCA),

cm.AsString("runtime-class-name", &nc.RuntimeClassName),
); err != nil {
return nil, err
}
Expand Down Expand Up @@ -214,4 +266,7 @@ type Config struct {

// QueueSidecarRootCA is a root certificate to be trusted by the queue proxy sidecar qpoptions.
QueueSidecarRootCA string

// RuntimeClassName is which runtime the Pod will use
RuntimeClassName string
}
135 changes: 135 additions & 0 deletions pkg/deployment/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ import (
"github.com/google/go-cmp/cmp"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"

"knative.dev/pkg/ptr"
"knative.dev/pkg/system"
"knative.dev/serving/test/conformance/api/shared"

Expand Down Expand Up @@ -269,6 +271,63 @@ func TestControllerConfiguration(t *testing.T) {
QueueSidecarEphemeralStorageLimit: quantity("21M"),
QueueSidecarTokenAudiences: sets.New("foo"),
},
}, {
name: "runtime class name defaults to nothing",
wantErr: false,
data: map[string]string{
QueueSidecarImageKey: defaultSidecarImage,
},
wantConfig: &Config{
DigestResolutionTimeout: digestResolutionTimeoutDefault,
ProgressDeadline: ProgressDeadlineDefault,
QueueSidecarCPURequest: &QueueSidecarCPURequestDefault,
QueueSidecarImage: defaultSidecarImage,
QueueSidecarTokenAudiences: sets.New(""),
RegistriesSkippingTagResolving: sets.New("kind.local", "ko.local", "dev.local"),
RuntimeClassName: "",
},
}, {
name: "runtime class name with wildcard",
wantErr: false,
wantConfig: &Config{
RuntimeClassName: "gvisor: {}",
DigestResolutionTimeout: digestResolutionTimeoutDefault,
ProgressDeadline: ProgressDeadlineDefault,
QueueSidecarCPURequest: &QueueSidecarCPURequestDefault,
QueueSidecarImage: defaultSidecarImage,
QueueSidecarTokenAudiences: sets.New(""),
RegistriesSkippingTagResolving: sets.New("kind.local", "ko.local", "dev.local"),
},
data: map[string]string{
"runtime-class-name": "gvisor: {}",
QueueSidecarImageKey: defaultSidecarImage,
},
}, {
name: "runtime class name with wildcard and label selectors",
wantErr: false,
wantConfig: &Config{
RuntimeClassName: `---
gvisor: {}
kata:
selector:
some: value-here
`,
DigestResolutionTimeout: digestResolutionTimeoutDefault,
ProgressDeadline: ProgressDeadlineDefault,
QueueSidecarCPURequest: &QueueSidecarCPURequestDefault,
QueueSidecarImage: defaultSidecarImage,
QueueSidecarTokenAudiences: sets.New(""),
RegistriesSkippingTagResolving: sets.New("kind.local", "ko.local", "dev.local"),
},
data: map[string]string{
"runtime-class-name": `---
gvisor: {}
kata:
selector:
some: value-here
`,
QueueSidecarImageKey: defaultSidecarImage,
},
}}

for _, tt := range configTests {
Expand Down Expand Up @@ -304,3 +363,79 @@ func quantity(val string) *resource.Quantity {
r := resource.MustParse(val)
return &r
}

func TestPodRuntimeClassName(t *testing.T) {
ts := []struct {
name string
serviceLabels map[string]string
runtimeClassNames string
want *string
}{{
name: "empty",
serviceLabels: map[string]string{},
runtimeClassNames: "",
want: nil,
}, {
name: "wildcard set",
serviceLabels: map[string]string{},
runtimeClassNames: `gvisor: {}`,
want: ptr.String("gvisor"),
}, {
name: "set via label",
serviceLabels: map[string]string{
"very-cool": "indeed",
},
runtimeClassNames: `---
gvisor: {}
kata:
selector:
very-cool: indeed
`,
want: ptr.String("kata"),
}, {
name: "no default only labels with set labels",
serviceLabels: map[string]string{
"very-cool": "indeed",
},
runtimeClassNames: `---
"": {}
kata:
selector:
very-cool: indeed
`,
want: ptr.String("kata"),
}, {
name: "no default only labels with set no labels",
serviceLabels: map[string]string{},
runtimeClassNames: `---
"": {}
kata:
selector:
very-cool: indeed
`,
want: nil,
}, {
name: "invalid configuration",
serviceLabels: map[string]string{},
runtimeClassNames: `---
"": ""
`,
want: nil,
}}

for _, tt := range ts {
tt := tt
t.Run(tt.name, func(t *testing.T) {
if tt.serviceLabels == nil {
tt.serviceLabels = map[string]string{}
}
defaults := defaultConfig()
defaults.RuntimeClassName = tt.runtimeClassNames
got, want := defaults.PodRuntimeClassName(tt.serviceLabels), tt.want

if !equality.Semantic.DeepEqual(got, want) {
t.Errorf("PodRuntimeClassName() = %v, wanted %v", got, want)
}
})
}
}
23 changes: 23 additions & 0 deletions pkg/deployment/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions pkg/reconciler/revision/resources/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ func makePodSpec(rev *v1.Revision, cfg *config.Config) (*corev1.PodSpec, error)
podSpec := BuildPodSpec(rev, append(BuildUserContainers(rev), *queueContainer), cfg)
podSpec.Volumes = append(podSpec.Volumes, extraVolumes...)

if val := cfg.Deployment.PodRuntimeClassName(rev.ObjectMeta.Labels); podSpec.RuntimeClassName != nil {
podSpec.RuntimeClassName = val
}
if cfg.Observability.EnableVarLogCollection {
podSpec.Volumes = append(podSpec.Volumes, varLogVolume)

Expand Down
Loading

0 comments on commit f63e7f9

Please sign in to comment.