diff --git a/go.mod b/go.mod index d414d58..20c423c 100644 --- a/go.mod +++ b/go.mod @@ -7,22 +7,25 @@ require ( github.com/urfave/cli v1.22.14 golang.org/x/time v0.3.0 gopkg.in/yaml.v2 v2.4.0 + helm.sh/helm/v3 v3.13.3 k8s.io/apimachinery v0.28.4 k8s.io/client-go v0.28.4 k8s.io/kubectl v0.28.4 ) require ( + github.com/Masterminds/semver/v3 v3.2.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/imdario/mergo v0.3.6 // indirect + github.com/imdario/mergo v0.3.13 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect diff --git a/go.sum b/go.sum index e21baab..21a98f2 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,12 @@ github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= +github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -24,8 +26,8 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= -github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= @@ -40,6 +42,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= @@ -112,8 +116,11 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +helm.sh/helm/v3 v3.13.3 h1:0zPEdGqHcubehJHP9emCtzRmu8oYsJFRrlVF3TFj8xY= +helm.sh/helm/v3 v3.13.3/go.mod h1:3OKO33yI3p4YEXtTITN2+4oScsHeQe71KuzhlZ+aPfg= k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY= k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0= k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8= diff --git a/manifests/helm.go b/manifests/helm.go new file mode 100644 index 0000000..2ff5e1f --- /dev/null +++ b/manifests/helm.go @@ -0,0 +1,59 @@ +package manifests + +import ( + "fmt" + "io/fs" + "path/filepath" + "strings" + + "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/chart/loader" +) + +// LoadCharts returns charts from embed filesystem. +func LoadCharts(componentName string) (*chart.Chart, error) { + files, err := getFilesFromFSRecursively(componentName) + if err != nil { + return nil, fmt.Errorf("failed to get chart files: %w", err) + } + + topDir := componentName + string(filepath.Separator) + bufFiles := make([]*loader.BufferedFile, 0, len(files)) + for _, f := range files { + data, err := fs.ReadFile(FS, f) + if err != nil { + return nil, fmt.Errorf("failed to read file (%s): %w", f, err) + } + + fname := filepath.ToSlash(strings.TrimPrefix(f, topDir)) + bufFiles = append(bufFiles, + &loader.BufferedFile{ + Name: fname, + Data: data, + }, + ) + } + return loader.LoadFiles(bufFiles) +} + +func getFilesFromFSRecursively(componentName string) ([]string, error) { + files := make([]string, 0) + + err := fs.WalkDir(FS, componentName, + func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + + if d.IsDir() { + return nil + } + files = append(files, path) + return nil + }, + ) + if err != nil { + return nil, err + } + return files, nil +} diff --git a/manifests/mainfest.go b/manifests/mainfest.go new file mode 100644 index 0000000..0983de6 --- /dev/null +++ b/manifests/mainfest.go @@ -0,0 +1,8 @@ +package manifests + +import "embed" + +// FS embeds the manifests +// +//go:embed virtualcluster/* +var FS embed.FS diff --git a/manifests/virtualcluster/nodes/Chart.yaml b/manifests/virtualcluster/nodes/Chart.yaml new file mode 100644 index 0000000..567ab84 --- /dev/null +++ b/manifests/virtualcluster/nodes/Chart.yaml @@ -0,0 +1,4 @@ +{ + "name": "virtualnodes", + "version": "0.0.1" +} diff --git a/manifests/virtualcluster/nodes/templates/clusterrole.yaml b/manifests/virtualcluster/nodes/templates/clusterrole.yaml new file mode 100644 index 0000000..a0da8a7 --- /dev/null +++ b/manifests/virtualcluster/nodes/templates/clusterrole.yaml @@ -0,0 +1,59 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ .Values.name }} +rules: + - apiGroups: + - "" + resources: + - events + verbs: + - create + - update + - patch + - watch + - list + - get + - apiGroups: + - "" + resources: + - nodes + verbs: + - watch + - list + - get + - apiGroups: + - "" + resources: + - nodes/status + verbs: + - update + - patch + - apiGroups: + - "" + resources: + - pods + verbs: + - watch + - list + - delete + - update + - patch + - apiGroups: + - "" + resources: + - pods/status + verbs: + - update + - patch + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - update + - patch + - watch + - list + - get diff --git a/manifests/virtualcluster/nodes/templates/clusterrolebinding.yaml b/manifests/virtualcluster/nodes/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..532f3d6 --- /dev/null +++ b/manifests/virtualcluster/nodes/templates/clusterrolebinding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ .Values.name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ .Values.name }} +subjects: + - kind: ServiceAccount + name: {{ .Values.name }} + namespace: {{ .Release.Namespace }} diff --git a/manifests/virtualcluster/nodes/templates/config.yaml b/manifests/virtualcluster/nodes/templates/config.yaml new file mode 100644 index 0000000..f04cb16 --- /dev/null +++ b/manifests/virtualcluster/nodes/templates/config.yaml @@ -0,0 +1,370 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + app: {{ .Values.name }} + name: {{ .Values.name }} + namespace: {{ .Release.Namespace }} +data: + # NOTE: https://github.com/helm/helm/issues/2798#issuecomment-470435015 + kwok-config.yaml: |-{{` + kind: Stage + apiVersion: kwok.x-k8s.io/v1alpha1 + metadata: + name: pod-create + spec: + resourceRef: + apiGroup: v1 + kind: Pod + selector: + matchExpressions: + - key: '.metadata.deletionTimestamp' + operator: 'DoesNotExist' + - key: '.status.podIP' + operator: 'DoesNotExist' + weight: 1 + delay: + durationMilliseconds: 1000 + jitterDurationMilliseconds: 5000 + next: + event: + type: Normal + reason: Created + message: Created container + statusTemplate: | + {{ $now := Now }} + + conditions: + {{ if .spec.initContainers }} + - lastProbeTime: null + lastTransitionTime: '{{ $now }}' + message: 'containers with incomplete status: [{{ range .spec.initContainers }} {{ .name }} {{ end }}]' + reason: ContainersNotInitialized + status: "False" + type: Initialized + {{ else }} + - lastProbeTime: null + lastTransitionTime: '{{ $now }}' + status: "True" + type: Initialized + {{ end }} + - lastProbeTime: null + lastTransitionTime: '{{ $now }}' + message: 'containers with unready status: [{{ range .spec.containers }} {{ .name }} {{ end }}]' + reason: ContainersNotReady + status: "False" + type: Ready + - lastProbeTime: null + lastTransitionTime: '{{ $now }}' + message: 'containers with unready status: [{{ range .spec.containers }} {{ .name }} {{ end }}]' + reason: ContainersNotReady + status: "False" + type: ContainersReady + {{ range .spec.readinessGates }} + - lastTransitionTime: {{ $now }} + status: "True" + type: {{ .conditionType }} + {{ end }} + + {{ if .spec.initContainers }} + initContainerStatuses: + {{ range .spec.initContainers }} + - image: {{ .image }} + name: {{ .name }} + ready: false + restartCount: 0 + started: false + state: + waiting: + reason: PodInitializing + {{ end }} + containerStatuses: + {{ range .spec.containers }} + - image: {{ .image }} + name: {{ .name }} + ready: false + restartCount: 0 + started: false + state: + waiting: + reason: PodInitializing + {{ end }} + {{ else }} + containerStatuses: + {{ range .spec.containers }} + - image: {{ .image }} + name: {{ .name }} + ready: false + restartCount: 0 + started: false + state: + waiting: + reason: ContainerCreating + {{ end }} + {{ end }} + + hostIP: {{ NodeIPWith .spec.nodeName }} + podIP: {{ PodIPWith .spec.nodeName ( or .spec.hostNetwork false ) ( or .metadata.uid "" ) ( or .metadata.name "" ) ( or .metadata.namespace "" ) }} + phase: Pending + --- + kind: Stage + apiVersion: kwok.x-k8s.io/v1alpha1 + metadata: + name: pod-init-container-running + spec: + resourceRef: + apiGroup: v1 + kind: Pod + selector: + matchExpressions: + - key: '.metadata.deletionTimestamp' + operator: 'DoesNotExist' + - key: '.status.phase' + operator: 'In' + values: + - 'Pending' + - key: '.status.conditions.[] | select( .type == "Initialized" ) | .status' + operator: 'NotIn' + values: + - 'True' + - key: '.status.initContainerStatuses.[].state.waiting.reason' + operator: 'Exists' + weight: 1 + delay: + durationMilliseconds: 1000 + jitterDurationMilliseconds: 5000 + next: + statusTemplate: | + {{ $now := Now }} + {{ $root := . }} + initContainerStatuses: + {{ range $index, $item := .spec.initContainers }} + {{ $origin := index $root.status.initContainerStatuses $index }} + - image: {{ $item.image }} + name: {{ $item.name }} + ready: true + restartCount: 0 + started: true + state: + running: + startedAt: '{{ $now }}' + {{ end }} + --- + kind: Stage + apiVersion: kwok.x-k8s.io/v1alpha1 + metadata: + name: pod-init-container-completed + spec: + resourceRef: + apiGroup: v1 + kind: Pod + selector: + matchExpressions: + - key: '.metadata.deletionTimestamp' + operator: 'DoesNotExist' + - key: '.status.phase' + operator: 'In' + values: + - 'Pending' + - key: '.status.conditions.[] | select( .type == "Initialized" ) | .status' + operator: 'NotIn' + values: + - 'True' + - key: '.status.initContainerStatuses.[].state.running.startedAt' + operator: 'Exists' + weight: 1 + delay: + durationMilliseconds: 1000 + jitterDurationMilliseconds: 5000 + next: + statusTemplate: | + {{ $now := Now }} + {{ $root := . }} + conditions: + - lastProbeTime: null + lastTransitionTime: '{{ $now }}' + status: "True" + type: Initialized + initContainerStatuses: + {{ range $index, $item := .spec.initContainers }} + {{ $origin := index $root.status.initContainerStatuses $index }} + - image: {{ $item.image }} + name: {{ $item.name }} + ready: true + restartCount: 0 + started: false + state: + terminated: + exitCode: 0 + finishedAt: '{{ $now }}' + reason: Completed + startedAt: '{{ $now }}' + {{ end }} + containerStatuses: + {{ range .spec.containers }} + - image: {{ .image }} + name: {{ .name }} + ready: false + restartCount: 0 + started: false + state: + waiting: + reason: ContainerCreating + {{ end }} + --- + kind: Stage + apiVersion: kwok.x-k8s.io/v1alpha1 + metadata: + name: pod-ready + spec: + resourceRef: + apiGroup: v1 + kind: Pod + selector: + matchExpressions: + - key: '.metadata.deletionTimestamp' + operator: 'DoesNotExist' + - key: '.status.phase' + operator: 'In' + values: + - 'Pending' + - key: '.status.conditions.[] | select( .type == "Initialized" ) | .status' + operator: 'In' + values: + - 'True' + - key: '.status.conditions.[] | select( .type == "ContainersReady" ) | .status' + operator: 'NotIn' + values: + - 'True' + weight: 1 + delay: + durationMilliseconds: 1000 + jitterDurationMilliseconds: 5000 + next: + delete: false + statusTemplate: | + {{ $now := Now }} + {{ $root := . }} + conditions: + - lastProbeTime: null + lastTransitionTime: '{{ $now }}' + message: '' + reason: '' + status: "True" + type: Ready + - lastProbeTime: null + lastTransitionTime: '{{ $now }}' + message: '' + reason: '' + status: "True" + type: ContainersReady + containerStatuses: + {{ range $index, $item := .spec.containers }} + {{ $origin := index $root.status.containerStatuses $index }} + - image: {{ $item.image }} + name: {{ $item.name }} + ready: true + restartCount: 0 + started: true + state: + running: + startedAt: '{{ $now }}' + {{ end }} + phase: Running + --- + kind: Stage + apiVersion: kwok.x-k8s.io/v1alpha1 + metadata: + name: pod-complete + spec: + resourceRef: + apiGroup: v1 + kind: Pod + selector: + matchExpressions: + - key: '.metadata.deletionTimestamp' + operator: 'DoesNotExist' + - key: '.status.phase' + operator: 'In' + values: + - 'Running' + - key: '.status.conditions.[] | select( .type == "Ready" ) | .status' + operator: 'In' + values: + - 'True' + weight: 1 + delay: + durationMilliseconds: 1000 + jitterDurationMilliseconds: 5000 + next: + delete: false + statusTemplate: | + {{ $now := Now }} + {{ $root := . }} + containerStatuses: + {{ range $index, $item := .spec.containers }} + {{ $origin := index $root.status.containerStatuses $index }} + - image: {{ $item.image }} + name: {{ $item.name }} + ready: true + restartCount: 0 + started: false + state: + terminated: + exitCode: 0 + finishedAt: '{{ $now }}' + reason: Completed + startedAt: '{{ $now }}' + {{ end }} + phase: Succeeded + --- + kind: Stage + apiVersion: kwok.x-k8s.io/v1alpha1 + metadata: + name: pod-remove-finalizer + spec: + resourceRef: + apiGroup: v1 + kind: Pod + selector: + matchExpressions: + - key: '.metadata.deletionTimestamp' + operator: 'Exists' + - key: '.metadata.finalizers.[]' + operator: 'In' + values: + - 'kwok.x-k8s.io/fake' + weight: 1 + delay: + durationMilliseconds: 1000 + jitterDurationMilliseconds: 5000 + next: + finalizers: + remove: + - value: 'kwok.x-k8s.io/fake' + event: + type: Normal + reason: Killing + message: Stopping container + --- + kind: Stage + apiVersion: kwok.x-k8s.io/v1alpha1 + metadata: + name: pod-delete + spec: + resourceRef: + apiGroup: v1 + kind: Pod + selector: + matchExpressions: + - key: '.metadata.deletionTimestamp' + operator: 'Exists' + - key: '.metadata.finalizers' + operator: 'DoesNotExist' + weight: 1 + delay: + durationMilliseconds: 1000 + jitterDurationFrom: + expressionFrom: '.metadata.deletionTimestamp' + next: + delete: true`}} diff --git a/manifests/virtualcluster/nodes/templates/nodes.tpl b/manifests/virtualcluster/nodes/templates/nodes.tpl new file mode 100644 index 0000000..c8e290d --- /dev/null +++ b/manifests/virtualcluster/nodes/templates/nodes.tpl @@ -0,0 +1,50 @@ +{{- $name := .Values.name }} +{{- $cpu := .Values.cpu }} +{{- $memory := .Values.memory }} +{{- $labels := .Values.nodeLabels }} +{{- range $index := (untilStep 0 (int .Values.replicas) 1) }} +apiVersion: v1 +kind: Node +metadata: + annotations: + node.alpha.kubernetes.io/ttl: "0" + kwok.x-k8s.io/node: fake + kwok.x-k8s.io/manage: {{ $name }}-{{ $index }} + labels: + beta.kubernetes.io/arch: amd64 + beta.kubernetes.io/os: linux + kubernetes.io/arch: amd64 + kubernetes.io/hostname: {{ $name }}-{{ $index }} + kubernetes.io/os: linux + kubernetes.io/role: agent + node-role.kubernetes.io/agent: "" + node.kubernetes.io/exclude-from-external-load-balancers: "true" + kubernetes.azure.com/managed: "false" + type: kperf-virtualnodes + alpha.kperf.io/nodepool: {{ $name }} +{{- range $key, $value := $labels }} + {{ $key }}: {{ $value }} +{{- end }} + name: {{ $name }}-{{ $index }} +spec: + taints: # Avoid scheduling actual running pods to fake Node + - effect: NoSchedule + key: kperf.io/nodepool + value: fake +status: + allocatable: + cpu: {{ $cpu }} + memory: {{ $memory }}Gi + pods: 110 + capacity: + cpu: {{ $cpu }} + memory: {{ $memory }}Gi + pods: 110 + nodeInfo: + architecture: amd64 + containerRuntimeVersion: "kwok" + kubeProxyVersion: fake + kubeletVersion: fake + operatingSystem: linux +--- +{{- end}} diff --git a/manifests/virtualcluster/nodes/templates/serviceaccount.yaml b/manifests/virtualcluster/nodes/templates/serviceaccount.yaml new file mode 100644 index 0000000..5c20ddc --- /dev/null +++ b/manifests/virtualcluster/nodes/templates/serviceaccount.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.name }} + namespace: {{ .Release.Namespace }} diff --git a/manifests/virtualcluster/nodes/templates/statefulsets.tpl b/manifests/virtualcluster/nodes/templates/statefulsets.tpl new file mode 100644 index 0000000..882e80f --- /dev/null +++ b/manifests/virtualcluster/nodes/templates/statefulsets.tpl @@ -0,0 +1,70 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ .Values.name }} + namespace: {{ .Release.Namespace }} +spec: + selector: + matchLabels: + app: {{ .Values.name }} + replicas: {{ .Values.replicas }} + podManagementPolicy: Parallel + template: + metadata: + labels: + app: {{ .Values.name }} + spec: +{{- if .Values.controllerNodeSelectors }} + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + {{- range $key, $values := .Values.controllerNodeSelectors }} + - key: "{{ $key }}" + operator: In + values: + {{- range $values }} + - {{ . }} + {{- end }} + {{- end }} +{{- end }} + terminationGracePeriodSeconds: 1 + containers: + - args: + - --config=/data/kwok-config.yaml + - --manage-all-nodes=false + - --manage-single-node=$(POD_NAME) # act as virtualnode + - --disregard-status-with-annotation-selector=kwok.x-k8s.io/status=custom + - --disregard-status-with-label-selector= + - --node-ip=$(POD_IP) + - --node-port=10247 + - --cidr=10.0.0.1/24 + - --node-lease-duration-seconds=40 + env: + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + image: registry.k8s.io/kwok/kwok:v0.4.0 + imagePullPolicy: IfNotPresent + name: kwok-controller + volumeMounts: + - name: kwok-config + mountPath: /data/ + resources: + limits: + cpu: "500m" + requests: + cpu: "200m" + restartPolicy: Always + serviceAccount: {{ .Values.name }} + serviceAccountName: {{ .Values.name }} + volumes: + - name: kwok-config + configMap: + name: {{ .Values.name }} diff --git a/manifests/virtualcluster/nodes/values.yaml b/manifests/virtualcluster/nodes/values.yaml new file mode 100644 index 0000000..fa21288 --- /dev/null +++ b/manifests/virtualcluster/nodes/values.yaml @@ -0,0 +1,6 @@ +name: "" +controllerNodeSelectors: {} +replicas: 0 +nodeLabels: {} +cpu: 0 +memory: 0