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
script:
- 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:
paths:
- 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"
image = "ubuntu-20.04"
server_type = "cx31"
@ -31,14 +31,14 @@ resource "hcloud_server" "jira_09_2021" {
resource "aws_route53_record" "v4_neu" {
zone_id = the_dns_zone
name = "jira-neu"
name = "cloud-neu"
type = "A"
ttl = "300"
records = [hcloud_server.jira_09_2021.ipv4_address]
records = [hcloud_server.cloud_09_2021.ipv4_address]
}
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
:k8s {:external-ip "ip-from-above"}
: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:
```
{: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.
: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
ADD resources /tmp

View file

@ -1,6 +1,8 @@
#!/bin/bash
set -Eeo pipefail
apt update && apt -qqy install postgresql-client > /dev/null
mkdir /var/data
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/cljs"
"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
:modules {:main {:init-fn dda.c4k-nextcloud.browser/init}}
:release {}

View file

@ -6,6 +6,34 @@
[dda.c4k-common.browser :as br]
[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 []
(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)
@ -32,7 +60,12 @@
(br/validate! "auth" core/auth? :deserializer edn/read-string)
(br/set-validated!))
(defn add-validate-listener [name]
(-> (br/get-element-by-id name)
(.addEventListener "blur" #(do (validate-all!)))))
(defn init []
(br/append-hickory (generate-content-div))
(-> js/document
(.getElementById "generate-button")
(.addEventListener "click"
@ -41,22 +74,9 @@
(config-from-document)
(br/get-content-from-element "auth" :deserializer edn/read-string))
(br/set-output!)))))
(-> (br/get-element-by-id "fqdn")
(.addEventListener "blur"
#(do (validate-all!))))
(-> (br/get-element-by-id "nextcloud-data-volume-path")
(.addEventListener "blur"
#(do (validate-all!))))
(-> (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!))))
)
(add-validate-listener "fqdn")
(add-validate-listener "nextcloud-data-volume-path")
(add-validate-listener "postgres-data-volume-path")
(add-validate-listener "restic-repository")
(add-validate-listener "issuer")
(add-validate-listener "auth"))

View file

@ -12,12 +12,21 @@ spec:
imagePullPolicy: IfNotPresent
command: ["/entrypoint-start-and-wait.sh"]
env:
- name: POSTGRES_USER_FILE
value: /var/run/secrets/cloud-secrets/postgres-user
- name: POSTGRES_DB_FILE
value: /var/run/secrets/cloud-secrets/postgres-db
- name: POSTGRES_PASSWORD_FILE
value: /var/run/secrets/cloud-secrets/postgres-password
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgres-secret
key: postgres-user
- 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
value: "postgresql-service:5432"
- name: POSTGRES_SERVICE

View file

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

View file

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

View file

@ -22,6 +22,14 @@ spec:
imagePullPolicy: IfNotPresent
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:
- name: NEXTCLOUD_ADMIN_USER
valueFrom:

View file

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

View file

@ -9,14 +9,14 @@
:kind "Secret"
:metadata {:name "cloud-secret"}
:type "Opaque"
:stringData
:data
{:nextcloud-admin-user "Y2xvdWRhZG1pbg=="
:nextcloud-admin-password "Y2xvdWRwYXNzd29yZA=="}}
(cut/generate-secret {:nextcloud-admin-user "cloudadmin"
:nextcloud-admin-password "cloudpassword"}))))
(deftest should-generate-certificate
(is (= {:apiVersion "cert-manager.io/v1alpha2"
(is (= {:apiVersion "cert-manager.io/v1"
:kind "Certificate"
:metadata {:name "cloud-cert", :namespace "default"}
:spec
@ -58,71 +58,46 @@
(deftest should-generate-persistent-volume
(is (= {:kind "PersistentVolume"
:apiVersion "v1"
:metadata {:name "cloud-pv-volume", :labels {:type "local" :app "cloud"}}
:spec
{:storageClassName "manual"
:accessModes ["ReadWriteOnce"]
:capacity {:storage "200Gi"}
:hostPath {:path "xx"}}}
:metadata {:name "cloud-pv-volume"
:labels {:type "local", :app.kubernetes.io/application "cloud"}}
:spec {:storageClassName "manual"
:accessModes ["ReadWriteOnce"]
:capacity {:storage "200Gi"}
:hostPath {:path "xx"}}}
(cut/generate-persistent-volume {:nextcloud-data-volume-path "xx"}))))
(deftest should-generate-deployment
(is (= {:apiVersion "apps/v1"
:kind "Deployment"
:metadata {:name "cloud"}
:metadata {:name "cloud-deployment"}
:spec
{:selector {:matchLabels {:app "cloud"}}
{:selector {:matchLabels #:app.kubernetes.io{:name "cloud-pod", :application "cloud"}}
:strategy {:type "Recreate"}
:template
{:metadata {:labels {:app "cloud"}}
{:metadata {:labels {:app.kubernetes.io/name "cloud-pod", :app.kubernetes.io/application "cloud", :redeploy "v3"}}
:spec
{:containers
[{:image "domaindrivenarchitecture/meissa-cloud-app"
[{:image "domaindrivenarchitecture/c4k-cloud"
:name "cloud-app"
:imagePullPolicy "IfNotPresent"
: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
[{:name "NEXTCLOUD_ADMIN_USER_FILE"
:value
"/var/run/secrets/cloud-secrets/nextcloud-admin-user"}
{:name "NEXTCLOUD_ADMIN_PASSWORD_FILE"
:value
"/var/run/secrets/cloud-secrets/nextcloud-admin-password"}
[{:name "NEXTCLOUD_ADMIN_USER", :valueFrom {:secretKeyRef {:name "cloud-secret", :key "nextcloud-admin-user"}}}
{:name "NEXTCLOUD_ADMIN_PASSWORD"
:valueFrom {:secretKeyRef {:name "cloud-secret", :key "nextcloud-admin-password"}}}
{:name "NEXTCLOUD_TRUSTED_DOMAINS", :value "xx"}
{:name "POSTGRES_USER_FILE"
:value
"/var/run/secrets/postgres-secret/postgres-user"}
{:name "POSTGRES_PASSWORD_FILE"
:value
"/var/run/secrets/postgres-secret/postgres-password"}
{: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"}}]}}}}
{:name "POSTGRES_USER", :valueFrom {:secretKeyRef {:name "postgres-secret", :key "postgres-user"}}}
{: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", :value "postgresql-service:5432"}]
:volumeMounts [{:name "cloud-data-volume", :mountPath "/var/www/html"}]}]
:volumes [{:name "cloud-data-volume", :persistentVolumeClaim {:claimName "cloud-pvc"}}]}}}}
(cut/generate-deployment {:fqdn "xx"}))))