Services expose port 80 via ClusterIP but widgets were using container target ports (5000, 3001, 4533, 3000). Calibre was using external URL through Authentik. All now use correct internal service URLs.
365 lines
9.4 KiB
HCL
365 lines
9.4 KiB
HCL
variable "tls_secret_name" {
|
|
type = string
|
|
sensitive = true
|
|
}
|
|
variable "nextcloud_db_password" {
|
|
type = string
|
|
sensitive = true
|
|
}
|
|
variable "nfs_server" { type = string }
|
|
variable "redis_host" { type = string }
|
|
variable "mysql_host" { type = string }
|
|
variable "homepage_credentials" {
|
|
type = map(any)
|
|
sensitive = true
|
|
}
|
|
|
|
|
|
module "tls_secret" {
|
|
source = "../../modules/kubernetes/setup_tls_secret"
|
|
namespace = kubernetes_namespace.nextcloud.metadata[0].name
|
|
tls_secret_name = var.tls_secret_name
|
|
}
|
|
|
|
resource "kubernetes_namespace" "nextcloud" {
|
|
metadata {
|
|
name = "nextcloud"
|
|
labels = {
|
|
"istio-injection" : "disabled"
|
|
tier = local.tiers.edge
|
|
"resource-governance/custom-limitrange" = "true"
|
|
"resource-governance/custom-quota" = "true"
|
|
}
|
|
}
|
|
}
|
|
|
|
resource "kubernetes_resource_quota" "nextcloud" {
|
|
metadata {
|
|
name = "nextcloud-quota"
|
|
namespace = kubernetes_namespace.nextcloud.metadata[0].name
|
|
}
|
|
spec {
|
|
hard = {
|
|
"requests.cpu" = "4"
|
|
"requests.memory" = "8Gi"
|
|
"limits.cpu" = "32"
|
|
"limits.memory" = "16Gi"
|
|
pods = "10"
|
|
}
|
|
}
|
|
}
|
|
|
|
resource "kubernetes_limit_range" "nextcloud" {
|
|
metadata {
|
|
name = "nextcloud-limits"
|
|
namespace = kubernetes_namespace.nextcloud.metadata[0].name
|
|
}
|
|
spec {
|
|
limit {
|
|
type = "Container"
|
|
default = {
|
|
cpu = "250m"
|
|
memory = "256Mi"
|
|
}
|
|
default_request = {
|
|
cpu = "25m"
|
|
memory = "64Mi"
|
|
}
|
|
max = {
|
|
cpu = "16"
|
|
memory = "8Gi"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
resource "helm_release" "nextcloud" {
|
|
namespace = kubernetes_namespace.nextcloud.metadata[0].name
|
|
name = "nextcloud"
|
|
|
|
repository = "https://nextcloud.github.io/helm/"
|
|
chart = "nextcloud"
|
|
atomic = true
|
|
version = "8.8.1"
|
|
|
|
values = [templatefile("${path.module}/chart_values.yaml", { tls_secret_name = var.tls_secret_name, db_password = var.nextcloud_db_password, redis_host = var.redis_host, mysql_host = var.mysql_host })]
|
|
timeout = 6000
|
|
}
|
|
|
|
# resource "kubernetes_config_map" "config" {
|
|
# metadata {
|
|
# name = "config"
|
|
# namespace = kubernetes_namespace.nextcloud.metadata[0].name
|
|
|
|
# annotations = {
|
|
# "reloader.stakater.com/match" = "true"
|
|
# }
|
|
# }
|
|
|
|
# data = {
|
|
# "conf.yml" = file("${path.module}/conf.yml")
|
|
# }
|
|
# }
|
|
|
|
module "nfs_nextcloud_data" {
|
|
source = "../../modules/kubernetes/nfs_volume"
|
|
name = "nextcloud-data"
|
|
namespace = kubernetes_namespace.nextcloud.metadata[0].name
|
|
nfs_server = var.nfs_server
|
|
nfs_path = "/mnt/main/nextcloud"
|
|
storage = "100Gi"
|
|
}
|
|
|
|
module "nfs_nextcloud_backup" {
|
|
source = "../../modules/kubernetes/nfs_volume"
|
|
name = "nextcloud-backup"
|
|
namespace = kubernetes_namespace.nextcloud.metadata[0].name
|
|
nfs_server = var.nfs_server
|
|
nfs_path = "/mnt/main/nextcloud-backup"
|
|
}
|
|
|
|
resource "kubernetes_deployment" "whiteboard" {
|
|
metadata {
|
|
name = "whiteboard"
|
|
namespace = kubernetes_namespace.nextcloud.metadata[0].name
|
|
labels = {
|
|
app = "whiteboard"
|
|
tier = local.tiers.edge
|
|
}
|
|
annotations = {
|
|
"reloader.stakater.com/search" = "true"
|
|
}
|
|
}
|
|
spec {
|
|
replicas = 1
|
|
selector {
|
|
match_labels = {
|
|
app = "whiteboard"
|
|
}
|
|
}
|
|
template {
|
|
metadata {
|
|
labels = {
|
|
app = "whiteboard"
|
|
}
|
|
}
|
|
spec {
|
|
priority_class_name = "tier-3-edge"
|
|
container {
|
|
image = "ghcr.io/nextcloud-releases/whiteboard:release"
|
|
name = "whiteboard"
|
|
|
|
port {
|
|
container_port = 3002
|
|
}
|
|
env {
|
|
name = "NEXTCLOUD_URL"
|
|
value = "http://nextcloud:8080"
|
|
}
|
|
env {
|
|
name = "JWT_SECRET_KEY"
|
|
value = var.nextcloud_db_password # anything secret is fine
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
resource "kubernetes_service" "whiteboard" {
|
|
metadata {
|
|
name = "whiteboard"
|
|
namespace = kubernetes_namespace.nextcloud.metadata[0].name
|
|
labels = {
|
|
app = "whiteboard"
|
|
}
|
|
}
|
|
|
|
spec {
|
|
selector = {
|
|
app = "whiteboard"
|
|
}
|
|
port {
|
|
name = "http"
|
|
port = 80
|
|
target_port = 3002
|
|
}
|
|
}
|
|
}
|
|
|
|
module "ingress" {
|
|
source = "../../modules/kubernetes/ingress_factory"
|
|
namespace = kubernetes_namespace.nextcloud.metadata[0].name
|
|
name = "nextcloud"
|
|
tls_secret_name = var.tls_secret_name
|
|
port = 8080
|
|
rybbit_site_id = "5a3bfe59a3fe"
|
|
extra_annotations = {
|
|
"gethomepage.dev/enabled" = "true"
|
|
"gethomepage.dev/name" = "Nextcloud"
|
|
"gethomepage.dev/description" = "Cloud productivity suite"
|
|
"gethomepage.dev/icon" = "nextcloud.png"
|
|
"gethomepage.dev/group" = "Productivity"
|
|
"gethomepage.dev/pod-selector" = ""
|
|
"gethomepage.dev/widget.type" = "nextcloud"
|
|
"gethomepage.dev/widget.url" = "http://nextcloud.nextcloud.svc.cluster.local:8080"
|
|
"gethomepage.dev/widget.username" = var.homepage_credentials["nextcloud"]["username"]
|
|
"gethomepage.dev/widget.password" = var.homepage_credentials["nextcloud"]["password"]
|
|
}
|
|
}
|
|
|
|
module "whiteboard_ingress" {
|
|
source = "../../modules/kubernetes/ingress_factory"
|
|
namespace = kubernetes_namespace.nextcloud.metadata[0].name
|
|
name = "whiteboard"
|
|
tls_secret_name = var.tls_secret_name
|
|
port = 80
|
|
}
|
|
|
|
resource "kubernetes_config_map" "backup-script" {
|
|
metadata {
|
|
name = "nextcloud-backup-script"
|
|
namespace = kubernetes_namespace.nextcloud.metadata[0].name
|
|
}
|
|
|
|
data = {
|
|
"backup.sh" = <<-EOF
|
|
#!/bin/bash
|
|
set -e
|
|
|
|
BACKUP_DIR="/backup"
|
|
DATA_DIR="/nextcloud-data"
|
|
DATE=$(date +%Y%m%d_%H%M%S)
|
|
BACKUP_PATH="$BACKUP_DIR/$DATE"
|
|
|
|
echo "Starting Nextcloud backup at $(date)"
|
|
|
|
# Note: Maintenance mode is skipped because occ is not available in the NFS mount.
|
|
# For a proper backup with maintenance mode, exec into the nextcloud pod:
|
|
# kubectl exec -n nextcloud deployment/nextcloud -- php occ maintenance:mode --on
|
|
|
|
# Create backup directory
|
|
mkdir -p "$BACKUP_PATH"
|
|
|
|
# Backup everything (config, data, custom_apps, themes, etc.)
|
|
echo "Backing up Nextcloud installation..."
|
|
rsync -a "$DATA_DIR/" "$BACKUP_PATH/"
|
|
|
|
# Keep only last 7 backups
|
|
echo "Cleaning old backups..."
|
|
cd "$BACKUP_DIR"
|
|
ls -dt */ | tail -n +8 | xargs -r rm -rf
|
|
|
|
echo "Backup completed at $(date)"
|
|
echo "Backup stored at: $BACKUP_PATH"
|
|
EOF
|
|
|
|
"restore.sh" = <<-EOF
|
|
#!/bin/bash
|
|
# Restore script - run manually when needed
|
|
# Usage: ./restore.sh <backup_date>
|
|
# Example: ./restore.sh 20250117_030000
|
|
#
|
|
# Before restoring, enable maintenance mode:
|
|
# kubectl exec -n nextcloud deployment/nextcloud -- php occ maintenance:mode --on
|
|
# After restoring, disable it:
|
|
# kubectl exec -n nextcloud deployment/nextcloud -- php occ maintenance:mode --off
|
|
|
|
set -e
|
|
|
|
if [ -z "$1" ]; then
|
|
echo "Usage: $0 <backup_date>"
|
|
echo "Available backups:"
|
|
ls -1 /backup/
|
|
exit 1
|
|
fi
|
|
|
|
BACKUP_PATH="/backup/$1"
|
|
DATA_DIR="/nextcloud-data"
|
|
|
|
if [ ! -d "$BACKUP_PATH" ]; then
|
|
echo "Backup not found: $BACKUP_PATH"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Restoring from $BACKUP_PATH"
|
|
|
|
# Restore everything
|
|
echo "Restoring Nextcloud installation..."
|
|
rsync -a "$BACKUP_PATH/" "$DATA_DIR/"
|
|
|
|
echo "Restore completed!"
|
|
echo "Remember to run: kubectl exec -n nextcloud deployment/nextcloud -- php occ maintenance:mode --off"
|
|
EOF
|
|
}
|
|
}
|
|
|
|
resource "kubernetes_cron_job_v1" "nextcloud-backup" {
|
|
metadata {
|
|
name = "nextcloud-backup"
|
|
namespace = kubernetes_namespace.nextcloud.metadata[0].name
|
|
}
|
|
|
|
spec {
|
|
schedule = "0 3 * * 0" # Sunday at 3 AM
|
|
successful_jobs_history_limit = 3
|
|
failed_jobs_history_limit = 3
|
|
concurrency_policy = "Forbid"
|
|
|
|
job_template {
|
|
metadata {}
|
|
spec {
|
|
template {
|
|
metadata {}
|
|
spec {
|
|
restart_policy = "OnFailure"
|
|
|
|
container {
|
|
name = "backup"
|
|
image = "alpine:latest"
|
|
|
|
command = ["/bin/sh", "-c", "apk add --no-cache rsync bash && /scripts/backup.sh"]
|
|
|
|
volume_mount {
|
|
name = "nextcloud-data"
|
|
mount_path = "/nextcloud-data"
|
|
}
|
|
|
|
volume_mount {
|
|
name = "backup"
|
|
mount_path = "/backup"
|
|
}
|
|
|
|
volume_mount {
|
|
name = "scripts"
|
|
mount_path = "/scripts"
|
|
}
|
|
}
|
|
|
|
volume {
|
|
name = "nextcloud-data"
|
|
persistent_volume_claim {
|
|
claim_name = module.nfs_nextcloud_data.claim_name
|
|
}
|
|
}
|
|
|
|
volume {
|
|
name = "backup"
|
|
persistent_volume_claim {
|
|
claim_name = module.nfs_nextcloud_backup.claim_name
|
|
}
|
|
}
|
|
|
|
volume {
|
|
name = "scripts"
|
|
config_map {
|
|
name = kubernetes_config_map.backup-script.metadata[0].name
|
|
default_mode = "0755"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|