diff --git a/controllers/job/init/README.md b/controllers/job/init/deploy/README.md similarity index 100% rename from controllers/job/init/README.md rename to controllers/job/init/deploy/README.md diff --git a/controllers/terminal/deploy/Kubefile b/controllers/terminal/deploy/Kubefile index a72f33ac3..cac4e9d7f 100644 --- a/controllers/terminal/deploy/Kubefile +++ b/controllers/terminal/deploy/Kubefile @@ -3,12 +3,7 @@ FROM scratch USER 65532:65532 COPY registry registry -COPY manifests manifests +COPY charts charts +COPY terminal-controller-entrypoint.sh terminal-controller-entrypoint.sh -ENV userNamespace="user-system" -ENV cloudDomain="127.0.0.1.nip.io" -ENV cloudPort="" -ENV wildcardCertSecretName="wildcard-cert" -ENV wildcardCertSecretNamespace="sealos-system" - -CMD ["kubectl apply -f manifests"] +CMD ["bash terminal-controller-entrypoint.sh"] diff --git a/controllers/terminal/deploy/README.md b/controllers/terminal/deploy/README.md index 9353208a2..08f72f32c 100644 --- a/controllers/terminal/deploy/README.md +++ b/controllers/terminal/deploy/README.md @@ -1,11 +1,38 @@ ### How to build image ```shell -sealos build -t docker.io/labring/sealos-terminal-controller:latest -f Dockerfile . +sealos build -t docker.io/labring/sealos-terminal-controller:latest -f Kubefile . ``` ### How to run ```shell -sealos run docker.io/labring/sealos-terminal-controller:latest +sealos run docker.io/labring/sealos-terminal-controller:latest ``` + +### Configuration + +The terminal controller supports the following environment variables: + +- `RELEASE_NAME`: Helm release name (default: `terminal`) +- `RELEASE_NAMESPACE`: Deployment namespace (default: `terminal-system`) +- `CHART_PATH`: Path to helm chart (default: `./charts/terminal-controller`) +- `HELM_OPTS`: Additional helm options +- `SEALOS_CLOUD_DOMAIN`: Cloud domain (auto-detected from sealos-config) +- `SEALOS_CLOUD_PORT`: Cloud port (auto-detected from sealos-config) +- `TERMINAL_BACKUP_ENABLED`: Enable resource backup (default: `true`) +- `TERMINAL_BACKUP_DIR`: Backup directory (default: `/tmp/sealos-backup/terminal-controller`) + +### Deployment Structure + +This deployment uses Helm charts for better manageability: + +- **Chart**: `charts/terminal-controller/` +- **Entrypoint**: `terminal-controller-entrypoint.sh` +- **CRD**: Terminals.terminal.sealos.io + +The controller will automatically: +- Create namespace if it doesn't exist (via `--create-namespace`) +- Adopt existing resources for smooth migration +- Backup resources before upgrades +- Configure from sealos-system configmap diff --git a/controllers/terminal/deploy/charts/terminal-controller/.helmignore b/controllers/terminal/deploy/charts/terminal-controller/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/controllers/terminal/deploy/charts/terminal-controller/.helmignore @@ -0,0 +1,23 @@ +# 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 +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/controllers/terminal/deploy/charts/terminal-controller/Chart.yaml b/controllers/terminal/deploy/charts/terminal-controller/Chart.yaml new file mode 100644 index 000000000..8229d9f41 --- /dev/null +++ b/controllers/terminal/deploy/charts/terminal-controller/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: terminal +description: Helm chart for the sealos terminal controller +type: application +version: 0.1.0 +appVersion: "0.1.0" diff --git a/controllers/terminal/deploy/charts/terminal-controller/crds/terminals.terminal.sealos.io.yaml b/controllers/terminal/deploy/charts/terminal-controller/crds/terminals.terminal.sealos.io.yaml new file mode 100644 index 000000000..7afca3e54 --- /dev/null +++ b/controllers/terminal/deploy/charts/terminal-controller/crds/terminals.terminal.sealos.io.yaml @@ -0,0 +1,97 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.0 + creationTimestamp: null + name: terminals.terminal.sealos.io +spec: + group: terminal.sealos.io + names: + kind: Terminal + listKind: TerminalList + plural: terminals + singular: terminal + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.user + name: User + type: string + - jsonPath: .spec.keepalived + name: Keepalived + type: string + - jsonPath: .status.domain + name: Domain + type: string + - jsonPath: .metadata.annotations.lastUpdateTime + name: LastUpdateTime + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: Terminal is the Schema for the terminals API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: TerminalSpec defines the desired state of Terminal + properties: + apiServer: + type: string + ingressType: + default: nginx + enum: + - nginx + type: string + keepalived: + type: string + replicas: + format: int32 + type: integer + token: + type: string + ttyImage: + type: string + user: + type: string + required: + - keepalived + - replicas + - token + - ttyImage + - user + type: object + status: + description: TerminalStatus defines the observed state of Terminal + properties: + availableReplicas: + format: int32 + type: integer + domain: + type: string + secretHeader: + type: string + serviceName: + type: string + required: + - availableReplicas + - domain + - secretHeader + - serviceName + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/controllers/terminal/deploy/charts/terminal-controller/templates/NOTES.txt b/controllers/terminal/deploy/charts/terminal-controller/templates/NOTES.txt new file mode 100644 index 000000000..6f54f1872 --- /dev/null +++ b/controllers/terminal/deploy/charts/terminal-controller/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 }} diff --git a/controllers/terminal/deploy/charts/terminal-controller/templates/_helpers.tpl b/controllers/terminal/deploy/charts/terminal-controller/templates/_helpers.tpl new file mode 100644 index 000000000..f69e03993 --- /dev/null +++ b/controllers/terminal/deploy/charts/terminal-controller/templates/_helpers.tpl @@ -0,0 +1,60 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "terminal.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +*/}} +{{- define "terminal.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 }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "terminal.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "terminal.labels" -}} +helm.sh/chart: {{ include "terminal.chart" . }} +{{ include "terminal.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "terminal.selectorLabels" -}} +app.kubernetes.io/name: {{ include "terminal.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "terminal.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "terminal.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/controllers/terminal/deploy/charts/terminal-controller/templates/configmap.yaml b/controllers/terminal/deploy/charts/terminal-controller/templates/configmap.yaml new file mode 100644 index 000000000..87ef08922 --- /dev/null +++ b/controllers/terminal/deploy/charts/terminal-controller/templates/configmap.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "terminal.fullname" . }}-manager-config + namespace: {{ .Release.Namespace }} + labels: + control-plane: controller-manager + {{- include "terminal.labels" . | nindent 4 }} +data: + controller_manager_config.yaml: | + apiVersion: controller-runtime.sigs.k8s.io/v1alpha1 + kind: ControllerManagerConfig + health: + healthProbeBindAddress: :8081 + metrics: + bindAddress: 127.0.0.1:8080 + leaderElection: + leaderElect: true + resourceName: 50686b4e.sealos.io + config.yaml: | + global: + cloudDomain: {{ .Values.config.cloudDomain | quote }} + {{- if .Values.config.cloudPort }} + cloudPort: {{ .Values.config.cloudPort | quote }} + {{- end }} + terminalController: + ingressTLSSecretName: {{ .Values.config.ingressTLSSecretName | quote }} diff --git a/controllers/terminal/deploy/charts/terminal-controller/templates/deployment.yaml b/controllers/terminal/deploy/charts/terminal-controller/templates/deployment.yaml new file mode 100644 index 000000000..3e9a10b02 --- /dev/null +++ b/controllers/terminal/deploy/charts/terminal-controller/templates/deployment.yaml @@ -0,0 +1,98 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "terminal.fullname" . }}-controller-manager + labels: + control-plane: controller-manager + {{- include "terminal.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + control-plane: controller-manager + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + checksum/terminal-manager-config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + control-plane: controller-manager + {{- include "terminal.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "terminal.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: manager + command: + - /manager + args: + - --health-probe-bind-address=:8081 + - --metrics-bind-address=127.0.0.1:8080 + - --leader-elect + - --config-file-path=/config.yaml + env: + - name: TERMINAL_SYSTEM_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + image: "{{ .Values.image }}" + imagePullPolicy: {{ .Values.imagePullPolicy }} + livenessProbe: + {{- toYaml .Values.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.readinessProbe | nindent 12 }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + volumeMounts: + {{- with .Values.volumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + - name: terminal-manager-config + mountPath: /config.yaml + subPath: config.yaml + terminationGracePeriodSeconds: 10 + affinity: + {{- if .Values.affinity }} + {{- toYaml .Values.affinity | nindent 8 }} + {{- else }} + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: control-plane + operator: In + values: + - controller-manager + topologyKey: kubernetes.io/hostname + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + {{- with .Values.volumes }} + {{- toYaml . | nindent 8 }} + {{- end }} + - name: terminal-manager-config + configMap: + name: {{ include "terminal.fullname" . }}-manager-config diff --git a/controllers/terminal/deploy/charts/terminal-controller/templates/rbac.yaml b/controllers/terminal/deploy/charts/terminal-controller/templates/rbac.yaml new file mode 100644 index 000000000..ac2acf8ae --- /dev/null +++ b/controllers/terminal/deploy/charts/terminal-controller/templates/rbac.yaml @@ -0,0 +1,174 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "terminal.fullname" . }}-leader-election-role + namespace: {{ .Release.Namespace }} + labels: + control-plane: controller-manager + {{- include "terminal.labels" . | nindent 4 }} +rules: + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "terminal.fullname" . }}-manager-role +rules: + - apiGroups: + - "" + resources: + - events + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - apps + resources: + - deployments + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - "" + resources: + - services + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - networking.k8s.io + resources: + - ingresses + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - rbac.authorization.k8s.io + resources: + - rolebindings + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - rbac.authorization.k8s.io + resources: + - roles + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - terminal.sealos.io + resources: + - terminals + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - terminal.sealos.io + resources: + - terminals/finalizers + verbs: + - update + - apiGroups: + - terminal.sealos.io + resources: + - terminals/status + verbs: + - get + - patch + - update +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "terminal.fullname" . }}-leader-election-rolebinding + namespace: {{ .Release.Namespace }} + labels: + control-plane: controller-manager + {{- include "terminal.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "terminal.fullname" . }}-leader-election-role +subjects: + - kind: ServiceAccount + name: {{ include "terminal.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "terminal.fullname" . }}-manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "terminal.fullname" . }}-manager-role +subjects: + - kind: ServiceAccount + name: {{ include "terminal.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} diff --git a/controllers/terminal/deploy/charts/terminal-controller/templates/service.yaml b/controllers/terminal/deploy/charts/terminal-controller/templates/service.yaml new file mode 100644 index 000000000..8686ddcee --- /dev/null +++ b/controllers/terminal/deploy/charts/terminal-controller/templates/service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + control-plane: controller-manager + {{- include "terminal.labels" . | nindent 4 }} + name: {{ include "terminal.fullname" . }}-controller-manager-metrics-service + namespace: {{ .Release.Namespace }} +spec: + ports: + - name: https + port: 8443 + protocol: TCP + targetPort: https + selector: + control-plane: controller-manager diff --git a/controllers/terminal/deploy/charts/terminal-controller/templates/serviceaccount.yaml b/controllers/terminal/deploy/charts/terminal-controller/templates/serviceaccount.yaml new file mode 100644 index 000000000..2314ee0a8 --- /dev/null +++ b/controllers/terminal/deploy/charts/terminal-controller/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "terminal.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} + labels: + control-plane: controller-manager + {{- include "terminal.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} diff --git a/controllers/terminal/deploy/charts/terminal-controller/values.yaml b/controllers/terminal/deploy/charts/terminal-controller/values.yaml new file mode 100644 index 000000000..fb11fc7c5 --- /dev/null +++ b/controllers/terminal/deploy/charts/terminal-controller/values.yaml @@ -0,0 +1,67 @@ +# Default values for terminal controller helm chart. + +replicaCount: 1 + +image: ghcr.io/labring/sealos-terminal-controller:latest +imagePullPolicy: Always + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "terminal" + +serviceAccount: + create: true + automount: true + annotations: {} + name: "terminal-controller-manager" + +podAnnotations: {} +podLabels: {} + +podSecurityContext: + runAsNonRoot: true + +securityContext: + allowPrivilegeEscalation: false + runAsNonRoot: true + +service: + metrics: + port: 8443 + +resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + +config: + cloudDomain: "cloud.sealos.io" + cloudPort: "" + ingressTLSSecretName: "wildcard-cert-sealos" + +livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + +readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + +volumes: [] +volumeMounts: [] + +nodeSelector: {} + +tolerations: [] + +# If no affinity is provided a default podAntiAffinity is used to spread controllers. +affinity: {} diff --git a/controllers/terminal/deploy/manifests/deploy.yaml.tmpl b/controllers/terminal/deploy/manifests/deploy.yaml.tmpl deleted file mode 100644 index c92a9e8c6..000000000 --- a/controllers/terminal/deploy/manifests/deploy.yaml.tmpl +++ /dev/null @@ -1,476 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - labels: - control-plane: controller-manager - name: terminal-system ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.0 - creationTimestamp: null - name: terminals.terminal.sealos.io -spec: - group: terminal.sealos.io - names: - kind: Terminal - listKind: TerminalList - plural: terminals - singular: terminal - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.user - name: User - type: string - - jsonPath: .spec.keepalived - name: Keepalived - type: string - - jsonPath: .status.domain - name: Domain - type: string - - jsonPath: .metadata.annotations.lastUpdateTime - name: LastUpdateTime - priority: 1 - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1 - schema: - openAPIV3Schema: - description: Terminal is the Schema for the terminals API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: TerminalSpec defines the desired state of Terminal - properties: - apiServer: - type: string - ingressType: - default: nginx - enum: - - nginx - type: string - keepalived: - type: string - replicas: - format: int32 - type: integer - token: - type: string - ttyImage: - type: string - user: - type: string - required: - - keepalived - - replicas - - token - - ttyImage - - user - type: object - status: - description: TerminalStatus defines the observed state of Terminal - properties: - availableReplicas: - format: int32 - type: integer - domain: - type: string - secretHeader: - type: string - serviceName: - type: string - required: - - availableReplicas - - domain - - secretHeader - - serviceName - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: terminal-controller-manager - namespace: terminal-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: terminal-leader-election-role - namespace: terminal-system -rules: -- apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - create - - update - - patch - - delete -- apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - get - - list - - watch - - create - - update - - patch - - delete -- apiGroups: - - "" - resources: - - events - verbs: - - create - - patch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - creationTimestamp: null - name: terminal-manager-role -rules: -- apiGroups: - - "" - resources: - - events - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - apps - resources: - - deployments - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - services - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - networking.k8s.io - resources: - - ingresses - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - rbac.authorization.k8s.io - resources: - - rolebindings - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - rbac.authorization.k8s.io - resources: - - roles - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - terminal.sealos.io - resources: - - terminals - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - terminal.sealos.io - resources: - - terminals/finalizers - verbs: - - update -- apiGroups: - - terminal.sealos.io - resources: - - terminals/status - verbs: - - get - - patch - - update ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: terminal-metrics-reader -rules: -- nonResourceURLs: - - /metrics - verbs: - - get ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: terminal-proxy-role -rules: -- apiGroups: - - authentication.k8s.io - resources: - - tokenreviews - verbs: - - create -- apiGroups: - - authorization.k8s.io - resources: - - subjectaccessreviews - verbs: - - create ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: terminal-leader-election-rolebinding - namespace: terminal-system -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: terminal-leader-election-role -subjects: -- kind: ServiceAccount - name: terminal-controller-manager - namespace: terminal-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: terminal-manager-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: terminal-manager-role -subjects: -- kind: ServiceAccount - name: terminal-controller-manager - namespace: terminal-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: terminal-proxy-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: terminal-proxy-role -subjects: -- kind: ServiceAccount - name: terminal-controller-manager - namespace: terminal-system ---- -apiVersion: v1 -data: - controller_manager_config.yaml: | - apiVersion: controller-runtime.sigs.k8s.io/v1alpha1 - kind: ControllerManagerConfig - health: - healthProbeBindAddress: :8081 - metrics: - bindAddress: 127.0.0.1:8080 - webhook: - port: 9443 - leaderElection: - leaderElect: true - resourceName: 50686b4e.sealos.io - # leaderElectionReleaseOnCancel defines if the leader should step down volume - # when the Manager ends. This requires the binary to immediately end when the - # Manager is stopped, otherwise, this setting is unsafe. Setting this significantly - # speeds up voluntary leader transitions as the new leader don't have to wait - # LeaseDuration time first. - # In the default scaffold provided, the program ends immediately after - # the manager stops, so would be fine to enable this option. However, - # if you are doing or is intended to do any operation such as perform cleanups - # after the manager stops then its usage might be unsafe. - # leaderElectionReleaseOnCancel: true - config.yaml: | - global: - cloudDomain: {{ .cloudDomain }} - cloudPort: {{ if .cloudPort }}{{ .cloudPort }}{{ end }} - terminalController: - ingressTLSSecretName: {{ .wildcardCertSecretName }} -kind: ConfigMap -metadata: - name: terminal-manager-config - namespace: terminal-system ---- -apiVersion: v1 -kind: Service -metadata: - labels: - control-plane: controller-manager - name: terminal-controller-manager-metrics-service - namespace: terminal-system -spec: - ports: - - name: https - port: 8443 - protocol: TCP - targetPort: https - selector: - control-plane: controller-manager ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - control-plane: controller-manager - name: terminal-controller-manager - namespace: terminal-system -spec: - replicas: 1 - selector: - matchLabels: - control-plane: controller-manager - template: - metadata: - annotations: - kubectl.kubernetes.io/default-container: manager - labels: - control-plane: controller-manager - spec: - containers: - - args: - - --secure-listen-address=0.0.0.0:8443 - - --upstream=http://127.0.0.1:8080/ - - --logtostderr=true - - --v=0 - image: gcr.io/kubebuilder/kube-rbac-proxy:v0.12.0 - name: kube-rbac-proxy - ports: - - containerPort: 8443 - name: https - protocol: TCP - resources: - limits: - cpu: 1000m - memory: 1024Mi - requests: - cpu: 50m - memory: 128Mi - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - runAsNonRoot: true - - args: - - --health-probe-bind-address=:8081 - - --metrics-bind-address=127.0.0.1:8080 - - --leader-elect - - --config-file-path=/config.yaml - command: - - /manager - image: ghcr.io/labring/sealos-terminal-controller:latest - imagePullPolicy: Always - volumeMounts: - - name: terminal-manager-volume - mountPath: /config.yaml - subPath: config.yaml - livenessProbe: - httpGet: - path: /healthz - port: 8081 - initialDelaySeconds: 15 - periodSeconds: 20 - name: manager - readinessProbe: - httpGet: - path: /readyz - port: 8081 - initialDelaySeconds: 5 - periodSeconds: 10 - resources: - limits: - cpu: 500m - memory: 128Mi - requests: - cpu: 10m - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - runAsNonRoot: true - securityContext: - runAsNonRoot: true - serviceAccountName: terminal-controller-manager - terminationGracePeriodSeconds: 10 - affinity: - podAntiAffinity: - preferredDuringSchedulingIgnoredDuringExecution: - - weight: 100 - podAffinityTerm: - labelSelector: - matchExpressions: - - key: "control-plane" - operator: In - values: - - controller-manager - topologyKey: "kubernetes.io/hostname" - volumes: - - name: terminal-manager-volume - configMap: - name: terminal-manager-config \ No newline at end of file diff --git a/controllers/terminal/deploy/terminal-controller-entrypoint.sh b/controllers/terminal/deploy/terminal-controller-entrypoint.sh new file mode 100755 index 000000000..59914e939 --- /dev/null +++ b/controllers/terminal/deploy/terminal-controller-entrypoint.sh @@ -0,0 +1,120 @@ +#!/bin/bash +set -ex + +HELM_OPTS=${HELM_OPTS:-""} +RELEASE_NAME=${RELEASE_NAME:-"terminal"} +RELEASE_NAMESPACE=${RELEASE_NAMESPACE:-"terminal-system"} +CHART_PATH=${CHART_PATH:-"./charts/terminal-controller"} + +TERMINAL_BACKUP_ENABLED=${TERMINAL_BACKUP_ENABLED:-"true"} +TERMINAL_BACKUP_DIR=${TERMINAL_BACKUP_DIR:-"/tmp/sealos-backup/terminal-controller"} + +adopt_namespaced_resource() { + local kind="$1" + local name="$2" + if kubectl -n "${RELEASE_NAMESPACE}" get "${kind}" "${name}" >/dev/null 2>&1; then + kubectl -n "${RELEASE_NAMESPACE}" label "${kind}" "${name}" app.kubernetes.io/managed-by=Helm --overwrite >/dev/null 2>&1 || true + kubectl -n "${RELEASE_NAMESPACE}" annotate "${kind}" "${name}" meta.helm.sh/release-name="${RELEASE_NAME}" meta.helm.sh/release-namespace="${RELEASE_NAMESPACE}" --overwrite >/dev/null 2>&1 || true + fi +} + +adopt_cluster_resource() { + local kind="$1" + local name="$2" + if kubectl get "${kind}" "${name}" >/dev/null 2>&1; then + kubectl label "${kind}" "${name}" app.kubernetes.io/managed-by=Helm --overwrite >/dev/null 2>&1 || true + kubectl annotate "${kind}" "${name}" meta.helm.sh/release-name="${RELEASE_NAME}" meta.helm.sh/release-namespace="${RELEASE_NAMESPACE}" --overwrite >/dev/null 2>&1 || true + fi +} + +get_cm_value() { + local namespace="$1" + local name="$2" + local key="$3" + kubectl get configmap "${name}" -n "${namespace}" -o "jsonpath={.data.${key}}" 2>/dev/null || true +} + +add_set_string() { + local key="$1" + local value="$2" + HELM_SET_ARGS+=(--set-string "${key}=${value}") +} + +backup_ns_resource() { + local kind="$1" + local name="$2" + if kubectl -n "${RELEASE_NAMESPACE}" get "${kind}" "${name}" >/dev/null 2>&1; then + kubectl -n "${RELEASE_NAMESPACE}" get "${kind}" "${name}" -o yaml >> "${TERMINAL_BACKUP_FILE}" + printf "\n---\n" >> "${TERMINAL_BACKUP_FILE}" + fi +} + +backup_cluster_resource() { + local kind="$1" + local name="$2" + if kubectl get "${kind}" "${name}" >/dev/null 2>&1; then + kubectl get "${kind}" "${name}" -o yaml >> "${TERMINAL_BACKUP_FILE}" + printf "\n---\n" >> "${TERMINAL_BACKUP_FILE}" + fi +} + +backup_terminal_resources() { + if [ "${TERMINAL_BACKUP_ENABLED}" != "true" ]; then + return + fi + local ts + ts=$(date +%Y%m%d%H%M%S) + mkdir -p "${TERMINAL_BACKUP_DIR}" + TERMINAL_BACKUP_FILE="${TERMINAL_BACKUP_DIR}/update-${ts}.yaml" + : > "${TERMINAL_BACKUP_FILE}" + + backup_cluster_resource customresourcedefinition terminals.terminal.sealos.io + backup_cluster_resource clusterrole terminal-manager-role + backup_cluster_resource clusterrolebinding terminal-manager-rolebinding + + if kubectl get namespace "${RELEASE_NAMESPACE}" >/dev/null 2>&1; then + kubectl get namespace "${RELEASE_NAMESPACE}" -o yaml >> "${TERMINAL_BACKUP_FILE}" + printf "\n---\n" >> "${TERMINAL_BACKUP_FILE}" + fi + backup_ns_resource configmap terminal-manager-config + backup_ns_resource service terminal-controller-manager-metrics-service + backup_ns_resource deployment terminal-controller-manager + backup_ns_resource serviceaccount terminal-controller-manager + backup_ns_resource role terminal-leader-election-role + backup_ns_resource rolebinding terminal-leader-election-rolebinding +} + +backup_terminal_resources + +HELM_SET_ARGS=() + +# Auto configure from sealos-config +SEALOS_CLOUD_DOMAIN=${SEALOS_CLOUD_DOMAIN:-"$(get_cm_value sealos-system sealos-config cloudDomain)"} +SEALOS_CLOUD_PORT=${SEALOS_CLOUD_PORT:-"$(get_cm_value sealos-system sealos-config cloudPort)"} + +if [ -n "${SEALOS_CLOUD_DOMAIN}" ]; then + add_set_string config.cloudDomain "${SEALOS_CLOUD_DOMAIN}" +fi + +if [ -n "${SEALOS_CLOUD_PORT}" ]; then + add_set_string config.cloudPort "${SEALOS_CLOUD_PORT}" +fi + +if ! helm status "${RELEASE_NAME}" -n "${RELEASE_NAMESPACE}" >/dev/null 2>&1; then + if kubectl get namespace "${RELEASE_NAMESPACE}" >/dev/null 2>&1; then + kubectl label namespace "${RELEASE_NAMESPACE}" app.kubernetes.io/managed-by=Helm --overwrite >/dev/null 2>&1 || true + kubectl annotate namespace "${RELEASE_NAMESPACE}" meta.helm.sh/release-name="${RELEASE_NAME}" meta.helm.sh/release-namespace="${RELEASE_NAMESPACE}" --overwrite >/dev/null 2>&1 || true + fi + + adopt_namespaced_resource configmap terminal-manager-config + adopt_namespaced_resource service terminal-controller-manager-metrics-service + adopt_namespaced_resource deployment terminal-controller-manager + adopt_namespaced_resource serviceaccount terminal-controller-manager + adopt_namespaced_resource role terminal-leader-election-role + adopt_namespaced_resource rolebinding terminal-leader-election-rolebinding + + adopt_cluster_resource clusterrole terminal-manager-role + adopt_cluster_resource clusterrolebinding terminal-manager-rolebinding +fi + +helm upgrade -i "${RELEASE_NAME}" -n "${RELEASE_NAMESPACE}" --create-namespace "${CHART_PATH}" "${HELM_SET_ARGS[@]}" ${HELM_OPTS}