diff --git a/.gitea/workflows/upload-helm.yml b/.gitea/workflows/upload-helm.yml new file mode 100644 index 0000000..e286ebf --- /dev/null +++ b/.gitea/workflows/upload-helm.yml @@ -0,0 +1,24 @@ +name: Upload Helm Chart +run-name: Uploading helm chart +on: [push] + +jobs: + Explore-Gitea-Actions: + runs-on: ubuntu-latest + env: + HELM_CHART_VERSION: "1.0.24" + steps: + - uses: actions/checkout@v2 + - name: Set up Helm + uses: azure/setup-helm@v1 + with: + version: 'v3.0.0' + - run: 'sed -i "s/version:.*/version: \"${HELM_CHART_VERSION}\"/" ./Chart/Chart.yaml' + - run: helm package ./Chart + - run: echo ${{ secrets.GITEA_TOKEN }} + - name: Upload Helm Chart + run: | + curl --request POST \ + -H "Authorization: Bearer ${{ secrets.GITEA_TOKEN }}" \ + --form "chart=@wordyne-${HELM_CHART_VERSION}.tgz" \ + https://git.cloudyne.io/api/packages/helm/helm/charts \ No newline at end of file diff --git a/Chart/Chart.yaml b/Chart/Chart.yaml index 98600e1..8f5b296 100644 --- a/Chart/Chart.yaml +++ b/Chart/Chart.yaml @@ -2,5 +2,5 @@ apiVersion: v2 name: wordyne description: Helm chart for deploying pre-built website containers to kubernetes clusters type: application -version: "0.6.13" +version: "1.0.24" appVersion: "6.2.2" diff --git a/Chart/templates-disabled/job.yaml b/Chart/templates-disabled/job.yaml index db7cb2f..a383ac7 100644 --- a/Chart/templates-disabled/job.yaml +++ b/Chart/templates-disabled/job.yaml @@ -1,5 +1,4 @@ -{{- if .Values.site.skipWPCRegistration | default false }} -{{- else }} +{{- if .Values.site.autoRegisterEnabled | default false }} apiVersion: batch/v1 kind: Job metadata: @@ -21,4 +20,5 @@ spec: imagePullSecrets: - name: pull-secret backoffLimit: 4 +{{- else }} {{- end }} \ No newline at end of file diff --git a/Chart/templates/_helpers.tpl b/Chart/templates/_helpers.tpl index 9a76373..212bf95 100644 --- a/Chart/templates/_helpers.tpl +++ b/Chart/templates/_helpers.tpl @@ -3,13 +3,17 @@ Define the application name and fullname */}} {{- define "..name" -}} -{{- .Values.site.domain | trunc 63 | replace "." "-" | trimSuffix "-" }} +{{- .Values.site.name | trunc 63 }} {{- end }} {{- define "..fullname" -}} {{ include "..name" . }} {{- end }} +{{- define "..domains" }} +{{- if .Values.site.additionalDomains }}{{ .Values.site.additionalDomains | toYaml }}{{- end }} +- {{ .Values.site.domain | replace "www." "" }} +{{- end }} {{- define "..resourcelimits" -}} resources: @@ -38,7 +42,31 @@ app.kubernetes.io/name: {{ include "..name" . }} app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} app.kubernetes.io/managed-by: {{ .Release.Service }} -cloudyne.systems/customer: {{ .Values.customer.legalName | replace " " "-" | trunc 63 | trimSuffix "-" }} -cloudyne.systems/customer-legal-id: {{ .Values.customer.legalId }} -cloudyne.systems/site: {{ .Values.site.domain }} +cloudyne.systems/customer: {{ .Values.customer.legalName | replace " " "-" | replace "," "" | trunc 63 | trimSuffix "-" | quote }} +cloudyne.systems/customer-legal-id: '{{ .Values.customer.legalId }}' +cloudyne.systems/site: {{ .Values.site.domain | quote }} +{{- end }} +{{- define "..selector-labels" -}} +cloudyne.systems/customer: {{ .Values.customer.legalName | replace " " "-" | replace "," "" | trunc 63 | trimSuffix "-" | quote }} +cloudyne.systems/site: {{ .Values.site.domain | quote }} +cloudyne.systems/component: site +{{- end }} +{{- define "..affinity-labels" -}} +podAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: cloudyne.systems/customer + operator: In + values: + - {{ .Values.customer.legalName | replace " " "-" | replace "," "" | trunc 63 | trimSuffix "-" | quote }} + - key: cloudyne.systems/site + operator: In + values: + - {{ .Values.site.domain | quote }} + - key: cloudyne.systems/component + operator: In + values: + - "site" + topologyKey: kubernetes.io/hostname {{- end }} diff --git a/Chart/templates/certificate.yaml b/Chart/templates/certificate.yaml index cc87c76..4046b8b 100644 --- a/Chart/templates/certificate.yaml +++ b/Chart/templates/certificate.yaml @@ -1,3 +1,4 @@ +{{- if and .Values.site.certificate .Values.site.certificate.certManager }} apiVersion: cert-manager.io/v1 kind: Certificate metadata: @@ -6,17 +7,21 @@ metadata: {{- include "..labels" . | nindent 8 }} spec: issuerRef: - name: cloudyne-internal-root-v2 - kind: ClusterIssuer + name: {{ .Values.site.certificate.issuerRef }} + kind: {{ .Values.site.certificate.issuerKind }} secretName: {{ include "..fullname" . }}-cert-secret - commonName: {{ .Values.site.url }} - dnsNames: - - {{ .Values.site.domain | replace "www." "" }} - - www.{{ .Values.site.domain | replace "www." "" }} - - {{ .Values.site.domain | replace "www." "" | replace "." "-" }}.eu.cust.azurecd.net - - www.{{ .Values.site.domain | replace "www." "" | replace "." "-" }}.eu.cust.azurecd.net -{{- if .Values.site.additionalIngressDomains }} - {{- range .Values.site.additionalIngressDomains }} - - {{ . }} - {{- end }} -{{- end }} + commonName: {{ .Values.site.domain }} + dnsNames: {{ include "..domains" . | nindent 8 }} +{{- else if and .Values.site.certificate .Values.site.certificate.custom .Values.site.certificate.custom.enabled }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "..fullname" . }}-cert-secret + labels: + {{- include "..labels" . | nindent 8 }} +type: kubernetes.io/tls +data: + tls.crt: {{ .Values.site.certificate.custom.cert | b64enc }} + tls.key: {{ .Values.site.certificate.custom.key | b64enc }} +{{- else }} +{{- end }} \ No newline at end of file diff --git a/Chart/templates/configmap.yaml b/Chart/templates/configmap.yaml index 3b2bc8b..214292c 100644 --- a/Chart/templates/configmap.yaml +++ b/Chart/templates/configmap.yaml @@ -5,30 +5,45 @@ metadata: labels: {{- include "..labels" . | nindent 8 }} data: - SMTP_PORT: '2525' - SMTP_AUTH: 'true' - SMTP_FROM: 'customer-noreply@v3.nu' - {{- if .Values.email }} - {{- if .Values.email.forceFromEmail }} - SMTP_FORCE_FROM: {{ .Values.email.forceFromEmail }} - {{- end }} - {{- if .Values.email.domains }} +{{- if .Values.email.smtpHost }} + SMTP_HOST: {{ .Values.email.smtpHost }} +{{- end }} +{{- if .Values.email.smtpPort }} + SMTP_PORT: {{ .Values.email.smtpPort | quote }} +{{- end }} +{{- if .Values.email.smtpAuth }} + SMTP_AUTH: 'True' + {{- if .Values.email.smtpUser }} + SMTP_USER: {{ .Values.email.smtpUser }} + {{- end }} + {{- if .Values.email.smtpPassword }} + SMTP_PASSWORD: {{ .Values.email.smtpPassword }} + {{- end }} +{{- end }} +{{- if .Values.email.smtpStarttls }} + SMTP_STARTTLS: 'True' +{{- end }} +{{- if .Values.email.defaultSender }} + SMTP_FROM: {{ .Values.email.defaultSender }} +{{- end }} +{{- if .Values.email.defaultSenderName }} + SMTP_FROM_NAME: {{ .Values.email.defaultSenderName }} +{{- end }} +{{- if .Values.email.forceSender }} + SMTP_FORCE_FROM: {{ .Values.email.forceSender }} +{{- end }} +{{- if .Values.email.domains }} SMTP_ALLOWONLY_DOMAINS: {{ .Values.email.domains | join "," }} - {{- end }} - {{- if .Values.email.allowedEmails }} +{{- end }} +{{- if .Values.email.allowedEmails }} SMTP_ALLOWONLY_EMAILS: {{ .Values.email.allowedEmails | join "," }} - {{- end }} - {{- else }} - SMTP_FORCE_FROM: "customer-noreply@v3.nu" - SMTP_FROM_NAME: "V3 Customer Mailer" - {{- end }} - WP_ENV: "{{ .Values.site.environment | default "production" }}" - WP_HOME: "https://{{ ( .Values.site.redirectDomain | default ( .Values.site.domain )) | replace "https://" "" | replace "http://" "" }}" - {{- if .Values.site.additionalEnv }} - {{- range $k, $v := .Values.site.additionalEnv }} +{{- end }} + WP_HOME: "https://{{ .Values.site.domain | replace "http://" "" | replace "https://" "" }}" +{{- if .Values.site.env }} + {{- range $k, $v := .Values.site.env }} {{ $k }}: {{ $v }} - {{- end }} - {{- end }} + {{- end }} +{{- end }} --- kind: ConfigMap apiVersion: v1 @@ -44,13 +59,26 @@ data: "webserverGroup": "unit", "applicationDir": "/app", "permissions": "0770", - "updatePermissions": true, - "importDatabase": {{ .Values.database.import | default false }}, - "databasePath": "{{ .Values.database.importPath | default "" }}", - "overwriteDatabase": {{ .Values.database.overwrite | default false }}, + "updatePermissions": {{ .Values.init.wp.updatePermissions | default false }}, + "importDatabase": {{ .Values.init.db.active | default false }}, + "databasePath": "{{ .Values.init.db.path | default "" }}", + "databaseUrl": "{{ .Values.init.db.url | default "" }}", + "importContent": {{ .Values.init.content.active | default false }}, + "contentPath": "{{ .Values.init.content.path | default "" }}", + "contentUrl": "{{ .Values.init.content.url | default "" }}", + "overwriteDatabase": {{ .Values.init.db.overwrite | default false }}, "generateSalts": true, - "activateTheme": "{{ .Values.site.theme | default .Values.site.name }}", - "convertUploadsToWebp": {{ .Values.site.enableWebpConversion | default false }}, + "activateTheme": "{{ .Values.init.wp.theme | default .Values.site.name }}", + {{- if .Values.init.asJob }} + "convertUploadsToWebp": {{ .Values.init.content.webpConverter | default true }}, + {{- else }} + "convertUploadsToWebp": {{ .Values.init.content.webpConverter | default false }}, + {{- end }} + {{- if and .Values.storage.cloud.active .Values.storage.local.active }} + "backupToCloud": true, + {{- else }} + "backupToCloud": false, + {{- end }} "convertMissingOnly": true } @@ -81,6 +109,30 @@ data: ] } }, + { + "action": { + "return": 302, + "location": "/wp/wp-admin" + }, + "match": { + "uri": [ + "/wp-admin", + "/wp-admin/*" + ] + } + }, + { + "action": { + "return": 302, + "location": "/wp/wp-login.php" + }, + "match": { + "uri": [ + "/wp-login.php", + "/wp-login.php*" + ] + } + }, { "action": { "return": 404 @@ -104,19 +156,7 @@ data: ] } }, - { - "action": { - "return": 302, - "location": "/wp/wp-admin" - }, - "match": { - "uri": [ - "/wp-admin", - "/wp-admin/*" - ] - } - }, - {{- if eq .Values.site.enableWebpRoute "true" }} + {{- if (.Values.site.webpRoute | default "true") }} { "match": { "uri": [ @@ -151,27 +191,37 @@ data: "applications": { "php": { "type": "php", + "processes": { + "max": {{ .Values.php.maxProc | default 5 }}, + "spare": {{ .Values.php.spareProc | default 1 }}, + "idle_timeout": {{ .Values.php.procIdleTimeout | default 65 }} + }, "options": { "user": { - "display_errors": "{{ .Values.site.displayErrors | default "0" }}", - "log_errors": "{{ .Values.site.logErrors | default "1" }}" + {{- if and .Values.php .Values.php.additionalValues }} + {{- range $k, $v := .Values.php.additionalValues }} + "{{ $k }}": "{{ $v }}", + {{- end }} + {{- end }} + "display_errors": "{{ .Values.php.displayErrors | default "Off" }}", + "log_errors": "{{ .Values.php.logErrors | default "On" }}" }, "admin": { "expose_php": "Off", "short_open_tag": "Off", "disable_functions": "exec,passthru,shell_exec,system,proc_open,popen,show_source", - "log_errors": "On", - {{- if and .Values.advanced .Values.advanced.php .Values.advanced.php.additionalAdminValues }} - {{- range $k, $v := .Values.advanced.php.additionalAdminValues }} - "{{ $k }}": "{{ $v }}", - {{- end }} - {{- else }} - "memory_limit": "{{ .Values.site.resources.php.memory | default "512M" }}", - "upload_max_filesize": "{{ .Values.site.resources.php.upload | default "512M" }}", - "post_max_size": "{{ .Values.site.resources.php.post | default "512M" }}", - "max_execution_time": "{{ .Values.site.resources.php.executionTime | default "300" }}", - "max_input_time": "{{ .Values.site.resources.php.inputTime | default "300" }}", - {{- end }} + "log_errors": "{{ .Values.php.logErrors | default "On" }}", + {{- if and .Values.php .Values.php.additionalAdminValues }} + {{- range $k, $v := .Values.php.additionalAdminValues }} + "{{ $k }}": "{{ $v }}", + {{- end }} + {{- else }} + "memory_limit": "{{ .Values.site.resources.php.memory | default "512M" }}", + "upload_max_filesize": "{{ .Values.site.resources.php.upload | default "512M" }}", + "post_max_size": "{{ .Values.site.resources.php.post | default "512M" }}", + "max_execution_time": "{{ .Values.site.resources.php.executionTime | default "300" }}", + "max_input_time": "{{ .Values.site.resources.php.inputTime | default "300" }}", + {{- end }} "date.timezone": "{{ .Values.customer.timezone | default "Europe/Stockholm" }}" } }, @@ -187,3 +237,20 @@ data: } } } +{{- if .Values.storage.configMap }} + {{- range .Values.storage.configMap }} + {{- if eq .type "configmap" }} +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: {{ include "..fullname" $ }}-cm-{{ .name }} + labels: + {{- include "..labels" $ | nindent 8 }} +data: + {{- range $k, $v := .files }} + {{ $v.name }}: {{ $v.content | toYaml | indent 4}} + {{- end }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/Chart/templates/database.yaml b/Chart/templates/database.yaml index eca8fb5..7a6facf 100644 --- a/Chart/templates/database.yaml +++ b/Chart/templates/database.yaml @@ -6,7 +6,7 @@ metadata: {{- include "..labels" . | nindent 8 }} spec: secretName: {{ include "..fullname" . }}-db-auth - instance: {{ .Values.database.server | default "kincaid" }} + instance: {{ .Values.site.dbInstance | default "kincaid" }} deletionProtected: yes backup: enable: No diff --git a/Chart/templates/deployment.yaml b/Chart/templates/deployment.yaml index ee1584f..e4a3474 100644 --- a/Chart/templates/deployment.yaml +++ b/Chart/templates/deployment.yaml @@ -4,7 +4,6 @@ metadata: name: {{ include "..fullname" . }} labels: {{- include "..labels" . | nindent 4 }} - cloudyne.systems/component: site spec: {{- if .Values.site.resources }} replicas: {{ .Values.site.resources.replicas | default 1 }} @@ -12,97 +11,174 @@ spec: replicas: 1 {{- end }} selector: - matchLabels: - cloudyne.systems/customer: {{ .Values.customer.legalName | replace " " "-" | lower | trunc 63 }} - cloudyne.systems/customer-legal-id: {{ .Values.customer.legalId }} - cloudyne.systems/site: {{ .Values.site.domain }} + matchLabels: + {{- include "..selector-labels" . | nindent 6 }} template: metadata: labels: - cloudyne.systems/customer: {{ .Values.customer.legalName | replace " " "-" | lower | trunc 63 }} - cloudyne.systems/customer-legal-id: {{ .Values.customer.legalId }} - cloudyne.systems/site: {{ .Values.site.domain }} + {{- include "..selector-labels" . | nindent 8 }} spec: securityContext: fsGroup: 101 volumes: - - name: cloud - persistentVolumeClaim: - claimName: pvc-{{ include "..fullname" . }} - name: serverconfig configMap: name: {{ include "..fullname" . }}-cfg + {{- if and .Values.secrets .Values.secrets.external }} + {{- range .Values.secrets.external }} + {{- if eq .type "file" }} + - name: {{ .name }} + secret: + secretName: {{- include "..fullname" $ }}-exts-{{ .name }} + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.storage.kubernetes }} + {{- range .Values.storage.kubernetes }} + - name: {{ .name }} + {{- if eq .type "secret" }} + secret: + secretName: "{{- include "..fullname" $ }}-sec-{{ .name }}" + {{- end }} + {{- if eq .type "configmap" }} + configMap: + name: "{{- include "..fullname" $ }}-sec-{{ .name }}" + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.storage.cloud.active }} + - name: cloud + persistentVolumeClaim: + claimName: pvc-{{- include "..name" . }}-cloud + {{- end }} + {{- if .Values.storage.local.active }} + - name: local + persistentVolumeClaim: + claimName: pvc-{{- include "..name" . }}-local + {{- end }} + {{- if and .Values.secrets .Values.secrets.external }} + {{- range .Values.secrets.external }} + {{- if eq .type "docker" }} imagePullSecrets: - - name: pull-secret + - name: "{{- include "..fullname" $ }}-exts-{{ .name }}" + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.storage.kubernetes }} + {{- range .Values.storage.kubernetes }} + {{- if eq .type "docker" }} + imagePullSecrets: + - name: "{{- include "..fullname" $ }}-sec-{{ .name }}" + {{- end }} + {{- end }} + {{- end }} + {{- if not .Values.init.asJob }} initContainers: - - name: deploy + {{- if and .Values.storage.cloud.active .Values.storage.local.active .Values.storage.local.cloneCloud }} + - name: init-local-storage securityContext: allowPrivilegeEscalation: false runAsUser: 0 - image: "cloudyne.azurecr.io/buildahome/{{ .Values.site.name | default ( .Values.site.domain | replace "." "-" ) }}:{{ .Values.site.imageTag | default "latest" }}" + image: cloudyne/ubuntu-ci:latest + command: ["python3"] + args: ["/usr/local/bin/storage-clone", "/mnt/cloud", "/mnt/local"] imagePullPolicy: Always volumeMounts: - name: cloud - mountPath: /full-cloud + mountPath: /mnt/cloud + - name: local + mountPath: /mnt/local + {{- end }} + - name: init-site + securityContext: + allowPrivilegeEscalation: false + runAsUser: 0 + image: "{{ .Values.site.image }}" + imagePullPolicy: Always + volumeMounts: - name: serverconfig mountPath: /init-go/config.json subPath: init.json - {{- if .Values.storage.wpContent }} - {{- range $v := .Values.storage.wpContent }} - - name: cloud - mountPath: "/app/web/app/{{ $v }}" - subPath: "{{ $v }}" + {{- if .Values.storage.local.active }} + {{- range .Values.storage.folders }} + - name: local + mountPath: "/app/web/app/{{ . }}" + subPath: "{{ . }}" {{- end }} - {{- end }} - {{- if .Values.storage.additionalMounts }} - {{- range $v := .Values.storage.additionalMounts }} + {{- if .Values.storage.cloud.active }} - name: cloud - mountPath: {{ $v.localPath }} - subPath: {{ $v.cloudPath }} + mountPath: "/mnt/cloud" {{- end }} - {{- end }} + {{- else }} + {{- if .Values.storage.cloud.active }} + {{- range .Values.storage.folders }} + - name: cloud + mountPath: "/app/web/app/{{ . }}" + subPath: "{{ . }}" + {{- end }} + {{- end }} + {{- end }} + envFrom: - configMapRef: name: {{ include "..fullname" . }}-env + {{- if and .Values.secrets .Values.secrets.external }} + {{- range .Values.secrets.external }} + {{- if eq .type "env" }} + - secretRef: + name: "{{- include "..fullname" $ }}-exts-{{ .name }}" + {{- end }} + {{- end }} + {{- end }} - secretRef: name: {{ include "..fullname" . }}-db-auth - - secretRef: - name: global-secrets - command: [ "/init-go/init-go" ] + command: ["sh"] + args: ["-c", "/init-go/init-go"] + {{- end }} containers: - name: wordpress securityContext: runAsUser: 101 - image: "cloudyne.azurecr.io/buildahome/{{ .Values.site.name | default ( .Values.site.domain | replace "." "-" ) }}:{{ .Values.site.imageTag | default "latest" }}" + image: "{{ .Values.site.image }}" imagePullPolicy: Always volumeMounts: - - name: serverconfig + - name: serverconfig mountPath: /docker-entrypoint.d/unit.json subPath: unit.json - {{- if .Values.storage.wpContent }} - {{- range $v := .Values.storage.wpContent }} - - name: cloud - mountPath: "/app/web/app/{{ $v }}" - subPath: "{{ $v }}" + {{- if .Values.storage.local.active }} + {{- range .Values.storage.folders }} + - name: local + mountPath: "/app/web/app/{{ . }}" + subPath: "{{ . }}" {{- end }} - {{- end }} - {{- if .Values.storage.additionalMounts }} - {{- range $v := .Values.storage.additionalMounts }} + {{- if .Values.storage.cloud.active }} - name: cloud - mountPath: {{ $v.localPath }} - subPath: {{ $v.cloudPath }} + mountPath: "/mnt/cloud" {{- end }} - {{- end }} + {{- else }} + {{- if .Values.storage.cloud.active }} + {{- range .Values.storage.folders }} + - name: cloud + mountPath: "/app/web/app/{{ . }}" + subPath: "{{ . }}" + {{- end }} + {{- end }} + {{- end }} + {{- include "..resourcelimits" . | nindent 10 }} envFrom: - configMapRef: name: {{ include "..fullname" . }}-env + {{- if and .Values.secrets .Values.secrets.external }} + {{- range .Values.secrets.external }} + {{- if eq .type "env" }} + - secretRef: + name: "{{- include "..fullname" $ }}-exts-{{ .name }}" + {{- end }} + {{- end }} + {{- end }} - secretRef: name: {{ include "..fullname" . }}-db-auth - - secretRef: - name: global-secrets - {{- include "..resourcelimits" . | nindent 10 }} ports: - containerPort: 8080 name: http - protocol: TCP - + protocol: TCP \ No newline at end of file diff --git a/Chart/templates/externalsecret.yaml b/Chart/templates/externalsecret.yaml index 6dc53cb..d5dad97 100644 --- a/Chart/templates/externalsecret.yaml +++ b/Chart/templates/externalsecret.yaml @@ -1,60 +1,37 @@ -apiVersion: external-secrets.io/v1beta1 -kind: ExternalSecret -metadata: - name: {{ include "..fullname" . }}-ex-gl-secret - labels: - {{- include "..labels" . | nindent 8 }} -spec: - refreshInterval: 4h - secretStoreRef: - kind: ClusterSecretStore - name: az-cluster-store - target: - name: global-secrets - creationPolicy: Orphan - template: - metadata: - labels: - app.kubernetes.io/managed-by: External-Secrets - data: - - secretKey: COMPOSER_AUTH - remoteRef: - key: secret/GITLAB-COMPOSER-AUTH - - secretKey: SMTP_USER - remoteRef: - key: secret/SMTP-USER - - secretKey: SMTP_PASS - remoteRef: - key: secret/SMTP-PASSWORD - - secretKey: SMTP_HOST - remoteRef: - key: secret/SMTP-HOST - - secretKey: WPC_REGISTRATION_SECRET - remoteRef: - key: secret/WPC-REGISTRATION-SECRET +{{- if and .Values.secrets .Values.secrets.external }} + {{- range .Values.secrets.external }} --- apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: - name: {{ include "..fullname" . }}-ex-pull-secret + name: {{ include "..fullname" $ }}-ext-{{ .name }} labels: - {{- include "..labels" . | nindent 8 }} + {{- include "..labels" $ | nindent 8 }} spec: - refreshInterval: 4h + refreshInterval: {{ .refreshInterval | default "10h" }} secretStoreRef: + {{- if .ref.clusterSecretStore }} kind: ClusterSecretStore - name: az-cluster-store + name: {{ .ref.clusterSecretStore }} + {{- else }} + kind: SecretStore + name: {{ .ref.secretStore }} + namespace: {{ .ref.secretStoreNamespace }} + {{- end }} target: - name: pull-secret + name: {{ include "..fullname" $ }}-exts-{{ .name }} template: + {{- if eq .type "docker"}} + type: kubernetes.io/dockerconfigjson + {{- end }} metadata: labels: app.kubernetes.io/managed-by: External-Secrets - type: kubernetes.io/dockerconfigjson - data: - .dockerconfigjson: "{{`{{ .dockerconfig | toString }}`}}" - creationPolicy: Orphan data: - - secretKey: dockerconfig + {{- range $v := .items }} + - secretKey: {{ $v.target }} remoteRef: - key: secret/CLDY-CR-PULL-TOKEN + key: {{ $v.source }} + {{- end }} + {{- end }} +{{- end }} diff --git a/Chart/templates/ingress.yaml b/Chart/templates/ingress.yaml index c45e744..5f6f3c5 100644 --- a/Chart/templates/ingress.yaml +++ b/Chart/templates/ingress.yaml @@ -9,72 +9,27 @@ metadata: {{- include "..labels" . | nindent 4 }} spec: ingressClassName: nginx - tls: +{{- if or .Values.site.certificate.certManager .Values.site.certificate.importCert }} + tls: - secretName: {{ include "..fullname" . }}-cert-secret - hosts: - - {{ .Values.site.domain | replace "www." "" }} - - www.{{ .Values.site.domain | replace "www." "" }} - - {{ .Values.site.domain | replace "www." "" | replace "." "-" }}.eu.cust.azurecd.net - - www.{{ .Values.site.domain | replace "www." "" | replace "." "-" }}.eu.cust.azurecd.net -{{- if .Values.site.additionalIngressDomains }} - {{- range .Values.site.additionalIngressDomains }} - - {{ . }} - {{- end }} -{{- end }} - + hosts: {{ include "..domains" . | nindent 6 }} +{{- else if .Values.site.certificate.existingCert }} + tls: + - secretName: {{ .Values.site.certificate.existingCertName }} + hosts: {{ include "..domains" . | nindent 6 }} +{{- end }} rules: - - host: {{ .Values.site.domain | replace "www." "" }} + {{- range include "..domains" . | split "\n" }} + {{- if ne . "" }} + - host: {{ . | replace "- " ""}} http: paths: - - path: / - pathType: Prefix - backend: - service: - name: {{ include "..fullname" . }} - port: - number: 80 - - host: www.{{ .Values.site.domain | replace "www." "" }} - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: {{ include "..fullname" . }} - port: - number: 80 - - host: {{ .Values.site.domain | replace "www." "" | replace "." "-" }}.eu.cust.azurecd.net - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: {{ include "..fullname" . }} - port: - number: 80 - - - host: www.{{ .Values.site.domain | replace "www." "" | replace "." "-" }}.eu.cust.azurecd.net - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: {{ include "..fullname" . }} - port: - number: 80 - {{- if .Values.site.additionalIngressDomains }} - {{- range .Values.site.additionalIngressDomains }} - - host: {{ . }} - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: {{ include "..fullname" $ }} - port: - number: 80 - {{- end }} + - path: / + pathType: Prefix + backend: + service: + name: {{ include "..fullname" $ }} + port: + number: 80 + {{- end }} {{- end }} \ No newline at end of file diff --git a/Chart/templates/job.yaml b/Chart/templates/job.yaml new file mode 100644 index 0000000..693adf4 --- /dev/null +++ b/Chart/templates/job.yaml @@ -0,0 +1,131 @@ +{{- if .Values.init.asJob }} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "..fullname" . }}-initializer + labels: + {{- include "..labels" . | nindent 4 }} + cloudyne.systems/component: site-init +spec: + backoffLimit: 2 + template: + spec: + restartPolicy: "OnFailure" + affinity: {{ include "..affinity-labels" . | nindent 8 }} + securityContext: + fsGroup: 101 + volumes: + - name: serverconfig + configMap: + name: {{ include "..fullname" . }}-cfg + {{- if and .Values.secrets .Values.secrets.external }} + {{- range .Values.secrets.external }} + {{- if eq .type "file" }} + - name: {{ .name }} + secret: + secretName: {{- include "..fullname" $ }}-exts-{{ .name }} + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.storage.kubernetes }} + {{- range .Values.storage.kubernetes }} + - name: {{ .name }} + {{- if eq .type "secret" }} + secret: + secretName: "{{- include "..fullname" $ }}-sec-{{ .name }}" + {{- end }} + {{- if eq .type "configmap" }} + configMap: + name: "{{- include "..fullname" $ }}-sec-{{ .name }}" + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.storage.cloud.active }} + - name: cloud + persistentVolumeClaim: + claimName: pvc-{{- include "..name" . }}-cloud + {{- end }} + {{- if .Values.storage.local.active }} + - name: local + persistentVolumeClaim: + claimName: pvc-{{- include "..name" . }}-local + {{- end }} + {{- if and .Values.secrets .Values.secrets.external }} + {{- range .Values.secrets.external }} + {{- if eq .type "docker" }} + imagePullSecrets: + - name: "{{- include "..fullname" $ }}-exts-{{ .name }}" + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.storage.kubernetes }} + {{- range .Values.storage.kubernetes }} + {{- if eq .type "docker" }} + imagePullSecrets: + - name: "{{- include "..fullname" $ }}-sec-{{ .name }}" + {{- end }} + {{- end }} + {{- end }} + {{- if and .Values.storage.cloud.active .Values.storage.local.active .Values.storage.local.cloneCloud }} + initContainers: + - name: init-local-storage + securityContext: + allowPrivilegeEscalation: false + runAsUser: 0 + image: cloudyne/ubuntu-ci:latest + command: ["python3"] + args: ["/usr/local/bin/storage-clone", "/mnt/cloud", "/mnt/local"] + imagePullPolicy: IfNotPresent + volumeMounts: + - name: cloud + mountPath: /mnt/cloud + - name: local + mountPath: /mnt/local + {{- end }} + containers: + - name: init-site + securityContext: + allowPrivilegeEscalation: false + runAsUser: 0 + image: "{{ .Values.site.image }}" + imagePullPolicy: IfNotPresent + volumeMounts: + - name: serverconfig + mountPath: /init-go/config.json + subPath: init.json + {{- if .Values.storage.local.active }} + {{- range .Values.storage.folders }} + - name: local + mountPath: "/app/web/app/{{ . }}" + subPath: "{{ . }}" + {{- end }} + {{- if .Values.storage.cloud.active }} + - name: cloud + mountPath: "/mnt/cloud" + {{- end }} + {{- else }} + {{- if .Values.storage.cloud.active }} + {{- range .Values.storage.folders }} + - name: cloud + mountPath: "/app/web/app/{{ . }}" + subPath: "{{ . }}" + {{- end }} + {{- end }} + {{- end }} + + envFrom: + - configMapRef: + name: {{ include "..fullname" . }}-env + {{- if and .Values.secrets .Values.secrets.external }} + {{- range .Values.secrets.external }} + {{- if eq .type "env" }} + - secretRef: + name: "{{- include "..fullname" $ }}-exts-{{ .name }}" + {{- end }} + {{- end }} + {{- end }} + - secretRef: + name: {{ include "..fullname" . }}-db-auth + command: ["sh"] + args: ["-c", "/init-go/init-go"] +{{- end }} \ No newline at end of file diff --git a/Chart/templates/persistentvolume.yaml b/Chart/templates/persistentvolume.yaml index bc86d81..dd91279 100644 --- a/Chart/templates/persistentvolume.yaml +++ b/Chart/templates/persistentvolume.yaml @@ -1,38 +1,39 @@ +{{ if .Values.storage.cloud.active }} apiVersion: v1 kind: PersistentVolume metadata: - name: pv-{{ include "..fullname" . }} - labels: - {{- include "..labels" . | nindent 8 }} + name: pv-{{ include "..name" . }}-cloud + labels: + {{- include "..labels" . | nindent 4 }} spec: - accessModes: - - ReadWriteOnce - capacity: - storage: {{ .Values.site.resources.disk | default "5Gi" }} - csi: - driver: blob.csi.azure.com - nodeStageSecretRef: - name: cloudyne{{ .Values.storage.class | default "premium01" }}-credentials - namespace: blob-csi - volumeAttributes: - containername: {{ .Values.storage.container | default ( .Values.site.domain | replace "." "-") }} - csi.storage.k8s.io/pv/name: pv-{{ include "..fullname" . }} - csi.storage.k8s.io/pvc/namespace: {{ include "..fullname" . }} - secretnamespace: {{ include "..fullname" . }} - skuName: {{ .Values.storage.type | default "Premium_LRS" }} - volumeHandle: {{ .Values.storage.class | default "premium01" }}-retain_{{ include "..fullname" . }} - mountOptions: - - -o allow_other - - --file-cache-timeout-in-seconds=120 - - --use-attr-cache=true - - --cancel-list-on-mount-seconds=10 - - -o attr_timeout=120 - - -o entry_timeout=120 - - -o negative_timeout=120 - - --log-level=LOG_WARNING - - --cache-size-mb=3500 - - -o uid=101 - persistentVolumeReclaimPolicy: Retain - storageClassName: {{ .Values.storage.class | default "premium01" }}-retain - volumeMode: Filesystem ---- \ No newline at end of file + accessModes: + - ReadWriteOnce + capacity: + storage: {{ .Values.site.resources.disk }} + csi: + driver: {{ .Values.storage.cloud.driver | default "blob.csi.azure.com" }} + nodeStageSecretRef: + name: {{ .Values.storage.cloud.account }}-credentials + namespace: blob-csi + volumeAttributes: + containername: {{ .Values.storage.cloud.container }} + csi.storage.k8s.io/pv/name: pv-{{ include "..name" . }}-cloud + csi.storage.k8s.io/pvc/namespace: {{ .Release.Namespace }} + secretnamespace: {{ .Release.Namespace }} + skuName: {{ .Values.storage.cloud.sku | default "Premium_LRS" }} + volumeHandle: {{ .Values.storage.cloud.class }}_{{ .Values.storage.cloud.container }} + mountOptions: + - -o allow_other + - --file-cache-timeout-in-seconds=120 + - --use-attr-cache=true + - --cancel-list-on-mount-seconds=10 + - -o attr_timeout=120 + - -o entry_timeout=120 + - -o negative_timeout=120 + - --log-level=LOG_WARNING + - --cache-size-mb=3500 + - -o uid=101 + persistentVolumeReclaimPolicy: Retain + storageClassName: {{ .Values.storage.cloud.class }} + volumeMode: Filesystem +{{- end }} diff --git a/Chart/templates/persistentvolumeclaim.yaml b/Chart/templates/persistentvolumeclaim.yaml index f30c488..3989e0f 100644 --- a/Chart/templates/persistentvolumeclaim.yaml +++ b/Chart/templates/persistentvolumeclaim.yaml @@ -1,22 +1,37 @@ +{{- if .Values.storage.cloud.active }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: pvc-{{ include "..name" . }}-cloud + labels: + {{- include "..labels" . | nindent 4 }} + annotations: + volume.beta.kubernetes.io/storage-provisioner: {{ .Values.storage.cloud.driver }} + volume.kubernetes.io/storage-provisioner: {{ .Values.storage.cloud.driver }} +spec: + volumeMode: Filesystem + volumeName: pv-{{ include "..name" . }}-cloud + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .Values.site.resources.disk }} + storageClassName: {{ .Values.storage.cloud.class }} +{{- end }} +{{- if .Values.storage.local.active }} --- apiVersion: v1 kind: PersistentVolumeClaim metadata: - annotations: - volume.beta.kubernetes.io/storage-provisioner: blob.csi.azure.com - volume.kubernetes.io/storage-provisioner: blob.csi.azure.com - labels: - {{- include "..labels" . | nindent 8 }} - name: pvc-{{ include "..fullname" . }} + name: pvc-{{ include "..name" . }}-local + labels: + {{- include "..labels" . | nindent 4 }} spec: - volumeMode: Filesystem - volumeName: pv-{{ include "..fullname" . }} - accessModes: - - ReadWriteOnce - resources: - requests: - storage: {{ .Values.site.resources.disk | default "5Gi" }} - -{{- if and .Values.storage .Values.storage.class }} - storageClassName: {{ .Values.storage.class | default "premium01" }}-retain + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .Values.site.resources.disk }} + storageClassName: {{ .Values.storage.local.class }} {{- end }} \ No newline at end of file diff --git a/Chart/templates/secret.yaml b/Chart/templates/secret.yaml new file mode 100644 index 0000000..bf48703 --- /dev/null +++ b/Chart/templates/secret.yaml @@ -0,0 +1,17 @@ +{{- if .Values.storage.kubernetes }} + {{- range .Values.storage.kubernetes }} + {{- if eq .type "secret" }} +--- +kind: Secret +apiVersion: v1 +metadata: + name: {{ include "..fullname" $ }}-sec-{{ .name }} + labels: + {{- include "..labels" $ | nindent 8 }} +stringData: + {{- range $k, $v := .files }} + {{ $v.name }}: {{ $v.content | toYaml | indent 4}} + {{- end }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/Chart/templates/service.yaml b/Chart/templates/service.yaml index ecc4fa4..6b6191c 100644 --- a/Chart/templates/service.yaml +++ b/Chart/templates/service.yaml @@ -10,7 +10,5 @@ spec: port: 80 targetPort: 8080 selector: - cloudyne.systems/customer: {{ .Values.customer.legalName | replace " " "-" | lower | trunc 63 }} - cloudyne.systems/customer-legal-id: {{ .Values.customer.legalId }} - cloudyne.systems/site: {{ .Values.site.domain }} + {{- include "..selector-labels" . | nindent 4 }} type: ClusterIP diff --git a/Chart/values.yaml b/Chart/values.yaml index 2a8ea83..d4ae2f9 100644 --- a/Chart/values.yaml +++ b/Chart/values.yaml @@ -1,111 +1,41 @@ customer: - # The (dns-compliant) customer name (Required) - # name: dns-compliant-customer-name + # The customer name (DNS-Compliant) + name: customerdomain-tld - # The legal name of the customer (Required) - # legalName: Customer Name Ltd + # The customer legal name + legalName: Customer Name Ltd. - # The legal ID of the customer (Required) - # legalId: 112233-4455 + # The customer legal ID + legalId: 112233-4455 - # The timezone for the customer + # The customer timezone timezone: "Europe/Stockholm" -email: - # Force a given sender email - # forceSender: "example@email.com" - - # Set a default sender/display name - # defaultSender: "customer-noreply@v3.nu" - # defaultSenderName: "Customer Name" - - # Specify allowed domains/emails to use as senders - # domains: - # - customer.tld - # emails: - # - mail@customer.tld - -# Database configuration -database: - # Database server to use - server: kincaid - - # Import database from file if not already imported - import: false - importPath: "/full-cloud/import.sql" - overwriteExisting: false - -# Storage Settings -storage: - # The storage class to use for the site - # Default: premium01 - class: "premium01" - - # The storage type to use for the site - # Default: Premium_LRS - type: "Premium_LRS" - - # The storage container to use for the site (REQUIRED) - # Default: - - # container: "company-tld" - - # Skip WPC Auto-registration - # Default: false - # skipWPCRegistration: false - - # WP Content Folders - wpContent: - - uploads - - languages - - additionalMounts: {} - # - cloudPath: uploads - # localPath: /app/web/app/uploads - site: - # The name of the repository/composerpackage/dockerimage - # Default: domain.replace('.', '-') - # name: "customer-tld" + name: "customerdomain-tld" + domain: "customerdomain.tld" + additionalDomains: [] - # Tag of the container to deploy - # imageTag: "latest" - - # The primary domain/TLD where the site will be available - # domain: customer.tld + image: "ghcr.io/cloudynes/php-bedrock:8.0-alpine" - # The main url (subdomain) for the site - # Only needed if it differs from the domain - # ex. - # redirectDomain: tempdomain.customer.tld + env: + WP_ENV: "production" + + webpRoute: true + dbInstance: "" - # Additional ingress domains that should all - # point to the same site - # Defaults are: - # - . - # - www.. - # - -.eu.cust.azurecd.net - # - www--.eu.cust.azurecd.net - additionalIngressDomains: [] + certificate: + certManager: false + # issuerRef: "" + # issuerKind: "" + existingCert: false + # existingCertName: "" + importCert: false + # importCertValue: | + # .... + # importKeyValue: | + # .... - # PHP Version - phpVersion: "8.0" - - # Set environment (production/test/staging) - # Default: production - environment: production - - # Additional env vars - # additionalEnv: - # MY_ENV_VAR: "value" - additionalEnv: {} - - # Enable the route for trying .webp files before images - enableWebpRoute: "true" - - # Enable the automatic conversion of WebP images - enableWebpConversion: "true" - - # The resource limits for the site resources: replicas: 1 php: @@ -121,16 +51,115 @@ site: avg: 256Mi peak: 512Mi disk: 5Gi + +secrets: + external: [] + # - name: "ex-gl-secret" + # type: "env" + # ref: + # secretStore: "" + # clusterSecretStore: "az-cluster-store" + # target: "global-secrets" + # items: + # - source: secret/SMTP-USER + # target: SMTP_USER + # - source: secret/SMTP-PASSWORD + # target: SMTP_PASS + # - source: secret/SMTP-HOST + # target: SMTP_HOST + # - name: "ex-pull-secret" + # type: "docker" + # ref: + # secretStore: "" + # secretStoreNamespace: "" + # clusterSecretStore: "az-cluster-store" + # target: "pull-secret" + # items: + # - source: secret/PULL-TOKEN + # target: dockerconfig + + +storage: + kubernetes: + - name: "pull-secret" + type: "secret" + files: + - name: .dockerconfigjson + content: | + {"auths":{"ghcr.io":{"username":"ghcr.io","password":"ghcr.io","auth":"ghcr.io"}}} + # - name: "secret01" + # type: "secret" + # files: + # - name: x + # mount: /x.txt + # content: | + # Hello World + # - name: "config01" + # type: configmap + # files: + # - name: x + # mount: /x.txt + # content: | + # test: + # data: + # - x + # - y + # - z + cloud: + active: false + driver: "blob.csi.azure.com" + account: "azstorage11" + sku: "Premium_LRS" + class: "azstorage11class-retain" + container: "customerdomain-tld" + + local: + active: true + cloneCloud: False + class: "longhorn" + + folders: + - uploads + - languages - # Log Errors - logErrors: "1" +init: + asJob: false + wp: + theme: "abctheme" + updatePermissions: true + db: + active: false + overwrite: false + # path: "/full-cloud/init.sql" + # url: "https://url.to/init.sql" + content: + active: false + overwrite: false + webpConverter: false + # path: "/full-cloud/content.zip" + # url: "https://url.to/content.zip" - # Display Errors - displayErrors: "0" +email: + smtpHost: "" + smtpPort: "" + smtpAuth: false + smtpUser: "" + smtpPassword: "" + smtpStarttls: false -# advanced: - # php: - # displayErrors: "0" - # logErrors: "1" - # additionalAdminValues: {} + forceSender: "" + defaultSender: "" + defaultSenderName: "" + domains: + - domain + emails: + - email +php: + maxProc: 5 + spareProc: 2 + procIdleTimeout: 65 + logErrors: "On" + displayErrors: "Off" + additionalValues: {} + additionalAdminValues: {}