diff --git a/ansible/.gitignore b/ansible/.gitignore index f436f12..b51bab2 100644 --- a/ansible/.gitignore +++ b/ansible/.gitignore @@ -1 +1,2 @@ .vault-pass.txt +.venv diff --git a/ansible/inventory.ini b/ansible/inventory.ini index 243872d..4765513 100644 --- a/ansible/inventory.ini +++ b/ansible/inventory.ini @@ -1,2 +1,2 @@ [ovh] -ovh1 ansible_host=5.39.72.167 ansible_port=7511 ansible_user=ubuntu firewall_ports=80,443,6443,7511 +ovh1 ansible_host=5.39.72.167 ansible_port=7511 ansible_user=ubuntu firewall_ports=22,80,443,6443,7511 diff --git a/ansible/k3s.yml b/ansible/k3s.yml index 7d622a9..986bd79 100644 --- a/ansible/k3s.yml +++ b/ansible/k3s.yml @@ -14,3 +14,49 @@ curl -sfL https://get.k3s.io | sh - args: creates: /usr/local/bin/k3s + + # Open port 22 on Traefik. This is the official k3s way to do it - deploy a + # HelmChartConfig resource - but it can't easily be provisioned with + # kustomize for the usual namePrefix reasons. + # + # If traefik upgrade fails because CRDs are missing, see: + # https://github.com/k3s-io/k3s/issues/9534#issuecomment-1958116409 + - name: Deploy Traefik HelmChart manifest with SSH entrypoint for k3s + become: true + ansible.builtin.template: + src: templates/helm-chart-traefik-gitea.yaml + dest: /var/lib/rancher/k3s/server/manifests/traefik-gitea.yaml + mode: 0644 + + - name: Get Traefik service + kubernetes.core.k8s_info: + api_version: v1 + kind: Service + namespace: kube-system + name: traefik + kubeconfig: "~/.kube/config-ovh" # a bit brittle but ensures the correct cluster is used + delegate_to: localhost + become: false + register: traefik_service + + - name: Expose SSH port 22 on Traefik service if not present + kubernetes.core.k8s_json_patch: + api_version: v1 + kind: Service + name: traefik + namespace: kube-system + kubeconfig: "~/.kube/config-ovh" # see comment above + patch: + - op: add + path: /spec/ports/- + value: + name: ssh + port: 22 + protocol: TCP + targetPort: 22 + delegate_to: localhost + become: false + when: > + traefik_service.resources[0].spec.ports | + selectattr('port', 'equalto', 22) | list | length == 0 + run_once: true diff --git a/ansible/templates/helm-chart-traefik-gitea.yaml b/ansible/templates/helm-chart-traefik-gitea.yaml new file mode 100644 index 0000000..94575bb --- /dev/null +++ b/ansible/templates/helm-chart-traefik-gitea.yaml @@ -0,0 +1,11 @@ +apiVersion: helm.cattle.io/v1 +kind: HelmChartConfig +metadata: + name: traefik + namespace: kube-system +spec: + valuesContent: |- + ports: + ssh: + port: 22 + exposedPort: 22 diff --git a/deploy/base/kustomization.yaml b/deploy/base/kustomization.yaml index 1b3aa9d..2d3fef8 100644 --- a/deploy/base/kustomization.yaml +++ b/deploy/base/kustomization.yaml @@ -62,9 +62,6 @@ resources: - deploy-element.yaml - svc-element.yaml -- statefulset-gitea.yaml -- svc-gitea.yaml - - deploy-drone.yaml - svc-drone.yaml - deploy-drone-runner.yaml @@ -81,13 +78,6 @@ resources: - svc-solar-toolkit-gateway.yaml configMapGenerator: -- name: gitea-scripts - files: - - init-directory-structure.sh=resources/gitea-init-directory-structure.sh - - setup.sh=resources/gitea-setup.sh - options: - labels: - app: gitea - name: invidious-scripts files: - init.sh=resources/invidious-init.sh diff --git a/deploy/prod-ovh/cert-ingress-tls.yaml b/deploy/prod-ovh/cert-ingress-tls.yaml index b857723..64e7790 100644 --- a/deploy/prod-ovh/cert-ingress-tls.yaml +++ b/deploy/prod-ovh/cert-ingress-tls.yaml @@ -12,3 +12,9 @@ spec: dnsNames: - k3s.netflux.io - grafana-k3s.netflux.io + - git-k3s.netflux.io + - git.netflux.io + - grafana.netflux.io + - netflux.io + - caldav-k3s.netflux.io + - caldav.netflux.io diff --git a/deploy/prod-ovh/ingress-route-gitea-ssh.yaml b/deploy/prod-ovh/ingress-route-gitea-ssh.yaml new file mode 100644 index 0000000..a7d186b --- /dev/null +++ b/deploy/prod-ovh/ingress-route-gitea-ssh.yaml @@ -0,0 +1,15 @@ +# Traefik ingress route for routing TCP traffic to gitea service. +--- +apiVersion: traefik.io/v1alpha1 +kind: IngressRouteTCP +metadata: + name: gitea-ssh +spec: + entryPoints: + - ssh + routes: + - match: HostSNI(`*`) + services: + - name: prod-gitea + namespace: default + port: 22 diff --git a/deploy/prod-ovh/ingress.yaml b/deploy/prod-ovh/ingress.yaml index 37cb4f6..6dbe80f 100644 --- a/deploy/prod-ovh/ingress.yaml +++ b/deploy/prod-ovh/ingress.yaml @@ -32,6 +32,16 @@ spec: name: grafana port: name: service + - host: git.netflux.io + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: gitea + port: + name: http tls: - hosts: - k3s.netflux.io diff --git a/deploy/prod-ovh/kustomization.yaml b/deploy/prod-ovh/kustomization.yaml index 793311d..91b3649 100644 --- a/deploy/prod-ovh/kustomization.yaml +++ b/deploy/prod-ovh/kustomization.yaml @@ -32,7 +32,19 @@ resources: - svc-db.yaml - ingress.yaml +- statefulset-gitea.yaml +- svc-gitea.yaml +- ingress-route-gitea-ssh.yaml + + configMapGenerator: +- name: gitea-scripts + files: + - init-directory-structure.sh=resources/gitea-init-directory-structure.sh + - setup.sh=resources/gitea-setup.sh + options: + labels: + app: gitea - name: prometheus-server namespace: prometheus behavior: merge @@ -67,6 +79,15 @@ secretGenerator: files: - admin-user=secrets/grafana-admin-user - admin-password=secrets/grafana-admin-password +- name: gitea-config + files: + - admin-username=secrets/gitea-admin-username + - admin-password=secrets/gitea-admin-password + - admin-email=secrets/gitea-admin-email + - config.ini=secrets/gitea-config.ini + options: + labels: + app: gitea patches: # Patch prometheus-server pod to mount the secrets volume. diff --git a/deploy/prod-ovh/resources/gitea-init-directory-structure.sh b/deploy/prod-ovh/resources/gitea-init-directory-structure.sh new file mode 100644 index 0000000..62c12dd --- /dev/null +++ b/deploy/prod-ovh/resources/gitea-init-directory-structure.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail + +echo "Initializing directory structure..." + +mkdir -p /data/git/.ssh +chmod -R 700 /data/git/.ssh + +echo "Creating GITEA_CUSTOM=$GITEA_CUSTOM ..." +mkdir -p "$GITEA_CUSTOM" +chmod 0500 "$GITEA_CUSTOM" + +echo "Creating GITEA_TEMP=$GITEA_TEMP ..." +mkdir -p "$GITEA_TEMP" +chmod ug+rwx "$GITEA_TEMP" + +echo "Done" diff --git a/deploy/prod-ovh/resources/gitea-setup.sh b/deploy/prod-ovh/resources/gitea-setup.sh new file mode 100644 index 0000000..40a71c3 --- /dev/null +++ b/deploy/prod-ovh/resources/gitea-setup.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail + +echo "Running Gitea migrations..." + +gitea migrate + +echo "Setting up Gitea admin user..." + +# https://gitea.com/gitea/helm-chart/src/commit/80032dfc5c34950edea384e0227f7ab7c994f4ef/templates/gitea/init.yaml#L54 +function configure_admin_user() { + local account_id=$(gitea admin user list --admin | grep -e "\s\+${GITEA_ADMIN_USERNAME}\s\+" | awk -F " " "{printf \$1}") + if [[ -z "${account_id}" ]]; then + echo "No admin user '${GITEA_ADMIN_USERNAME}' found. Creating now..." + gitea admin user create --admin --username "${GITEA_ADMIN_USERNAME}" --password "${GITEA_ADMIN_PASSWORD}" --email "${GITEA_ADMIN_EMAIL}" --must-change-password=false + echo '...created.' + else + echo "Admin account '${GITEA_ADMIN_USERNAME}' already exists. Running update to sync password..." + gitea admin user change-password --username "${GITEA_ADMIN_USERNAME}" --password "${GITEA_ADMIN_PASSWORD}" + echo '...password sync done.' + fi +} + +configure_admin_user + +echo "Done" diff --git a/deploy/base/statefulset-gitea.yaml b/deploy/prod-ovh/statefulset-gitea.yaml similarity index 100% rename from deploy/base/statefulset-gitea.yaml rename to deploy/prod-ovh/statefulset-gitea.yaml diff --git a/deploy/base/svc-gitea.yaml b/deploy/prod-ovh/svc-gitea.yaml similarity index 100% rename from deploy/base/svc-gitea.yaml rename to deploy/prod-ovh/svc-gitea.yaml diff --git a/deploy/prod/ingress.yaml b/deploy/prod/ingress.yaml index 9b6879b..94e5b30 100644 --- a/deploy/prod/ingress.yaml +++ b/deploy/prod/ingress.yaml @@ -12,7 +12,6 @@ - grafana.netflux.io - tube.netflux.io - element.netflux.io - - git.netflux.io - drone.netflux.io - synapse.netflux.io - netflux.io @@ -28,9 +27,6 @@ - op: replace path: /spec/rules/2/host value: element.netflux.io -- op: replace - path: /spec/rules/3/host - value: git.netflux.io - op: replace path: /spec/rules/4/host value: drone.netflux.io