diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index a56bf9d89..6ceb4e3cc 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -100,6 +100,7 @@ jobs: helm cm-push --force --version="$RELEASE_VERSION" charts/k3s/ chartmuseum helm cm-push --force --version="$RELEASE_VERSION" charts/k0s/ chartmuseum helm cm-push --force --version="$RELEASE_VERSION" charts/k8s/ chartmuseum + helm cm-push --force --version="$RELEASE_VERSION" charts/eks/ chartmuseum env: CHART_MUSEUM_URL: "https://charts.loft.sh/" CHART_MUSEUM_USER: ${{ secrets.CHART_MUSEUM_USER }} diff --git a/charts/eks/.helmignore b/charts/eks/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/charts/eks/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/charts/eks/Chart.yaml b/charts/eks/Chart.yaml new file mode 100644 index 000000000..f81a06fb9 --- /dev/null +++ b/charts/eks/Chart.yaml @@ -0,0 +1,15 @@ +apiVersion: v2 +name: vcluster-eks +description: vcluster - Virtual Kubernetes Clusters (k8s) + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +version: 0.0.1 # version is auto-generated by release pipeline diff --git a/charts/eks/templates/NOTES.txt b/charts/eks/templates/NOTES.txt new file mode 100644 index 000000000..c32a7790f --- /dev/null +++ b/charts/eks/templates/NOTES.txt @@ -0,0 +1,8 @@ +Thank you for installing {{ .Chart.Name }}. + +Your release is named {{ .Release.Name }}. + +To learn more about the release, try: + + $ helm status {{ .Release.Name }} + $ helm get all {{ .Release.Name }} \ No newline at end of file diff --git a/charts/eks/templates/_helpers.tpl b/charts/eks/templates/_helpers.tpl new file mode 100644 index 000000000..fe19f0d60 --- /dev/null +++ b/charts/eks/templates/_helpers.tpl @@ -0,0 +1,59 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "vcluster.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "vcluster.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{- define "vcluster.clusterRoleName" -}} +{{- printf "vc-%s-v-%s" .Release.Name .Release.Namespace | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "vcluster.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "vcluster.labels" -}} +app.kubernetes.io/name: {{ include "vcluster.name" . }} +helm.sh/chart: {{ include "vcluster.chart" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- else }} +app.kubernetes.io/version: {{ .Chart.Version | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{/* +Get +*/}} +{{- $}} +{{- define "vcluster.admin.accessKey" -}} +{{- now | unixEpoch | toString | trunc 8 | sha256sum -}} +{{- end -}} \ No newline at end of file diff --git a/charts/eks/templates/api-deployment.yaml b/charts/eks/templates/api-deployment.yaml new file mode 100644 index 000000000..bac786d9b --- /dev/null +++ b/charts/eks/templates/api-deployment.yaml @@ -0,0 +1,137 @@ +{{- if not .Values.api.disabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }}-api + namespace: {{ .Release.Namespace }} + labels: + app: vcluster-api + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +{{- if .Values.api.labels }} +{{ toYaml .Values.api.labels | indent 4 }} +{{- end }} + {{- if .Values.api.annotations }} + annotations: +{{ toYaml .Values.api.annotations | indent 4 }} + {{- end }} +spec: + replicas: {{ .Values.api.replicas }} + strategy: + rollingUpdate: + maxSurge: 1 + {{- if (eq (int .Values.api.replicas) 1) }} + maxUnavailable: 0 + {{- else }} + maxUnavailable: 1 + {{- end }} + type: RollingUpdate + selector: + matchLabels: + app: vcluster-api + release: {{ .Release.Name }} + template: + metadata: + labels: + app: vcluster-api + release: {{ .Release.Name }} + spec: + terminationGracePeriodSeconds: 10 + {{- if .Values.api.affinity }} + affinity: +{{ toYaml .Values.api.affinity | indent 8 }} + {{- end }} + {{- if .Values.api.topologySpreadConstraints }} + topologySpreadConstraints: +{{ toYaml .Values.api.topologySpreadConstraints | indent 8 }} + {{- end }} + nodeSelector: +{{ toYaml .Values.api.nodeSelector | indent 8 }} + affinity: +{{ toYaml .Values.api.affinity | indent 8 }} + tolerations: +{{ toYaml .Values.api.tolerations | indent 8 }} + automountServiceAccountToken: false + volumes: + - name: certs + secret: + secretName: {{ .Release.Name }}-certs + {{- if .Values.api.volumes }} +{{ toYaml .Values.api.volumes | indent 8 }} + {{- end }} + containers: + - name: kube-apiserver + image: "{{ .Values.defaultImageRegistry }}{{ .Values.api.image }}" + command: + - kube-apiserver + - '--advertise-address=0.0.0.0' + - '--allow-privileged=true' + - '--audit-log-maxage=30' + - '--audit-log-maxbackup=10' + - '--audit-log-maxsize=512' + - '--cloud-provider=external' + - '--authorization-mode=Node,RBAC' + - '--client-ca-file=/run/config/pki/ca.crt' + - '--enable-admission-plugins=NodeRestriction' + - '--enable-bootstrap-token-auth=true' + - '--etcd-cafile=/run/config/pki/etcd-ca.crt' + - '--etcd-certfile=/run/config/pki/apiserver-etcd-client.crt' + - '--etcd-keyfile=/run/config/pki/apiserver-etcd-client.key' + - '--etcd-servers=https://{{ .Release.Name }}-etcd:2379' + - '--insecure-port=0' + - '--kubelet-client-certificate=/run/config/pki/apiserver-kubelet-client.crt' + - '--kubelet-client-key=/run/config/pki/apiserver-kubelet-client.key' + - '--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname' + - '--profiling=false' + - '--proxy-client-cert-file=/run/config/pki/front-proxy-client.crt' + - '--proxy-client-key-file=/run/config/pki/front-proxy-client.key' + - '--requestheader-allowed-names=front-proxy-client' + - '--requestheader-client-ca-file=/run/config/pki/front-proxy-ca.crt' + - '--requestheader-extra-headers-prefix=X-Remote-Extra-' + - '--requestheader-group-headers=X-Remote-Group' + - '--requestheader-username-headers=X-Remote-User' + - '--secure-port=6443' + - '--service-account-issuer=https://kubernetes.default.svc.cluster.local' + - '--service-account-key-file=/run/config/pki/sa.pub' + - '--service-account-signing-key-file=/run/config/pki/sa.key' + - '--service-cluster-ip-range={{ .Values.serviceCIDR }}' + - '--tls-cert-file=/run/config/pki/apiserver.crt' + - '--tls-private-key-file=/run/config/pki/apiserver.key' + - '--watch-cache=false' + {{- range $f := .Values.api.extraArgs }} + - {{ $f | quote }} + {{- end }} + livenessProbe: + httpGet: + path: /livez + port: 6443 + scheme: HTTPS + initialDelaySeconds: 10 + timeoutSeconds: 15 + periodSeconds: 10 + successThreshold: 1 + failureThreshold: 8 + readinessProbe: + httpGet: + path: /readyz + port: 6443 + scheme: HTTPS + timeoutSeconds: 15 + periodSeconds: 1 + successThreshold: 1 + failureThreshold: 3 + securityContext: +{{ toYaml .Values.api.securityContext | indent 10 }} + env: +{{ toYaml .Values.api.env | indent 10 }} + volumeMounts: + - mountPath: /run/config/pki + name: certs + readOnly: true + {{- if .Values.api.volumeMounts }} +{{ toYaml .Values.api.volumeMounts | indent 10 }} + {{- end }} + resources: +{{ toYaml .Values.api.resources | indent 10 }} +{{- end }} \ No newline at end of file diff --git a/charts/eks/templates/api-service.yaml b/charts/eks/templates/api-service.yaml new file mode 100644 index 000000000..48ebed294 --- /dev/null +++ b/charts/eks/templates/api-service.yaml @@ -0,0 +1,22 @@ +{{- if not .Values.api.disabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-api + namespace: {{ .Release.Namespace }} + labels: + app: vcluster-api + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + type: ClusterIP + ports: + - name: https + port: 443 + targetPort: 6443 + protocol: TCP + selector: + app: vcluster-api + release: {{ .Release.Name }} +{{- end }} \ No newline at end of file diff --git a/charts/eks/templates/controller-deployment.yaml b/charts/eks/templates/controller-deployment.yaml new file mode 100644 index 000000000..15dd8ae9f --- /dev/null +++ b/charts/eks/templates/controller-deployment.yaml @@ -0,0 +1,132 @@ +{{- if not .Values.controller.disabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }}-controller + namespace: {{ .Release.Namespace }} + labels: + app: vcluster-controller + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +{{- if .Values.controller.labels }} +{{ toYaml .Values.controller.labels | indent 4 }} +{{- end }} + {{- if .Values.controller.annotations }} + annotations: +{{ toYaml .Values.controller.annotations | indent 4 }} + {{- end }} +spec: + replicas: {{ .Values.controller.replicas }} + strategy: + rollingUpdate: + maxSurge: 1 + {{- if (eq (int .Values.controller.replicas) 1) }} + maxUnavailable: 0 + {{- else }} + maxUnavailable: 1 + {{- end }} + type: RollingUpdate + selector: + matchLabels: + app: vcluster-controller + release: {{ .Release.Name }} + template: + metadata: + labels: + app: vcluster-controller + release: {{ .Release.Name }} + spec: + terminationGracePeriodSeconds: 10 + {{- if .Values.controller.affinity }} + affinity: +{{ toYaml .Values.controller.affinity | indent 8 }} + {{- end }} + {{- if .Values.controller.topologySpreadConstraints }} + topologySpreadConstraints: +{{ toYaml .Values.controller.topologySpreadConstraints | indent 8 }} + {{- end }} + nodeSelector: +{{ toYaml .Values.controller.nodeSelector | indent 8 }} + affinity: +{{ toYaml .Values.controller.affinity | indent 8 }} + tolerations: +{{ toYaml .Values.controller.tolerations | indent 8 }} + automountServiceAccountToken: false + volumes: + - name: certs + secret: + secretName: {{ .Release.Name }}-certs + {{- if .Values.controller.volumes }} +{{ toYaml .Values.controller.volumes | indent 8 }} + {{- end }} + containers: + - name: kube-controller-manager + image: "{{ .Values.defaultImageRegistry }}{{ .Values.controller.image }}" + command: + - kube-controller-manager + - '--authentication-kubeconfig=/run/config/pki/controller-manager.conf' + - '--authorization-kubeconfig=/run/config/pki/controller-manager.conf' + - '--bind-address=0.0.0.0' + - '--client-ca-file=/run/config/pki/ca.crt' + - '--cluster-name=kubernetes' + - '--cluster-signing-cert-file=/run/config/pki/ca.crt' + - '--cluster-signing-key-file=/run/config/pki/ca.key' + - '--controllers=*,-nodeipam,-nodelifecycle,-persistentvolume-binder,-attachdetach,-persistentvolume-expander,-cloud-node-lifecycle' + - '--horizontal-pod-autoscaler-sync-period=60s' + - '--kubeconfig=/run/config/pki/controller-manager.conf' + - '--port=0' + - '--profiling=false' + - '--service-cluster-ip-range={{ .Values.serviceCIDR }}' + - '--tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256' + - '--use-service-account-credentials=true' + {{- if .Values.enableHA }} + - '--leader-elect=true' + {{- else }} + - '--leader-elect=false' + {{- end }} + - '--node-monitor-grace-period=180s' + - '--node-monitor-period=30s' + - '--port=0' + - '--pvclaimbinder-sync-period=60s' + - '--requestheader-client-ca-file=/run/config/pki/front-proxy-ca.crt' + - '--root-ca-file=/run/config/pki/ca.crt' + - '--service-account-private-key-file=/run/config/pki/sa.key' + - '--use-service-account-credentials=true' + {{- range $f := .Values.controller.extraArgs }} + - {{ $f | quote }} + {{- end }} + livenessProbe: + httpGet: + path: /healthz + port: 10257 + scheme: HTTPS + initialDelaySeconds: 10 + timeoutSeconds: 15 + periodSeconds: 10 + successThreshold: 1 + failureThreshold: 8 + startupProbe: + httpGet: + path: /healthz + port: 10257 + scheme: HTTPS + initialDelaySeconds: 10 + timeoutSeconds: 15 + periodSeconds: 10 + successThreshold: 1 + failureThreshold: 24 + securityContext: +{{ toYaml .Values.controller.securityContext | indent 10 }} + env: +{{ toYaml .Values.controller.env | indent 10 }} + volumeMounts: + - mountPath: /run/config/pki + name: certs + readOnly: true + {{- if .Values.controller.volumeMounts }} +{{ toYaml .Values.controller.volumeMounts | indent 10 }} + {{- end }} + resources: +{{ toYaml .Values.controller.resources | indent 10 }} +{{- end }} \ No newline at end of file diff --git a/charts/eks/templates/coredns.yaml b/charts/eks/templates/coredns.yaml new file mode 100644 index 000000000..3216ac92b --- /dev/null +++ b/charts/eks/templates/coredns.yaml @@ -0,0 +1,226 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: custom-deployments +data: + coredns.yaml: |- + apiVersion: v1 + kind: ServiceAccount + metadata: + name: coredns + namespace: kube-system + --- + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + labels: + kubernetes.io/bootstrapping: rbac-defaults + name: system:coredns + rules: + - apiGroups: + - "" + resources: + - endpoints + - services + - pods + - namespaces + verbs: + - list + - watch + - apiGroups: + - discovery.k8s.io + resources: + - endpointslices + verbs: + - list + - watch + --- + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + annotations: + rbac.authorization.kubernetes.io/autoupdate: "true" + labels: + kubernetes.io/bootstrapping: rbac-defaults + name: system:coredns + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:coredns + subjects: + - kind: ServiceAccount + name: coredns + namespace: kube-system + --- + apiVersion: v1 + kind: ConfigMap + metadata: + name: coredns + namespace: kube-system + data: + Corefile: | + .:1053 { + {{.LOG_IN_DEBUG}} + errors + health + ready + kubernetes cluster.local in-addr.arpa ip6.arpa { + pods insecure + fallthrough in-addr.arpa ip6.arpa + } + hosts /etc/coredns/NodeHosts { + ttl 60 + reload 15s + fallthrough + } + prometheus :9153 + forward . /etc/resolv.conf + cache 30 + loop + reload + loadbalance + } + import /etc/coredns/custom/*.server + NodeHosts: "" + --- + apiVersion: apps/v1 + kind: Deployment + metadata: + name: coredns + namespace: kube-system + labels: + k8s-app: kube-dns + kubernetes.io/name: "CoreDNS" + spec: + replicas: 1 + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + selector: + matchLabels: + k8s-app: kube-dns + template: + metadata: + labels: + k8s-app: kube-dns + spec: + priorityClassName: "system-cluster-critical" + serviceAccountName: coredns + tolerations: + - key: "CriticalAddonsOnly" + operator: "Exists" + - key: "node-role.kubernetes.io/control-plane" + operator: "Exists" + effect: "NoSchedule" + - key: "node-role.kubernetes.io/master" + operator: "Exists" + effect: "NoSchedule" + nodeSelector: + kubernetes.io/os: linux + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: DoNotSchedule + labelSelector: + matchLabels: + k8s-app: kube-dns + containers: + - name: coredns + image: "{{ .Values.defaultImageRegistry }}{{ .Values.coredns.image }}" + imagePullPolicy: IfNotPresent + resources: + limits: + cpu: 1000m + memory: 170Mi + requests: + cpu: 100m + memory: 70Mi + args: [ "-conf", "/etc/coredns/Corefile" ] + volumeMounts: + - name: config-volume + mountPath: /etc/coredns + readOnly: true + - name: custom-config-volume + mountPath: /etc/coredns/custom + readOnly: true + ports: + - containerPort: 1053 + name: dns + protocol: UDP + - containerPort: 1053 + name: dns-tcp + protocol: TCP + - containerPort: 9153 + name: metrics + protocol: TCP + securityContext: + runAsUser: {{.RUN_AS_USER}} + runAsNonRoot: {{.RUN_AS_NON_ROOT}} + allowPrivilegeEscalation: false + capabilities: + drop: + - all + readOnlyRootFilesystem: true + livenessProbe: + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 60 + periodSeconds: 10 + timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /ready + port: 8181 + scheme: HTTP + initialDelaySeconds: 0 + periodSeconds: 2 + timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 3 + dnsPolicy: Default + volumes: + - name: config-volume + configMap: + name: coredns + items: + - key: Corefile + path: Corefile + - key: NodeHosts + path: NodeHosts + - name: custom-config-volume + configMap: + name: coredns-custom + optional: true + --- + apiVersion: v1 + kind: Service + metadata: + name: kube-dns + namespace: kube-system + annotations: + prometheus.io/port: "9153" + prometheus.io/scrape: "true" + labels: + k8s-app: kube-dns + kubernetes.io/cluster-service: "true" + kubernetes.io/name: "CoreDNS" + spec: + selector: + k8s-app: kube-dns + ports: + - name: dns + port: 53 + targetPort: 1053 + protocol: UDP + - name: dns-tcp + port: 53 + targetPort: 1053 + protocol: TCP + - name: metrics + port: 9153 + protocol: TCP \ No newline at end of file diff --git a/charts/eks/templates/etcd-service.yaml b/charts/eks/templates/etcd-service.yaml new file mode 100644 index 000000000..650487c6e --- /dev/null +++ b/charts/eks/templates/etcd-service.yaml @@ -0,0 +1,26 @@ +{{- if not .Values.etcd.disabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-etcd + namespace: {{ .Release.Namespace }} + labels: + app: vcluster-etcd + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + type: ClusterIP + ports: + - name: etcd + port: 2379 + targetPort: 2379 + protocol: TCP + - name: peer + port: 2380 + targetPort: 2380 + protocol: TCP + selector: + app: vcluster-etcd + release: {{ .Release.Name }} + {{- end }} \ No newline at end of file diff --git a/charts/eks/templates/etcd-statefulset-service.yaml b/charts/eks/templates/etcd-statefulset-service.yaml new file mode 100644 index 000000000..648bb8213 --- /dev/null +++ b/charts/eks/templates/etcd-statefulset-service.yaml @@ -0,0 +1,27 @@ +{{- if not .Values.etcd.disabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-etcd-headless + namespace: {{ .Release.Namespace }} + labels: + app: vcluster-etcd + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + publishNotReadyAddresses: true + ports: + - name: etcd + port: 2379 + targetPort: 2379 + protocol: TCP + - name: peer + port: 2380 + targetPort: 2380 + protocol: TCP + clusterIP: None + selector: + app: vcluster-etcd + release: "{{ .Release.Name }}" +{{- end }} \ No newline at end of file diff --git a/charts/eks/templates/etcd-statefulset.yaml b/charts/eks/templates/etcd-statefulset.yaml new file mode 100644 index 000000000..0d3e0adac --- /dev/null +++ b/charts/eks/templates/etcd-statefulset.yaml @@ -0,0 +1,146 @@ +{{- if not .Values.etcd.disabled }} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ .Release.Name }}-etcd + namespace: {{ .Release.Namespace }} + labels: + app: vcluster-etcd + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +{{- if .Values.etcd.labels }} +{{ toYaml .Values.etcd.labels | indent 4 }} +{{- end }} + {{- if .Values.etcd.annotations }} + annotations: +{{ toYaml .Values.etcd.annotations | indent 4 }} + {{- end }} +spec: + serviceName: {{ .Release.Name }}-etcd-headless + replicas: {{ .Values.etcd.replicas }} + podManagementPolicy: Parallel + selector: + matchLabels: + app: vcluster-etcd + release: {{ .Release.Name }} + {{- if .Values.etcd.storage.persistence }} + {{- if not .Values.etcd.storage.volumeClaimTemplates }} + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: [ "ReadWriteOnce" ] + storageClassName: {{ .Values.etcd.storage.className }} + resources: + requests: + storage: {{ .Values.etcd.storage.size }} + {{- else }} + volumeClaimTemplates: +{{ toYaml .Values.etcd.volumeClaimTemplates | indent 4 }} + {{- end }} + {{- end }} + template: + metadata: + labels: + app: vcluster-etcd + release: {{ .Release.Name }} + spec: + terminationGracePeriodSeconds: 10 + {{- if .Values.etcd.affinity }} + affinity: +{{ toYaml .Values.etcd.affinity | indent 8 }} + {{- end }} + {{- if .Values.etcd.topologySpreadConstraints }} + topologySpreadConstraints: +{{ toYaml .Values.etcd.topologySpreadConstraints | indent 8 }} + {{- end }} + nodeSelector: +{{ toYaml .Values.etcd.nodeSelector | indent 8 }} + affinity: +{{ toYaml .Values.etcd.affinity | indent 8 }} + tolerations: +{{ toYaml .Values.etcd.tolerations | indent 8 }} + automountServiceAccountToken: false + volumes: + - name: certs + secret: + secretName: {{ .Release.Name }}-certs + {{- if .Values.volumes }} +{{ toYaml .Values.etcd.volumes | indent 8 }} + {{- end }} + {{- if not .Values.etcd.storage.persistence }} + - name: data + emptyDir: {} + {{- end }} + containers: + - name: etcd + image: "{{ .Values.defaultImageRegistry }}{{ .Values.etcd.image }}" + command: + - etcd + - '--cert-file=/run/config/pki/etcd-server.crt' + - '--client-cert-auth=true' + - '--data-dir=/var/lib/etcd' + - '--advertise-client-urls=https://$(NAME).{{ .Release.Name }}-etcd-headless.{{ .Release.Namespace }}:2379' + - '--initial-advertise-peer-urls=https://$(NAME).{{ .Release.Name }}-etcd-headless.{{ .Release.Namespace }}:2380' + {{- $releaseName := .Release.Name -}} + {{- $releaseNamespace := .Release.Namespace }} + - '--initial-cluster={{ range $index := untilStep 0 (int .Values.etcd.replicas) 1 }}{{ if (ne (int $index) 0) }},{{ end }}{{ $releaseName }}-etcd-{{ $index }}=https://{{ $releaseName }}-etcd-{{ $index }}.{{ $releaseName }}-etcd-headless.{{ $releaseNamespace }}:2380{{ end }}' + - '--initial-cluster-token={{ .Release.Name }}' + - '--initial-cluster-state=new' + - '--listen-client-urls=https://0.0.0.0:2379' + - '--listen-metrics-urls=http://0.0.0.0:2381' + - '--listen-peer-urls=https://0.0.0.0:2380' + - '--key-file=/run/config/pki/etcd-server.key' + - '--name=$(NAME)' + - '--peer-cert-file=/run/config/pki/etcd-peer.crt' + - '--peer-client-cert-auth=true' + - '--peer-key-file=/run/config/pki/etcd-peer.key' + - '--peer-trusted-ca-file=/run/config/pki/etcd-ca.crt' + - '--snapshot-count=10000' + - '--trusted-ca-file=/run/config/pki/etcd-ca.crt' + {{- range $f := .Values.etcd.extraArgs }} + - {{ $f | quote }} + {{- end }} + securityContext: +{{ toYaml .Values.etcd.securityContext | indent 10 }} + env: + - name: NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + {{- if .Values.etcd.env }} +{{ toYaml .Values.etcd.env | indent 10 }} + {{- end }} + volumeMounts: + - name: data + mountPath: /var/lib/etcd + - mountPath: /run/config/pki + name: certs + readOnly: true + {{- if .Values.etcd.volumeMounts }} +{{ toYaml .Values.etcd.volumeMounts | indent 10 }} + {{- end }} + resources: +{{ toYaml .Values.etcd.resources | indent 10 }} +{{- end }} + livenessProbe: + httpGet: + path: /health + port: 2381 + scheme: HTTP + initialDelaySeconds: 10 + timeoutSeconds: 15 + periodSeconds: 10 + successThreshold: 1 + failureThreshold: 8 + startupProbe: + httpGet: + path: /health + port: 2381 + scheme: HTTP + initialDelaySeconds: 10 + timeoutSeconds: 15 + periodSeconds: 10 + successThreshold: 1 + failureThreshold: 24 diff --git a/charts/eks/templates/ingress.yaml b/charts/eks/templates/ingress.yaml new file mode 100644 index 000000000..0705358bb --- /dev/null +++ b/charts/eks/templates/ingress.yaml @@ -0,0 +1,26 @@ +{{- if .Values.ingress.enabled }} +apiVersion: {{ .Values.ingress.apiVersion }} +kind: Ingress +metadata: + {{- if .Values.ingress.annotations }} + annotations: + {{- toYaml .Values.ingress.annotations | nindent 4 }} + {{- end }} + name: {{ .Release.Name }} + namespace: {{ .Release.Namespace }} +spec: + {{- if .Values.ingress.ingressClassName }} + ingressClassName: {{ .Values.ingress.ingressClassName | quote }} + {{- end }} + rules: + - host: {{ .Values.ingress.host | quote }} + http: + paths: + - backend: + service: + name: {{ .Release.Name }} + port: + name: https + path: / + pathType: {{ .Values.ingress.pathType }} +{{- end }} diff --git a/charts/eks/templates/pre-install-hook-job.yaml b/charts/eks/templates/pre-install-hook-job.yaml new file mode 100644 index 000000000..f7a4314d1 --- /dev/null +++ b/charts/eks/templates/pre-install-hook-job.yaml @@ -0,0 +1,46 @@ +{{- if .Values.preInstall.enabled }} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ .Release.Name }}-pre-install + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": pre-install + "helm.sh/hook-weight": "3" + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded +spec: + backoffLimit: 3 + template: + metadata: + name: {{ .Release.Name }}-pre-install + spec: + serviceAccountName: {{ .Release.Name }}-pre-install + restartPolicy: OnFailure + nodeSelector: +{{ toYaml .Values.preInstall.nodeSelector | indent 8 }} + affinity: +{{ toYaml .Values.preInstall.affinity | indent 8 }} + tolerations: +{{ toYaml .Values.preInstall.tolerations | indent 8 }} + containers: + - name: certs + {{- if .Values.syncer.image }} + image: "{{ .Values.defaultImageRegistry }}{{ .Values.syncer.image }}" + {{- else }} + image: "{{ .Values.defaultImageRegistry }}loftsh/vcluster:{{ .Chart.Version }}" + {{- end }} + imagePullPolicy: IfNotPresent + securityContext: + runAsUser: 0 + command: + - /vcluster + - certs + args: + - --prefix={{ .Release.Name }} + - --etcd-replicas={{ .Values.etcd.replicas }} + {{- if .Values.serviceCIDR }} + - --service-cidr={{ .Values.serviceCIDR }} + {{- end }} + resources: +{{ toYaml .Values.etcd.resources | indent 12 }} +{{- end }} \ No newline at end of file diff --git a/charts/eks/templates/pre-install-hook-role.yaml b/charts/eks/templates/pre-install-hook-role.yaml new file mode 100644 index 000000000..2bc7869bc --- /dev/null +++ b/charts/eks/templates/pre-install-hook-role.yaml @@ -0,0 +1,15 @@ +{{- if .Values.preInstall.enabled }} +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Release.Name }}-pre-install + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": pre-install + "helm.sh/hook-weight": "1" + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded,hook-failed +rules: + - apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "get", "list"] +{{- end }} \ No newline at end of file diff --git a/charts/eks/templates/pre-install-hook-rolebinding.yaml b/charts/eks/templates/pre-install-hook-rolebinding.yaml new file mode 100644 index 000000000..a96015ada --- /dev/null +++ b/charts/eks/templates/pre-install-hook-rolebinding.yaml @@ -0,0 +1,19 @@ +{{- if .Values.preInstall.enabled }} +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Release.Name }}-pre-install + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": pre-install + "helm.sh/hook-weight": "1" + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded,hook-failed +subjects: + - kind: ServiceAccount + name: {{ .Release.Name }}-pre-install + namespace: {{ .Release.Namespace }} +roleRef: + kind: Role + name: {{ .Release.Name }}-pre-install + apiGroup: rbac.authorization.k8s.io +{{- end }} \ No newline at end of file diff --git a/charts/eks/templates/pre-install-hook-serviceaccount.yaml b/charts/eks/templates/pre-install-hook-serviceaccount.yaml new file mode 100644 index 000000000..dd1fe742b --- /dev/null +++ b/charts/eks/templates/pre-install-hook-serviceaccount.yaml @@ -0,0 +1,11 @@ +{{- if .Values.preInstall.enabled }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Release.Name }}-pre-install + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": pre-install + "helm.sh/hook-weight": "1" + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded,hook-failed +{{- end }} \ No newline at end of file diff --git a/charts/eks/templates/rbac/clusterrole.yaml b/charts/eks/templates/rbac/clusterrole.yaml new file mode 100644 index 000000000..c4d2a58c6 --- /dev/null +++ b/charts/eks/templates/rbac/clusterrole.yaml @@ -0,0 +1,44 @@ +{{- if .Values.rbac.clusterRole.create }} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ template "vcluster.clusterRoleName" . }} + labels: + app: vcluster + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +rules: + - apiGroups: [""] + resources: ["nodes", "nodes/status"] + verbs: ["get", "watch", "list", "update", "patch"] + - apiGroups: [""] + resources: ["pods", "nodes/proxy", "nodes/metrics", "nodes/stats"] + verbs: ["get", "watch", "list"] + - apiGroups: [""] + resources: ["persistentvolumes"] + verbs: ["create", "delete", "patch", "update", "get", "watch", "list"] + - apiGroups: ["storage.k8s.io"] + resources: ["storageclasses"] + verbs: ["get", "watch", "list"] + - apiGroups: ["scheduling.k8s.io"] + resources: ["priorityclasses"] + verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] + - apiGroups: ["snapshot.storage.k8s.io"] + resources: ["volumesnapshotclasses"] + verbs: ["get", "list", "watch"] + - apiGroups: ["snapshot.storage.k8s.io"] + resources: ["volumesnapshotcontents"] + verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] + {{- range $key, $container := .Values.plugin }} + {{- if $container.rbac }} + {{- if $container.rbac.clusterRole }} + {{- if $container.rbac.clusterRole.extraRules }} + {{- range $ruleIndex, $rule := $container.rbac.clusterRole.extraRules }} + - {{ toJson $rule }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/eks/templates/rbac/clusterrolebinding.yaml b/charts/eks/templates/rbac/clusterrolebinding.yaml new file mode 100644 index 000000000..44606a040 --- /dev/null +++ b/charts/eks/templates/rbac/clusterrolebinding.yaml @@ -0,0 +1,23 @@ +{{- if .Values.rbac.clusterRole.create }} +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ template "vcluster.clusterRoleName" . }} + labels: + app: vcluster + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +subjects: + - kind: ServiceAccount + {{- if .Values.serviceAccount.name }} + name: {{ .Values.serviceAccount.name }} + {{- else }} + name: vc-{{ .Release.Name }} + {{- end }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: {{ template "vcluster.clusterRoleName" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} \ No newline at end of file diff --git a/charts/eks/templates/rbac/role.yaml b/charts/eks/templates/rbac/role.yaml new file mode 100644 index 000000000..77afdb48f --- /dev/null +++ b/charts/eks/templates/rbac/role.yaml @@ -0,0 +1,49 @@ +{{- if .Values.rbac.role.create }} +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Release.Name }} + namespace: {{ .Release.Namespace }} + labels: + app: vcluster + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +rules: + - apiGroups: [""] + resources: ["configmaps", "secrets", "services", "pods", "pods/attach", "pods/portforward", "pods/exec", "endpoints", "persistentvolumeclaims"] + verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] + - apiGroups: [""] + resources: ["events", "pods/log"] + verbs: ["get", "list", "watch"] + - apiGroups: ["networking.k8s.io"] + resources: ["ingresses"] + verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] + - apiGroups: ["apps"] + resources: ["statefulsets", "replicasets", "deployments"] + verbs: ["get", "list", "watch"] + {{- if .Values.rbac.role.extended }} + - apiGroups: ["networking.k8s.io"] + resources: ["networkpolicies"] + verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] + - apiGroups: ["snapshot.storage.k8s.io"] + resources: ["volumesnapshots"] + verbs: ["create", "delete", "patch", "update", "get", "list", "watch"] + {{- end }} + {{- if .Values.openshift.enable }} + - apiGroups: [""] + resources: ["endpoints/restricted"] + verbs: ["create"] + {{- end }} + {{- range $key, $container := .Values.plugin }} + {{- if $container.rbac }} + {{- if $container.rbac.role }} + {{- if $container.rbac.role.extraRules }} + {{- range $ruleIndex, $rule := $container.rbac.role.extraRules }} + - {{ toJson $rule }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/eks/templates/rbac/rolebinding.yaml b/charts/eks/templates/rbac/rolebinding.yaml new file mode 100644 index 000000000..e751c0e41 --- /dev/null +++ b/charts/eks/templates/rbac/rolebinding.yaml @@ -0,0 +1,24 @@ +{{- if .Values.rbac.role.create }} +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Release.Name }} + namespace: {{ .Release.Namespace }} + labels: + app: vcluster + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +subjects: + - kind: ServiceAccount + {{- if .Values.serviceAccount.name }} + name: {{ .Values.serviceAccount.name }} + {{- else }} + name: vc-{{ .Release.Name }} + {{- end }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: Role + name: {{ .Release.Name }} + apiGroup: rbac.authorization.k8s.io +{{- end }} \ No newline at end of file diff --git a/charts/eks/templates/serviceaccount.yaml b/charts/eks/templates/serviceaccount.yaml new file mode 100644 index 000000000..14a522afe --- /dev/null +++ b/charts/eks/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: vc-{{ .Release.Name }} + namespace: {{ .Release.Namespace }} + labels: + app: vcluster + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +{{- if .Values.serviceAccount.imagePullSecrets }} +imagePullSecrets: +{{ toYaml .Values.serviceAccount.imagePullSecrets | indent 2 }} +{{- end }} +{{- end }} diff --git a/charts/eks/templates/syncer-deployment.yaml b/charts/eks/templates/syncer-deployment.yaml new file mode 100644 index 000000000..489e0480a --- /dev/null +++ b/charts/eks/templates/syncer-deployment.yaml @@ -0,0 +1,195 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }} + namespace: {{ .Release.Namespace }} + labels: + app: vcluster + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +{{- if .Values.syncer.labels }} +{{ toYaml .Values.syncer.labels | indent 4 }} +{{- end }} + {{- if .Values.syncer.annotations }} + annotations: +{{ toYaml .Values.syncer.annotations | indent 4 }} + {{- end }} +spec: + replicas: {{ .Values.syncer.replicas }} + strategy: + rollingUpdate: + maxSurge: 1 + {{- if (eq (int .Values.syncer.replicas) 1) }} + maxUnavailable: 0 + {{- else }} + maxUnavailable: 1 + {{- end }} + type: RollingUpdate + selector: + matchLabels: + app: vcluster + release: {{ .Release.Name }} + template: + metadata: + labels: + app: vcluster + release: {{ .Release.Name }} + spec: + terminationGracePeriodSeconds: 10 + {{- if .Values.syncer.affinity }} + affinity: +{{ toYaml .Values.syncer.affinity | indent 8 }} + {{- end }} + {{- if .Values.syncer.topologySpreadConstraints }} + topologySpreadConstraints: +{{ toYaml .Values.syncer.topologySpreadConstraints | indent 8 }} + {{- end }} + nodeSelector: +{{ toYaml .Values.syncer.nodeSelector | indent 8 }} + affinity: +{{ toYaml .Values.syncer.affinity | indent 8 }} + tolerations: +{{ toYaml .Values.syncer.tolerations | indent 8 }} + {{- if .Values.serviceAccount.name }} + serviceAccountName: {{ .Values.serviceAccount.name }} + {{- else }} + serviceAccountName: vc-{{ .Release.Name }} + {{- end }} + volumes: + - name: coredns + configMap: + name: custom-deployments + - name: certs + secret: + secretName: {{ .Release.Name }}-certs + {{- if .Values.syncer.volumes }} +{{ toYaml .Values.syncer.volumes | indent 8 }} + {{- end }} + containers: + - name: syncer + {{- if .Values.syncer.image }} + image: "{{ .Values.defaultImageRegistry }}{{ .Values.syncer.image }}" + {{- else }} + image: "{{ .Values.defaultImageRegistry }}loftsh/vcluster:{{ .Chart.Version }}" + {{- end }} + {{- if .Values.syncer.workingDir }} + workingDir: {{ .Values.syncer.workingDir }} + {{- end }} + {{- if .Values.syncer.command }} + command: + {{- range $f := .Values.syncer.command }} + - {{ $f | quote }} + {{- end }} + {{- end }} + {{- if not .Values.syncer.noArgs }} + args: + - --name={{ .Release.Name }} + - --request-header-ca-cert=/pki/ca.crt + - --client-ca-cert=/pki/ca.crt + - --server-ca-cert=/pki/ca.crt + - --server-ca-key=/pki/ca.key + - --kube-config=/pki/admin.conf + {{- if .Values.defaultImageRegistry }} + - --default-image-registry={{ .Values.defaultImageRegistry }} + {{- end }} + {{- if .Values.enableHA }} + - --leader-elect=true + {{- else }} + - --leader-elect=false + {{- end }} + {{- if .Values.ingress.enabled }} + - --tls-san={{ .Values.ingress.host }} + {{- end }} + {{- range $f := .Values.syncer.extraArgs }} + - {{ $f | quote }} + {{- end }} + {{- else }} + args: +{{ toYaml .Values.syncer.extraArgs | indent 10 }} + {{- end }} + {{- if .Values.syncer.livenessProbe }} + {{- if .Values.syncer.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: /healthz + port: 8443 + scheme: HTTPS + failureThreshold: 10 + initialDelaySeconds: 60 + periodSeconds: 2 + {{- end }} + {{- end }} + {{- if .Values.syncer.readinessProbe }} + {{- if .Values.syncer.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: /readyz + port: 8443 + scheme: HTTPS + failureThreshold: 30 + periodSeconds: 2 + {{- end }} + {{- end }} + securityContext: +{{ toYaml .Values.syncer.securityContext | indent 10 }} + env: +{{ toYaml .Values.syncer.env | indent 10 }} + volumeMounts: +{{ toYaml .Values.syncer.volumeMounts | indent 10 }} + resources: +{{ toYaml .Values.syncer.resources | indent 10 }} + {{- range $key, $container := .Values.plugin }} + - image: {{ $.Values.defaultImageRegistry }}{{ $container.image }} + {{- if $container.name }} + name: {{ $container.name | quote }} + {{- else }} + name: {{ $key | quote }} + {{- end }} + {{- if $container.imagePullPolicy }} + imagePullPolicy: {{ $container.imagePullPolicy }} + {{- end }} + {{- if $container.workingDir }} + workingDir: {{ $container.workingDir }} + {{- end }} + {{- if $container.command }} + command: + {{- range $commandIndex, $command := $container.command }} + - {{ $command | quote }} + {{- end }} + {{- end }} + {{- if $container.args }} + args: + {{- range $argIndex, $arg := $container.args }} + - {{ $arg | quote }} + {{- end }} + {{- end }} + {{- if $container.terminationMessagePath }} + terminationMessagePath: {{ $container.terminationMessagePath }} + {{- end }} + {{- if $container.terminationMessagePolicy }} + terminationMessagePolicy: {{ $container.terminationMessagePolicy }} + {{- end }} + env: +{{ toYaml $container.env | indent 10 }} + envFrom: +{{ toYaml $container.envFrom | indent 10 }} + securityContext: +{{ toYaml $container.securityContext | indent 10 }} + lifecycle: +{{ toYaml $container.lifecycle | indent 10 }} + livenessProbe: +{{ toYaml $container.livenessProbe | indent 10 }} + readinessProbe: +{{ toYaml $container.readinessProbe | indent 10 }} + startupProbe: +{{ toYaml $container.startupProbe | indent 10 }} + volumeDevices: +{{ toYaml $container.volumeDevices | indent 10 }} + volumeMounts: +{{ toYaml $container.volumeMounts | indent 10 }} + {{- if $container.resources }} + resources: +{{ toYaml $container.resources | indent 10 }} + {{- end }} + {{- end }} diff --git a/charts/eks/templates/syncer-service.yaml b/charts/eks/templates/syncer-service.yaml new file mode 100644 index 000000000..d574bb686 --- /dev/null +++ b/charts/eks/templates/syncer-service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }} + namespace: {{ .Release.Namespace }} + labels: + app: vcluster + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + type: {{ .Values.service.type }} + ports: + - name: https + port: 443 + targetPort: 8443 + protocol: TCP + selector: + app: vcluster + release: {{ .Release.Name }} diff --git a/charts/eks/values.yaml b/charts/eks/values.yaml new file mode 100644 index 000000000..675d3f2a0 --- /dev/null +++ b/charts/eks/values.yaml @@ -0,0 +1,185 @@ +# Make sure the service-cidr is the exact service cidr of the host cluster. +# If this does not match, you won't be able to create services within the vcluster. You can find out +# the service cidr of the host cluster by creating a service with a not allowed ClusterIP in the host cluster. +# This will yield an error message in the form of: +# The Service "faulty-service" is invalid: spec.clusterIP: Invalid value: "1.1.1.1": provided IP is not in the valid range. The range of valid IPs is 10.96.0.0/12 +serviceCIDR: "10.96.0.0/12" + +# DefaultImageRegistry will be prepended to all deployed vcluster images, such as the vcluster pod, coredns etc.. Deployed +# images within the vcluster will not be rewritten. +defaultImageRegistry: "" + +# If the control plane is deployed in high availability mode +# Make sure to scale up the syncer.replicas, etcd.replicas, api.replicas & controller.replicas +enableHA: false + +# Plugins that should get loaded. Usually you want to apply those via 'vcluster create ... -f https://.../plugin.yaml' +plugin: {} +# Manually configure a plugin called test +# test: +# image: ... +# env: ... +# rbac: +# clusterRole: +# extraRules: ... +# role: +# extraRules: ... + +# Syncer configuration +syncer: + # Image to use for the syncer + # image: loftsh/vcluster + extraArgs: [] + volumeMounts: + - mountPath: /manifests/coredns + name: coredns + readOnly: true + - mountPath: /pki + name: certs + readOnly: true + env: [] + livenessProbe: + enabled: true + readinessProbe: + enabled: true + resources: + limits: + memory: 1Gi + requests: + cpu: 100m + memory: 128Mi + # Extra volumes + volumes: [] + # The amount of replicas to run the deployment with + replicas: 1 + # NodeSelector used to schedule the syncer + nodeSelector: {} + # Affinity to apply to the syncer deployment + affinity: {} + # Tolerations to apply to the syncer deployment + tolerations: [] + # Extra Labels for the syncer deployment + labels: {} + # Extra Annotations for the syncer deployment + annotations: {} + +# Etcd settings +etcd: + image: public.ecr.aws/eks-distro/etcd-io/etcd:v3.4.16-eks-1-21-8 + # The amount of replicas to run + replicas: 1 + # NodeSelector used + nodeSelector: {} + # Affinity to apply + affinity: {} + # Tolerations to apply + tolerations: [] + # Extra Labels + labels: {} + # Extra Annotations + annotations: {} + resources: + requests: + cpu: 100m + memory: 100Mi + # Storage settings for the etcd + storage: + # If this is disabled, vcluster will use an emptyDir instead + # of a PersistentVolumeClaim + persistence: true + # Size of the persistent volume claim + size: 5Gi + # Optional StorageClass used for the pvc + # if empty default StorageClass defined in your host cluster will be used + #className: + +# Kubernetes Controller Manager settings +controller: + image: public.ecr.aws/eks-distro/kubernetes/kube-controller-manager:v1.21.5-eks-1-21-8 + # The amount of replicas to run the deployment with + replicas: 1 + # NodeSelector used + nodeSelector: {} + # Affinity to apply + affinity: {} + # Tolerations to apply + tolerations: [] + # Extra Labels + labels: {} + # Extra Annotations + annotations: {} + resources: + requests: + cpu: 200m + +# Kubernetes API Server settings +api: + image: public.ecr.aws/eks-distro/kubernetes/kube-apiserver:v1.21.5-eks-1-21-8 + extraArgs: [] + # The amount of replicas to run the deployment with + replicas: 1 + # NodeSelector used to schedule the syncer + nodeSelector: {} + # Affinity to apply to the syncer deployment + affinity: {} + # Tolerations to apply to the syncer deployment + tolerations: [] + # Extra Labels for the syncer deployment + labels: {} + # Extra Annotations for the syncer deployment + annotations: {} + resources: + requests: + cpu: 200m + +# Core DNS settings +coredns: + image: public.ecr.aws/eks-distro/coredns/coredns:v1.8.4-eks-1-21-8 + +# Service account that should be used by the vcluster +serviceAccount: + create: true + # Optional name of the service account to use + # name: default + +# Roles & ClusterRoles for the vcluster +rbac: + clusterRole: + # Enable this to let the vcluster sync + # real nodes, storage classes and priority classes + create: false + role: + # This is required for basic functionality of vcluster + create: true + # Extended role permissions are required for some optional features, e.g. Networkpolicy sync + extended: false + +# Service configurations +service: + type: ClusterIP + +# PreInstall hook configuration +preInstall: + enabled: true + +# Configure the ingress resource that allows you to access the vcluster +ingress: + # Enable ingress record generation + enabled: false + # Ingress path type + pathType: ImplementationSpecific + apiVersion: networking.k8s.io/v1 + ingressClassName: "" + host: vcluster.local + annotations: + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/backend-protocol: HTTPS + nginx.ingress.kubernetes.io/ssl-passthrough: "true" + nginx.ingress.kubernetes.io/ssl-redirect: "true" + +# Set "enable" to true when running vcluster in an OpenShift host +# This will add an extra rule to the deployed role binding in order +# to manage service endpoints +openshift: + enable: false + \ No newline at end of file diff --git a/cmd/vclusterctl/cmd/create.go b/cmd/vclusterctl/cmd/create.go index 4ddab6a2e..85c533034 100644 --- a/cmd/vclusterctl/cmd/create.go +++ b/cmd/vclusterctl/cmd/create.go @@ -28,7 +28,7 @@ import ( ) var ( - AllowedDistros = []string{"k3s", "k0s", "k8s"} + AllowedDistros = []string{"k3s", "k0s", "k8s", "eks"} ) // CreateCmd holds the login cmd flags diff --git a/pkg/helm/types.go b/pkg/helm/types.go index b12bc302b..70b86d432 100644 --- a/pkg/helm/types.go +++ b/pkg/helm/types.go @@ -6,6 +6,7 @@ const ( K3SChart = "vcluster" K0SChart = "vcluster-k0s" K8SChart = "vcluster-k8s" + EKSChart = "vcluster-eks" ) // ChartOptions holds the chart options diff --git a/pkg/helm/values/default.go b/pkg/helm/values/default.go index 336eaa7c8..c15319410 100644 --- a/pkg/helm/values/default.go +++ b/pkg/helm/values/default.go @@ -12,6 +12,8 @@ func GetDefaultReleaseValues(chartOptions *helm.ChartOptions, log log.Logger) (s return getDefaultK0SReleaseValues(chartOptions, log) } else if chartOptions.ChartName == helm.K8SChart { return getDefaultK8SReleaseValues(chartOptions, log) + } else if chartOptions.ChartName == helm.EKSChart { + return getDefaultEKSReleaseValues(chartOptions, log) } return "", nil diff --git a/pkg/helm/values/eks.go b/pkg/helm/values/eks.go new file mode 100644 index 000000000..1d6787a02 --- /dev/null +++ b/pkg/helm/values/eks.go @@ -0,0 +1,72 @@ +package values + +import ( + "strings" + + "github.com/loft-sh/vcluster/pkg/helm" + "github.com/loft-sh/vcluster/pkg/log" +) + +var EKSAPIVersionMap = map[string]string{ + "1.21": "public.ecr.aws/eks-distro/kubernetes/kube-apiserver:v1.21.5-eks-1-21-8", + "1.20": "public.ecr.aws/eks-distro/kubernetes/kube-apiserver:v1.20.11-eks-1-20-102", +} + +var EKSControllerVersionMap = map[string]string{ + "1.21": "public.ecr.aws/eks-distro/kubernetes/kube-controller-manager:v1.21.5-eks-1-21-8", + "1.20": "public.ecr.aws/eks-distro/kubernetes/kube-controller-manager:v1.20.11-eks-1-20-10", +} + +var EKSEtcdVersionMap = map[string]string{ + "1.21": "public.ecr.aws/eks-distro/etcd-io/etcd:v3.4.16-eks-1-21-8", + "1.20": "public.ecr.aws/eks-distro/etcd-io/etcd:v3.4.15-eks-1-20-10", +} + +var EKSCoreDNSVersionMap = map[string]string{ + "1.21": "public.ecr.aws/eks-distro/coredns/coredns:v1.8.4-eks-1-21-8", + "1.20": "public.ecr.aws/eks-distro/coredns/coredns:v1.8.3-eks-1-20-10", +} + +func getDefaultEKSReleaseValues(chartOptions *helm.ChartOptions, log log.Logger) (string, error) { + serverVersionString := GetKubernetesVersion(chartOptions.KubernetesVersion) + serverMinorInt, err := GetKubernetesMinorVersion(chartOptions.KubernetesVersion) + if err != nil { + return "", err + } + + apiImage := EKSAPIVersionMap[serverVersionString] + controllerImage := EKSControllerVersionMap[serverVersionString] + etcdImage := EKSEtcdVersionMap[serverVersionString] + corednsImage, ok := EKSCoreDNSVersionMap[serverVersionString] + if !ok { + if serverMinorInt > 21 { + log.Infof("officially unsupported host server version %s, will fallback to virtual cluster version v1.21", serverVersionString) + apiImage = EKSAPIVersionMap["1.21"] + controllerImage = EKSControllerVersionMap["1.21"] + etcdImage = EKSEtcdVersionMap["1.21"] + corednsImage = EKSCoreDNSVersionMap["1.21"] + } else { + log.Infof("officially unsupported host server version %s, will fallback to virtual cluster version v1.20", serverVersionString) + apiImage = EKSAPIVersionMap["1.20"] + controllerImage = EKSControllerVersionMap["1.20"] + etcdImage = EKSEtcdVersionMap["1.20"] + corednsImage = EKSCoreDNSVersionMap["1.20"] + } + } + + // build values + values := `api: + image: ##API_IMAGE## +controller: + image: ##CONTROLLER_IMAGE## +etcd: + image: ##ETCD_IMAGE## +coredns: + image: ##COREDNS_IMAGE## +` + values = strings.ReplaceAll(values, "##API_IMAGE##", apiImage) + values = strings.ReplaceAll(values, "##CONTROLLER_IMAGE##", controllerImage) + values = strings.ReplaceAll(values, "##ETCD_IMAGE##", etcdImage) + values = strings.ReplaceAll(values, "##COREDNS_IMAGE##", corednsImage) + return addCommonReleaseValues(values, chartOptions) +}