Merge branch 'master' of gitlab.com:domaindrivenarchitecture/c4k-nextcloud

This commit is contained in:
jem 2021-11-12 09:14:16 +01:00
commit f943994afa
15 changed files with 169 additions and 99 deletions

View file

@ -47,7 +47,7 @@ test-schema:
stage: build_and_test stage: build_and_test
script: script:
- lein uberjar - lein uberjar
- java -jar target/uberjar/c4k-nextcloud-standalone.jar valid-config.edn valid-auth.edn | kubeconform --kubernetes-version 1.19.0 --strict --skip Certificate - - java -jar target/uberjar/c4k-nextcloud-standalone.jar valid-config.edn valid-auth.edn | kubeconform --kubernetes-version 1.19.0 --strict --skip "Certificate,CronJob" -
artifacts: artifacts:
paths: paths:
- target/uberjar - target/uberjar

View file

@ -1,5 +1,42 @@
# meissa-cloud # convention 4 kubernetes: c4k-nextcloud
[![Clojars Project](https://img.shields.io/clojars/v/org.domaindrivenarchitecture/c4k-nextcloud.svg)](https://clojars.org/org.domaindrivenarchitecture/c4k-nextcloud) [![pipeline status](https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud/badges/master/pipeline.svg)](https://gitlab.com/domaindrivenarchitecture/c4k-nextcloud/-/commits/master)
# backup manuell triggern [<img src="https://domaindrivenarchitecture.org/img/delta-chat.svg" width=20 alt="DeltaChat"> chat over e-mail](mailto:buero@meissa-gmbh.de?subject=community-chat) | [<img src="https://meissa-gmbh.de/img/community/Mastodon_Logotype.svg" width=20 alt="team@social.meissa-gmbh.de"> team@social.meissa-gmbh.de](https://social.meissa-gmbh.de/@team) | [Website & Blog](https://domaindrivenarchitecture.org)
# restore manuell triggern ## Purpose
c4k-nextcloud provides a k8s deployment for nextcloud containing:
* adjusted nextcloud docker image
* nextcloud
* ingress having a letsencrypt managed certificate
* postgres database
The package aims to a low load sceanrio.
## Status
Stable - we use this setup on production.
## Try out
Click on the image to try out live in your browser:
[![Try it out](doc/tryItOut.png "Try out yourself")](https://domaindrivenarchitecture.org/pages/dda-provision/c4k-nextcloud/)
Your input will stay in your browser. No server interaction is required.
You will also be able to try out on cli:
```
target/graalvm/c4k-nextcloud src/test/resources/valid-config.edn src/test/resources/valid-auth.edn | kubeval -
target/graalvm/c4k-nextcloud src/test/resources/valid-config.edn src/test/resources/valid-auth.edn | kubectl apply -f -
```
## Documentation
* [Example Setup on Hetzner](doc/SetupOnHetzner.md)
* Backup and Restore
## License
Copyright © 2021 meissa GmbH
Licensed under the [Apache License, Version 2.0](LICENSE) (the "License")
Pls. find licenses of our subcomponents [here](doc/SUBCOMPONENT_LICENSE)

View file

@ -17,7 +17,7 @@ resource "aws_s3_bucket" "backup" {
} }
} }
resource "hcloud_server" "jira_09_2021" { resource "hcloud_server" "cloud_09_2021" {
name = "the name" name = "the name"
image = "ubuntu-20.04" image = "ubuntu-20.04"
server_type = "cx31" server_type = "cx31"
@ -31,14 +31,14 @@ resource "hcloud_server" "jira_09_2021" {
resource "aws_route53_record" "v4_neu" { resource "aws_route53_record" "v4_neu" {
zone_id = the_dns_zone zone_id = the_dns_zone
name = "jira-neu" name = "cloud-neu"
type = "A" type = "A"
ttl = "300" ttl = "300"
records = [hcloud_server.jira_09_2021.ipv4_address] records = [hcloud_server.cloud_09_2021.ipv4_address]
} }
output "ipv4" { output "ipv4" {
value = hcloud_server.jira_09_2021.ipv4_address value = hcloud_server.cloud_09_2021.ipv4_address
} }
``` ```
@ -52,23 +52,23 @@ For k8s installation we use our [dda-k8s-crate](https://github.com/DomainDrivenA
{:user :k8s {:user :k8s
:k8s {:external-ip "ip-from-above"} :k8s {:external-ip "ip-from-above"}
:cert-manager :letsencrypt-prod-issuer :cert-manager :letsencrypt-prod-issuer
:persistent-dirs ["jira", "postgres"] :persistent-dirs ["cloud", "postgres"]
} }
``` ```
## kubectl apply c4k-jira ## kubectl apply c4k-nextcloud
The last step for applying the jira deployment is The last step for applying the nextcloud deployment is
``` ```
c4k-jira config.edn auth.edn | kubectl apply -f - c4k-nextcloud config.edn auth.edn | kubectl apply -f -
``` ```
with the following config.edn: with the following config.edn:
``` ```
{:fqdn "the-fqdn-from aws_route53_record.v4_neu" {:fqdn "the-fqdn-from aws_route53_record.v4_neu"
:jira-data-volume-path "/var/jira" ;; Volume was configured at dda-k8s-crate, results in a PersistentVolume definition. :nextcloud-data-volume-path "/var/cloud" ;; Volume was configured at dda-k8s-crate, results in a PersistentVolume definition.
:postgres-data-volume-path "/var/postgres" ;; Volume was configured at dda-k8s-crate, results in a PersistentVolume definition. :postgres-data-volume-path "/var/postgres" ;; Volume was configured at dda-k8s-crate, results in a PersistentVolume definition.
:restic-repository "s3:s3.amazonaws.com/your-bucket/your-folder"} :restic-repository "s3:s3.amazonaws.com/your-bucket/your-folder"}
``` ```

BIN
doc/tryItOut.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

View file

@ -1,4 +1,4 @@
FROM nextcloud:19 FROM nextcloud:22
# Prepare Entrypoint Script # Prepare Entrypoint Script
ADD resources /tmp ADD resources /tmp

View file

@ -1,6 +1,8 @@
#!/bin/bash #!/bin/bash
set -Eeo pipefail set -Eeo pipefail
apt update && apt -qqy install postgresql-client > /dev/null
mkdir /var/data mkdir /var/data
install -m 0700 /tmp/install-debug.sh /usr/local/bin/ install -m 0700 /tmp/install-debug.sh /usr/local/bin/

18
public/index.html Normal file
View file

@ -0,0 +1,18 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>c4k-nextcloud</title>
<link href="https://domaindrivenarchitecture.org/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="https://domaindrivenarchitecture.org/css/fonts/fontawesome/fontawesome.css" rel="stylesheet"
type="text/css" />
<link href="https://domaindrivenarchitecture.org/css/custom.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="c4k-content"></div>
<script src="js/main.js"></script>
</body>
</html>

View file

@ -4,7 +4,8 @@
"src/test/cljc" "src/test/cljc"
"src/test/cljs" "src/test/cljs"
"src/test/resources"] "src/test/resources"]
:dependencies [[org.domaindrivenarchitecture/c4k-common-cljs "0.3.2-SNAPSHOT"]] :dependencies [[org.domaindrivenarchitecture/c4k-common-cljs "0.4.3"]
[hickory "0.7.1"]]
:builds {:frontend {:target :browser :builds {:frontend {:target :browser
:modules {:main {:init-fn dda.c4k-nextcloud.browser/init}} :modules {:main {:init-fn dda.c4k-nextcloud.browser/init}}
:release {} :release {}

View file

@ -6,6 +6,34 @@
[dda.c4k-common.browser :as br] [dda.c4k-common.browser :as br]
[dda.c4k-common.postgres :as pgc])) [dda.c4k-common.postgres :as pgc]))
(defn generate-content
[]
(into [] (concat [(assoc (br/generate-needs-validation) :content
(into [] (concat (br/generate-input-field "fqdn" "Your fqdn:" "nextcloud-neu.prod.meissa-gmbh.de")
(br/generate-input-field "nextcloud-data-volume-path" "(Optional) Your nextcloud-data-volume-path:" "/var/nextcloud")
(br/generate-input-field "postgres-data-volume-path" "(Optional) Your postgres-data-volume-path:" "/var/postgres")
(br/generate-input-field "restic-repository" "(Optional) Your restic-repository:" "restic-repository")
(br/generate-input-field "issuer" "(Optional) Your issuer prod/staging:" "")
[(br/generate-br)]
(br/generate-text-area "auth" "Your auth.edn:" "{:postgres-db-user \"nextcloud\"
:postgres-db-password \"nextcloud-db-password\"
:nextcloud-admin-password \"nextcloud-admin-password\"
:nextcloud-admin-user \"nextcloud-admin-user\"
:aws-access-key-id \"aws-id\"
:aws-secret-access-key \"aws-secret\"
:restic-password \"restic-password\"}"
"5")
[(br/generate-br)]
(br/generate-button "generate-button" "Generate c4k yaml"))))]
(br/generate-output "c4k-nextcloud-output" "Your c4k deployment.yaml:" "25"))))
(defn generate-content-div
[]
{:type :element
:tag :div
:content
(generate-content)})
(defn config-from-document [] (defn config-from-document []
(let [nextcloud-data-volume-path (br/get-content-from-element "nextcloud-data-volume-path" :optional true) (let [nextcloud-data-volume-path (br/get-content-from-element "nextcloud-data-volume-path" :optional true)
postgres-data-volume-path (br/get-content-from-element "postgres-data-volume-path" :optional true) postgres-data-volume-path (br/get-content-from-element "postgres-data-volume-path" :optional true)
@ -32,7 +60,12 @@
(br/validate! "auth" core/auth? :deserializer edn/read-string) (br/validate! "auth" core/auth? :deserializer edn/read-string)
(br/set-validated!)) (br/set-validated!))
(defn add-validate-listener [name]
(-> (br/get-element-by-id name)
(.addEventListener "blur" #(do (validate-all!)))))
(defn init [] (defn init []
(br/append-hickory (generate-content-div))
(-> js/document (-> js/document
(.getElementById "generate-button") (.getElementById "generate-button")
(.addEventListener "click" (.addEventListener "click"
@ -41,22 +74,9 @@
(config-from-document) (config-from-document)
(br/get-content-from-element "auth" :deserializer edn/read-string)) (br/get-content-from-element "auth" :deserializer edn/read-string))
(br/set-output!))))) (br/set-output!)))))
(-> (br/get-element-by-id "fqdn") (add-validate-listener "fqdn")
(.addEventListener "blur" (add-validate-listener "nextcloud-data-volume-path")
#(do (validate-all!)))) (add-validate-listener "postgres-data-volume-path")
(-> (br/get-element-by-id "nextcloud-data-volume-path") (add-validate-listener "restic-repository")
(.addEventListener "blur" (add-validate-listener "issuer")
#(do (validate-all!)))) (add-validate-listener "auth"))
(-> (br/get-element-by-id "postgres-data-volume-path")
(.addEventListener "blur"
#(do (validate-all!))))
(-> (br/get-element-by-id "restic-repository")
(.addEventListener "blur"
#(do (validate-all!))))
(-> (br/get-element-by-id "issuer")
(.addEventListener "blur"
#(do (validate-all!))))
(-> (br/get-element-by-id "auth")
(.addEventListener "blur"
#(do (validate-all!))))
)

View file

@ -12,12 +12,21 @@ spec:
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
command: ["/entrypoint-start-and-wait.sh"] command: ["/entrypoint-start-and-wait.sh"]
env: env:
- name: POSTGRES_USER_FILE - name: POSTGRES_USER
value: /var/run/secrets/cloud-secrets/postgres-user valueFrom:
- name: POSTGRES_DB_FILE secretKeyRef:
value: /var/run/secrets/cloud-secrets/postgres-db name: postgres-secret
- name: POSTGRES_PASSWORD_FILE key: postgres-user
value: /var/run/secrets/cloud-secrets/postgres-password - name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: postgres-password
- name: POSTGRES_DB
valueFrom:
configMapKeyRef:
name: postgres-config
key: postgres-db
- name: POSTGRES_HOST - name: POSTGRES_HOST
value: "postgresql-service:5432" value: "postgresql-service:5432"
- name: POSTGRES_SERVICE - name: POSTGRES_SERVICE

View file

@ -1,4 +1,4 @@
apiVersion: batch/v1beta1 apiVersion: batch/v1
kind: CronJob kind: CronJob
metadata: metadata:
name: cloud-backup name: cloud-backup

View file

@ -1,4 +1,4 @@
apiVersion: cert-manager.io/v1alpha2 apiVersion: cert-manager.io/v1
kind: Certificate kind: Certificate
metadata: metadata:
name: cloud-cert name: cloud-cert

View file

@ -22,6 +22,14 @@ spec:
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
ports: ports:
- containerPort: 80 - containerPort: 80
livenessProbe:
exec:
command:
- /bin/sh
- -c
- PGPASSWORD=$POSTGRES_PASSWORD psql -h postgresql-service -U $POSTGRES_USER $POSTGRES_DB
initialDelaySeconds: 1
periodSeconds: 5
env: env:
- name: NEXTCLOUD_ADMIN_USER - name: NEXTCLOUD_ADMIN_USER
valueFrom: valueFrom:

View file

@ -10,7 +10,7 @@
:kind "Secret" :kind "Secret"
:metadata {:name "backup-secret"} :metadata {:name "backup-secret"}
:type "Opaque" :type "Opaque"
:stringData :data
{:aws-access-key-id "YXdzLWlk", :aws-secret-access-key "YXdzLXNlY3JldA==", :restic-password "cmVzdGljLXB3"}} {:aws-access-key-id "YXdzLWlk", :aws-secret-access-key "YXdzLXNlY3JldA==", :restic-password "cmVzdGljLXB3"}}
(cut/generate-secret {:aws-access-key-id "aws-id" :aws-secret-access-key "aws-secret" :restic-password "restic-pw"})))) (cut/generate-secret {:aws-access-key-id "aws-id" :aws-secret-access-key "aws-secret" :restic-password "restic-pw"}))))
@ -25,7 +25,7 @@
(cut/generate-config {:restic-repository "s3:restic-repository"})))) (cut/generate-config {:restic-repository "s3:restic-repository"}))))
(deftest should-generate-cron (deftest should-generate-cron
(is (= {:apiVersion "batch/v1beta1" (is (= {:apiVersion "batch/v1"
:kind "CronJob" :kind "CronJob"
:metadata {:name "cloud-backup", :labels {:app.kubernetes.part-of "cloud"}} :metadata {:name "cloud-backup", :labels {:app.kubernetes.part-of "cloud"}}
:spec :spec
@ -38,7 +38,7 @@
{:spec {:spec
{:containers {:containers
[{:name "backup-app" [{:name "backup-app"
:image "domaindrivenarchitecture/meissa-cloud-backup" :image "domaindrivenarchitecture/c4k-cloud-backup"
:imagePullPolicy "IfNotPresent" :imagePullPolicy "IfNotPresent"
:command ["/entrypoint.sh"] :command ["/entrypoint.sh"]
:env :env

View file

@ -9,14 +9,14 @@
:kind "Secret" :kind "Secret"
:metadata {:name "cloud-secret"} :metadata {:name "cloud-secret"}
:type "Opaque" :type "Opaque"
:stringData :data
{:nextcloud-admin-user "Y2xvdWRhZG1pbg==" {:nextcloud-admin-user "Y2xvdWRhZG1pbg=="
:nextcloud-admin-password "Y2xvdWRwYXNzd29yZA=="}} :nextcloud-admin-password "Y2xvdWRwYXNzd29yZA=="}}
(cut/generate-secret {:nextcloud-admin-user "cloudadmin" (cut/generate-secret {:nextcloud-admin-user "cloudadmin"
:nextcloud-admin-password "cloudpassword"})))) :nextcloud-admin-password "cloudpassword"}))))
(deftest should-generate-certificate (deftest should-generate-certificate
(is (= {:apiVersion "cert-manager.io/v1alpha2" (is (= {:apiVersion "cert-manager.io/v1"
:kind "Certificate" :kind "Certificate"
:metadata {:name "cloud-cert", :namespace "default"} :metadata {:name "cloud-cert", :namespace "default"}
:spec :spec
@ -58,71 +58,46 @@
(deftest should-generate-persistent-volume (deftest should-generate-persistent-volume
(is (= {:kind "PersistentVolume" (is (= {:kind "PersistentVolume"
:apiVersion "v1" :apiVersion "v1"
:metadata {:name "cloud-pv-volume", :labels {:type "local" :app "cloud"}} :metadata {:name "cloud-pv-volume"
:spec :labels {:type "local", :app.kubernetes.io/application "cloud"}}
{:storageClassName "manual" :spec {:storageClassName "manual"
:accessModes ["ReadWriteOnce"] :accessModes ["ReadWriteOnce"]
:capacity {:storage "200Gi"} :capacity {:storage "200Gi"}
:hostPath {:path "xx"}}} :hostPath {:path "xx"}}}
(cut/generate-persistent-volume {:nextcloud-data-volume-path "xx"})))) (cut/generate-persistent-volume {:nextcloud-data-volume-path "xx"}))))
(deftest should-generate-deployment (deftest should-generate-deployment
(is (= {:apiVersion "apps/v1" (is (= {:apiVersion "apps/v1"
:kind "Deployment" :kind "Deployment"
:metadata {:name "cloud"} :metadata {:name "cloud-deployment"}
:spec :spec
{:selector {:matchLabels {:app "cloud"}} {:selector {:matchLabels #:app.kubernetes.io{:name "cloud-pod", :application "cloud"}}
:strategy {:type "Recreate"} :strategy {:type "Recreate"}
:template :template
{:metadata {:labels {:app "cloud"}} {:metadata {:labels {:app.kubernetes.io/name "cloud-pod", :app.kubernetes.io/application "cloud", :redeploy "v3"}}
:spec :spec
{:containers {:containers
[{:image "domaindrivenarchitecture/meissa-cloud-app" [{:image "domaindrivenarchitecture/c4k-cloud"
:name "cloud-app" :name "cloud-app"
:imagePullPolicy "IfNotPresent" :imagePullPolicy "IfNotPresent"
:ports [{:containerPort 80}] :ports [{:containerPort 80}]
:livenessProbe
{:exec
{:command
["/bin/sh"
"-c"
"PGPASSWORD=$POSTGRES_PASSWORD psql -h postgresql-service -U $POSTGRES_USER $POSTGRES_DB"]}
:initialDelaySeconds 1
:periodSeconds 5}
:env :env
[{:name "NEXTCLOUD_ADMIN_USER_FILE" [{:name "NEXTCLOUD_ADMIN_USER", :valueFrom {:secretKeyRef {:name "cloud-secret", :key "nextcloud-admin-user"}}}
:value {:name "NEXTCLOUD_ADMIN_PASSWORD"
"/var/run/secrets/cloud-secrets/nextcloud-admin-user"} :valueFrom {:secretKeyRef {:name "cloud-secret", :key "nextcloud-admin-password"}}}
{:name "NEXTCLOUD_ADMIN_PASSWORD_FILE"
:value
"/var/run/secrets/cloud-secrets/nextcloud-admin-password"}
{:name "NEXTCLOUD_TRUSTED_DOMAINS", :value "xx"} {:name "NEXTCLOUD_TRUSTED_DOMAINS", :value "xx"}
{:name "POSTGRES_USER_FILE" {:name "POSTGRES_USER", :valueFrom {:secretKeyRef {:name "postgres-secret", :key "postgres-user"}}}
:value {:name "POSTGRES_PASSWORD", :valueFrom {:secretKeyRef {:name "postgres-secret", :key "postgres-password"}}}
"/var/run/secrets/postgres-secret/postgres-user"} {:name "POSTGRES_DB", :valueFrom {:configMapKeyRef {:name "postgres-config", :key "postgres-db"}}}
{:name "POSTGRES_PASSWORD_FILE" {:name "POSTGRES_HOST", :value "postgresql-service:5432"}]
:value :volumeMounts [{:name "cloud-data-volume", :mountPath "/var/www/html"}]}]
"/var/run/secrets/postgres-secret/postgres-password"} :volumes [{:name "cloud-data-volume", :persistentVolumeClaim {:claimName "cloud-pvc"}}]}}}}
{:name "POSTGRES_DB_FILE"
:value
"/var/run/configs/postgres-config/postgres-db"}
{:name "POSTGRES_HOST"
:value "postgresql-service:5432"}]
:volumeMounts
[{:name "cloud-data-volume"
:mountPath "/var/www/html"}
{:name "cloud-secret-volume"
:mountPath "/var/run/secrets/cloud-secrets"
:readOnly true}
{:name "postgres-secret-volume"
:mountPath "/var/run/secrets/postgres-secret"
:readOnly true}
{:name "postgres-config-volume"
:mountPath "/var/run/configs/postgres-config"
:readOnly true}]}]
:volumes
[{:name "cloud-data-volume"
:persistentVolumeClaim {:claimName "cloud-pvc"}}
{:name "cloud-secret-volume"
:secret {:secretName "cloud-secret"}}
{:name "postgres-secret-volume"
:secret {:secretName "postgres-secret"}}
{:name "postgres-config-volume"
:configMap
{:name "postgres-config"
:items [{:key "postgres-db", :path "postgres-db"}]}}
{:name "backup-secret-volume"
:secret {:secretName "backup-secret"}}]}}}}
(cut/generate-deployment {:fqdn "xx"})))) (cut/generate-deployment {:fqdn "xx"}))))