128 Commits
Author SHA1 Message Date
pierre.geeraert 7553bcc923 reformat 2026-10-13 21:31:30 +01:00
pierre.geeraert b88864a731 not using gitea.tryton anymore 2026-10-13 19:02:08 +01:00
pierre.geeraert e21065a35c fix django secret missing 2026-10-13 19:00:00 +01:00
pierre.geeraert 40aa901a50 fix django secret missing 2026-10-13 18:58:38 +01:00
pierre.geeraert 147f862978 add import secrets 2026-10-13 18:49:36 +01:00
pi-ux-ce@ARES c9ade2f851 In your try() block, when the attribute doesn't exist, it correctly returns . However, when the attribute does exist, it returns the whole nested object (e.g., { host = ..., name = ... }). In Terraform, comparing a complex object/map to an empty string ({...} != ) is technically invalid or doesn't evaluate cleanly to a false check, causing the filter to let it slip through or crash when it expects a string. 2026-10-13 18:47:57 +01:00
pierre.geeraert aef087cfe1 enable more 2026-10-13 18:35:03 +01:00
pi-ux-ce@ARES ca989177da adding django and django-testing 2026-10-13 18:31:53 +01:00
pierre.geeraert 8848037c0f missed 2026-10-13 18:26:25 +01:00
pierre.geeraert a78a3c4e48 missed 2026-10-13 18:22:21 +01:00
pierre.geeraert 0fb7df60da cleanup incoming variables 2026-10-13 18:21:09 +01:00
pierre.geeraert ab4ef16a5e cleanup incoming variables 2026-10-13 18:18:06 +01:00
pierre.geeraert 51cef87475 ingress module 2026-10-13 18:12:14 +01:00
pierre.geeraert 23f59668a8 enable multiple domain name 2026-10-13 18:04:22 +01:00
pierre.geeraert 8002d9d0b7 ingress module 2026-10-13 18:00:23 +01:00
pierre.geeraert 243bd3a998 module service 2026-10-13 17:53:30 +01:00
pierre.geeraert 36d9421156 module service 2026-10-13 17:42:09 +01:00
pierre.geeraert 8e354b36b3 ingress module 2026-10-13 17:36:06 +01:00
pierre.geeraert e80f53c2e5 ingress module 2026-10-13 17:29:57 +01:00
pi-ux-ce@ARES c158dffcc9 beginning of modules 2026-10-13 17:26:10 +01:00
pierre.geeraert d7f6bc0869 cleanup 2026-10-13 16:18:28 +01:00
pierre.geeraert 56a02818cd cleanup 2026-10-13 16:15:59 +01:00
pierre.geeraert 6578e10274 bitwarden needs to expose 8080 not 5000 2026-10-13 14:55:42 +01:00
pierre.geeraert 6c2c971338 duplicate names 2026-10-13 14:52:29 +01:00
pierre.geeraert b4fdbccf98 add legacy domain support 2026-10-13 14:49:48 +01:00
pierre.geeraert 96236c6baf two ingress instead 2026-10-13 14:48:25 +01:00
pierre.geeraert bd2d151ebd disable reverse proxy and add extra site 2026-10-13 14:45:50 +01:00
pierre.geeraert dce7d02073 fix manifest and ingress 2026-10-13 13:49:34 +01:00
pierre.geeraert 763582404c fix changes 2026-10-13 13:35:02 +01:00
pierre.geeraert 22d22483b6 deploy clusterissuer 2026-10-13 13:33:38 +01:00
pierre.geeraert bdcc54d9b5 adding cert-manager helm chart 2026-10-13 11:55:56 +01:00
pi-ux-ce@ARES be06a539ea made some work on the ingress 2026-10-13 11:27:41 +01:00
pierre.geeraert a0d77cc2d6 auto create namespace 2026-10-13 08:53:57 +01:00
pierre.geeraert fe4f056c97 adding ingress helm 2026-10-13 08:51:12 +01:00
pierre.geeraert 086197f4f1 fix the misake 2026-10-12 19:45:31 +01:00
pierre.geeraert 591c1f83c4 fix the misake 2026-10-12 19:44:06 +01:00
pierre.geeraert 080eed640d fix the misake 2026-10-12 19:43:10 +01:00
pierre.geeraert 96bdb57a8e revert back the config file 2026-10-12 19:26:45 +01:00
pierre.geeraert a3adeb8406 try new method 2026-10-12 19:16:07 +01:00
pierre.geeraert 661ee11d6d big cleanup 2026-10-12 18:34:25 +01:00
pierre.geeraert 7f9bc2019d work on the reverse proxy 2026-10-12 18:24:51 +01:00
pierre.geeraert 9f872ebea0 cleanup 2026-10-12 18:14:23 +01:00
pierre.geeraert a69e4dd7a2 pvc.name not in use 2026-10-12 18:12:50 +01:00
pierre.geeraert 5f88c306a3 frogot the pvc part 2026-10-12 18:11:13 +01:00
pierre.geeraert fdba5cea6b forgot the pvc part 2026-10-12 18:08:07 +01:00
pierre.geeraert 9a5e82cb32 we don't use pvc.name anymore but pvc.key 2026-10-12 18:05:00 +01:00
pierre.geeraert 236a994bfa cleanup 2026-10-12 18:01:17 +01:00
pierre.geeraert 9257237fd1 importing all secrets 2026-10-12 18:00:49 +01:00
pierre.geeraert 04d6d19dde better way to import 2026-10-12 17:14:26 +01:00
pierre.geeraert bc1bee1074 plan for gluetun sound good 2026-10-12 16:54:42 +01:00
pierre.geeraert ec901f92df reformat 2026-10-12 16:53:38 +01:00
pierre.geeraert e538226182 infra restructure and adding lifecycle to the secret 2026-10-12 16:48:01 +01:00
pierre.geeraert c7c0941877 remove some bits as well 2026-10-12 12:11:16 +01:00
pierre.geeraert 69f4696faa fix backup sqlsserver 2026-10-12 10:58:21 +01:00
pierre.geeraert 307d4117ae enable all bitwarden 2026-10-12 10:48:37 +01:00
pi-ux-ce@ARES 37c93401f1 enable identity and remove un necessary svc file 2026-10-12 10:48:00 +01:00
pierre.geeraert 5f8bb25e76 fixing the pvcs 2026-10-12 10:46:04 +01:00
pi-ux-ce@ARES fe064cb7ea work on bitwarden 2026-10-12 10:40:13 +01:00
pi-ux-ce@ARES 002053c099 adding namepsace to gitea runner 2026-10-12 10:32:05 +01:00
pi-ux-ce 7962e91e3a gitea needed service port 2026-10-12 10:25:47 +01:00
pierre.geeraert 534958f828 adding database support 2026-10-12 09:54:26 +01:00
pierre geeraert b27bfe5714 not filling nodeport if the type is not nodeport 2026-10-12 00:16:07 +01:00
pierre geeraert 437891b2d4 work on the node port 2026-10-12 00:07:53 +01:00
pierre geeraert de81eb1e09 work on the node port 2026-10-12 00:04:24 +01:00
pierre geeraert d720f66322 cleaning unnecessary codee 2026-10-11 23:31:01 +01:00
pierre geeraert 4620270006 working destination file name 2026-10-11 23:20:57 +01:00
pierre geeraert ecaba98387 add comment 2026-10-11 13:02:17 +01:00
pi-ux-ce 85e853e9cb not working yet maybe we need the join function instead 2026-10-11 13:01:10 +01:00
pierre geeraert 64fdd22df8 disbale for our tests 2026-10-11 12:50:45 +01:00
pierre geeraert f8c89da4a1 fix bool error 2026-10-11 12:49:45 +01:00
pierre geeraert 79dbe3721e fix bool error 2026-10-11 12:44:27 +01:00
pierre geeraert a0cf0cebe4 another try for the hostpath 2026-10-11 12:42:29 +01:00
pi-ux-ce 6d9b7d792f testing with the shunt docker 2026-10-11 11:38:27 +01:00
pierre geeraert 51179673ce adding namespace 2026-10-11 11:32:54 +01:00
pierre.geeraert caac327b50 adding tfvars 2026-10-07 15:29:32 +01:00
pierre.geeraert 8c1b6cdef8 restructuring the code 2026-10-07 15:18:36 +01:00
pi-ux-ce 013465ffec add before changes 2026-09-29 16:09:13 +01:00
pi-ux-ce 562ee0edae allowed hosts for django 2026-09-16 13:04:14 +01:00
pi-ux-ce df39551a46 adding kopia but disable as failed 2026-09-10 11:25:14 +01:00
pi-ux-ce bc5fb92b24 start work on cronjob 2026-08-14 12:08:00 +01:00
pi-ux-ce 191f7b4fd5 soem changes anmd shutting down next for the night 2026-08-12 17:23:51 +01:00
pi-ux-ce f712611861 adding next and also modifying the nginx file 2026-08-12 11:49:19 +01:00
pi-ux-ce 300f3460e0 remove nextcloudt 2026-08-12 09:55:20 +01:00
pi-ux-ce 624bceb2ca change paperless URL 2026-08-12 09:28:41 +01:00
pi-ux-ce 8cdc4cbedc backup before chnage 2026-08-12 09:12:05 +01:00
pi-ux-ce f645883af4 adding all untracked files 2026-07-28 09:27:03 +01:00
pi-ux-ce 97a1d96d1b upgrading redis to latest 2026-07-27 11:27:03 +01:00
pi-ux-ce 414fc6fd08 add before changes 2026-07-27 11:24:03 +01:00
pi-ux-ce 4d5b8ed68f removing owncloud 2026-07-23 16:51:04 +01:00
pi-ux-ce 53dab4d910 remove qbittorrent for now 2026-07-23 16:38:44 +01:00
pi-ux-ce a3cb97eeb0 backup before changes 2026-07-23 14:20:32 +01:00
pierre.geeraert 686a5d2485 great README 2026-06-29 16:24:43 +01:00
pi-ux-ce 6b08931005 setup env mapper for DB 2026-06-29 16:12:49 +01:00
pi-ux-ce 7e8e229a63 adding files 2026-06-29 10:52:38 +01:00
pi-ux-ce 76bc297d3a fixed gluetun issue 2026-05-19 21:50:59 +01:00
pi-ux-ce fde0fedc1e backup before touching a lot gluetun 2026-05-19 21:17:45 +01:00
pi-ux-ce 680700503f add another gluetun profile 2026-03-15 21:56:47 +00:00
pi-ux-ce cf90976c76 adding a different path due to postgresql V18 2026-03-09 14:04:38 +00:00
pi-ux-ce 400e8f00fe adding all missed external_manifests 2026-03-05 21:07:28 +00:00
pi-ux-ce 17e6ea2251 main container get db backup pvc if shunt is in place , otherwise automatic db get it 2026-03-05 21:07:03 +00:00
pi-ux-ce 68e2a1bb2f upload 2026-03-05 20:24:04 +00:00
pi-ux-ce 7dc450eac0 cleanup bookstack 2026-03-04 00:27:49 +00:00
pi-ux-ce 1f0acfeed4 cleanup bookstack 2026-03-04 00:27:17 +00:00
pi-ux-ce b8d6150aa9 testing success , no need to specifiy DB name anymore in the secrets 2026-03-03 23:57:55 +00:00
pi-ux-ce 9c3cecd4ce more testing with default creds 2026-03-03 23:46:36 +00:00
pi-ux-ce 3072568008 adding shunt to deploy every db tools without the svc pvc or deploy , adding bitwarden info 2026-03-02 14:24:26 +00:00
pi-ux-ce e2be2f78a7 cleanup 2026-03-02 12:04:06 +00:00
pi-ux-ce 64b4160039 cleanup 2026-03-02 12:03:59 +00:00
pi-ux-ce 06a8d9e680 add cronjob backup DB mysql not workign yet 2026-03-02 09:27:03 +00:00
pi-ux-ce f933d5b659 format 2026-02-11 21:45:05 +00:00
pi-ux-ce 7c333b323a doing some cleanup 2026-02-11 21:43:36 +00:00
pi-ux-ce 4564ccd601 adding some import from configmap and secret from bitwarden 2026-02-11 21:36:46 +00:00
pi-ux-ce 8939736cdc working on terraform with bitwarden with success 2026-02-10 10:11:38 +00:00
pi-ux-ce aff67f5008 alot of deprecated modules 2026-02-06 10:40:20 +00:00
pi-ux-ce 56c957139c adding bitwarden and successfull migration 2026-02-05 11:28:48 +00:00
pi-ux-ce 2fc3e0d543 adding celery for django 2025-12-02 15:09:23 +00:00
pi-ux-ce 3a616a024b adding required files 2025-11-25 23:03:19 +00:00
pi-ux-ce 3b933c8fe1 change naming of svc to make them unique and quite some work on bitwarden 2025-11-25 23:02:26 +00:00
pi-ux-ce 594d0af218 adding bitwarden 2025-11-24 21:01:38 +00:00
pi-ux-ce b778662fa5 avoid duplicated PVC value: only one pvc of the same namespace/name will be created but multiple can be reused 2025-11-24 21:01:23 +00:00
pi-ux-ce ad69271f01 add files before tuching bitwarden 2025-11-24 19:28:18 +00:00
pi-ux-ce 652710a98a add these files 2025-08-12 10:23:59 +01:00
pi-ux-ce dca67792f6 upload files 2025-07-31 19:30:06 +01:00
pi-ux-ce ae83c9a258 adding oauthn and keycloak 2025-07-08 00:15:31 +01:00
pi-ux-ce a5e0e9a5c0 adding the command support 2025-07-08 00:15:14 +01:00
pi-ux-ce 6e07a68e90 enable django 2025-06-22 17:10:32 +01:00
pi-ux-ce 6ee3494165 try matching version of existing helm 2025-06-05 11:40:34 +01:00
pi-ux-ce 84e9172eac enable immich , still some work to do but close to the end 2025-06-03 23:04:25 +01:00
73 changed files with 9713 additions and 15046 deletions
+5
View File
@@ -39,3 +39,8 @@ terraform.rc
module.tf.save* module.tf.save*
terraform.tfstate* terraform.tfstate*
.terraform.lock.hcl .terraform.lock.hcl
.bw-provider-state
.claude
+1114 -265
View File
File diff suppressed because it is too large Load Diff
@@ -0,0 +1 @@
9fdbb94c-0fd5-4ce2-919f-1fbb596cd318
+119
View File
@@ -0,0 +1,119 @@
variable "cronjob" {
type = map(object({
name = optional(string)
image = string
enabled = bool
namespace = optional(string)
connected_namespace = optional(string, "")
schedule = string
command = optional(list(string))
args = optional(list(string))
pvc = optional(map(object({
name = string
pvc = optional(bool, false)
config_map = optional(bool, false)
secret = optional(bool, false)
host_path = optional(string)
pvc_size = optional(string)
storage_class_name = optional(string, "nfs-storage-intelligent")
annotations_fileType = optional(string)
existing_pvc = optional(bool, false)
mount_path = string
sub_path = optional(string)
})))
}))
}
locals {
pvc_list = flatten([
for key, value in var.cronjob : [
for index, pvc in value.pvc : {
key = "${coalesce(value.namespace, value.connected_namespace, key)}/${pvc.name}"
index = index
pvc = pvc.pvc
name = pvc.name
pvc_size = pvc.pvc_size
mount_path = pvc.mount_path
storage_class_name = pvc.storage_class_name
annotations_fileType = pvc.annotations_fileType
existing_pvc = pvc.existing_pvc
sub_path = pvc.sub_path
namespace = coalesce(value.namespace, value.connected_namespace, key)
}] if value.enabled == true && value.pvc != null
])
# group duplicates instead of throwing an error
pvc_map_grouped = {
for p in local.pvc_list :
p.key => p...
}
# keep only one PVC per key (take the first)
pvc_map = {
for k, list in local.pvc_map_grouped :
k => list[0]
}
pvc_details = values(local.pvc_map)
}
resource "kubernetes_persistent_volume_claim_v1" "automatic-pvc-cronjob" {
for_each = { for key, value in local.pvc_details : "${value.index}" => merge(value, { mew_key = value.index }) if value.pvc && value.existing_pvc != true }
metadata {
namespace = coalesce(each.value.namespace, each.key)
name = "${each.value.name}-pvc"
labels = {
deployment_method = "Terraform"
}
annotations = {
fileType = try(each.value.annotations_fileType, "file")
}
}
spec {
access_modes = ["ReadWriteMany"]
storage_class_name = each.value.storage_class_name
resources {
requests = {
storage = each.value.pvc_size
}
}
}
}
resource "kubernetes_cron_job_v1" "automatic_cronjob" {
for_each = { for key, value in var.cronjob : key => value if value.enabled == true }
metadata {
name = "${each.key}-cronjob"
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
labels = {
app = each.key
deployment_method = "Terraform"
}
}
spec {
schedule = each.value.schedule
job_template {
metadata {}
spec {
template {
metadata {}
spec {
container {
name = coalesce(each.value.name, each.key)
image = each.value.image
command = each.value.command != null ? each.value.command : []
args = each.value.args != null ? each.value.args : []
}
}
}
}
}
}
}
+172
View File
@@ -0,0 +1,172 @@
resource "kubernetes_deployment_v1" "database-automatic" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true && !(try(value.database.shunt, false)) }
metadata {
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
name = "${coalesce(each.value.name, each.key)}-db"
labels = {
app = each.key
deployment_method = "Terraform"
database = "true"
}
}
spec {
replicas = each.value.replicas
selector {
match_labels = {
app = "${each.key}-db"
}
}
template {
metadata {
labels = {
app = "${each.key}-db"
deployment_method = "Terraform"
database = "true"
}
}
spec {
container {
image = try(each.value.database.image, "docker.io/library/postgres:latest")
name = "${coalesce(each.value.name, each.key)}-db"
port {
container_port = 5432
name = "database-port"
}
volume_mount {
mount_path = try(each.value.database.mountPath, "/var/lib/postgresql/")
name = "${each.key}-db-pvc"
}
dynamic "volume_mount" {
for_each = try(each.value.database.engine == "sqlserver", false) && !(try(each.value.database.shunt, false)) ? [1] : []
content {
mount_path = "/backup"
name = "${each.key}-db-backup"
}
}
command = try([each.value.database.command], [])
args = each.value.database_args != null ? each.value.database_args : []
dynamic "env_from" {
for_each = each.value.database != null && each.value.enabled == true && !(try(each.value.database.shunt, false)) ? ["${each.key}-db-terraform"] : []
content {
dynamic "secret_ref" {
for_each = [1]
content {
name = env_from.value
}
}
}
}
dynamic "env" {
for_each = each.value.environment != null ? each.value.environment : {}
content {
name = env.key
value = env.value.value != null ? env.value.value : null
dynamic "value_from" {
for_each = env.value.value_from != null ? env.value.value_from : {}
content {
dynamic "secret_key_ref" {
for_each = [1]
content {
name = env.value.value_from.secret_key_ref.name
key = env.value.value_from.secret_key_ref.key
# optional = true
}
}
}
}
}
}
}
volume {
name = "${each.key}-db-pvc"
persistent_volume_claim {
claim_name = "${each.key}-db-pvc"
}
}
dynamic "volume" {
for_each = try(each.value.database.engine == "sqlserver", false) && !(try(each.value.database.shunt, false)) ? [1] : []
content {
name = "${each.key}-db-backup"
persistent_volume_claim {
claim_name = "${each.key}-db-backup"
}
}
}
}
}
}
}
resource "kubernetes_cron_job_v1" "database-backup" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true }
metadata {
name = "${coalesce(each.value.namespace, each.key)}-db-backup"
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
labels = {
app = each.key
deployment_method = "Terraform"
database = "true"
}
}
spec {
failed_jobs_history_limit = 5
schedule = "1 0 * * *"
timezone = "Etc/UTC"
successful_jobs_history_limit = 5
job_template {
metadata {}
spec {
backoff_limit = 4
ttl_seconds_after_finished = 100
template {
metadata {}
spec {
container {
name = "${coalesce(each.value.namespace, each.key)}-db-backup"
image = try(var.database_backup_info[each.value.database.engine].image, var.database_backup_info.postgres.image)
command = ["/bin/sh", "-c"]
args = [try(var.database_backup_info[each.value.database.engine].command, var.database_backup_info.postgres.command)]
env_from {
secret_ref {
name = "${each.key}-db-terraform"
}
}
volume_mount {
mount_path = "/backup"
name = "${each.key}-db-backup"
}
}
volume {
name = "${each.key}-db-backup"
persistent_volume_claim {
claim_name = "${each.key}-db-backup"
}
}
}
}
}
}
}
}
+252
View File
@@ -0,0 +1,252 @@
module "ingress" {
source = "../modules/ingress"
kubernetes_input = var.kubernetes
}
module "services" {
source = "../modules/services"
kubernetes_input = var.kubernetes
}
resource "kubernetes_deployment_v1" "automatic" {
for_each = { for key, value in var.kubernetes : key => value if value.enabled == true }
metadata {
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
name = coalesce(each.value.name, each.key)
labels = {
app = each.key
deployment_method = "Terraform"
}
}
spec {
replicas = each.value.replicas
selector {
match_labels = {
app = each.key
}
}
template {
metadata {
labels = {
app = each.key
deployment_method = "Terraform"
}
}
spec {
container {
image = each.value.image
name = coalesce(each.value.name, each.key)
dynamic "port" {
for_each = each.value.service_port != null ? each.value.service_port : []
content {
container_port = port.value
# name = "${each.key}-${port.value}"
name = replace("${port.value}${each.key}", "/(.{0,15})(.*)/", "$1")
}
}
dynamic "volume_mount" {
for_each = each.value.pvc != null ? each.value.pvc : {}
content {
mount_path = volume_mount.value.mount_path
name = "${volume_mount.value.name}-pvc"
sub_path = volume_mount.value.sub_path != null ? volume_mount.value.sub_path : ""
}
}
dynamic "volume_mount" {
for_each = try(each.value.database.engine == "sqlserver", false) && try(each.value.database.shunt, false) ? [1] : []
content {
mount_path = "/backup"
name = "${each.key}-db-backup"
}
}
dynamic "env_from" {
for_each = each.value.secret_ref != null ? each.value.secret_ref : []
content {
dynamic "secret_ref" {
for_each = [1]
content {
name = env_from.value
}
}
}
}
dynamic "env_from" {
for_each = each.value.database != null && each.value.enabled == true && !(try(each.value.database.shunt, false)) ? ["${each.key}-db-terraform"] : []
#for_each = each.value.database != null && each.value.enabled == true ? ["${each.key}-db-terraform"] : []
content {
dynamic "secret_ref" {
for_each = [1]
content {
name = env_from.value
}
}
}
}
dynamic "env_from" {
for_each = each.value.database != null && each.value.enabled == true ? ["${each.key}-db-mapped-terraform"] : []
content {
dynamic "secret_ref" {
for_each = [1]
content {
name = env_from.value
}
}
}
}
dynamic "env_from" {
for_each = each.value.config_map_ref != null ? each.value.config_map_ref : []
content {
dynamic "config_map_ref" {
for_each = [1]
content {
name = env_from.value
}
}
}
}
command = each.value.command != null ? each.value.command : []
dynamic "env" {
for_each = each.value.environment != null ? each.value.environment : {}
content {
name = env.key
value = env.value.value != null ? env.value.value : null
dynamic "value_from" {
for_each = env.value.value_from != null ? env.value.value_from : {}
content {
dynamic "secret_key_ref" {
for_each = [1]
content {
name = env.value.value_from.secret_key_ref.name
key = env.value.value_from.secret_key_ref.key
}
}
}
}
}
}
dynamic "resources" {
for_each = each.value.requirements != null ? [1] : []
content {
limits = {
cpu = each.value.requirements.limits-cpu
memory = each.value.requirements.limits-memory
}
requests = {
cpu = each.value.requirements.requests-cpu
memory = each.value.requirements.requests-memory
}
}
}
dynamic "security_context" {
for_each = each.value.security_context == true ? [1] : []
content {
privileged = true
#capabilities = {
# add : ["NET_ADMIN", "NET_RAW"]
#}
}
}
dynamic "liveness_probe" {
for_each = each.value.liveness_tcp_socket != null || each.value.liveness_http_get != null ? [""] : []
content {
dynamic "tcp_socket" {
for_each = each.value.liveness_tcp_socket != null ? [""] : []
content {
port = each.value.liveness_tcp_socket
}
}
dynamic "http_get" {
for_each = each.value.liveness_http_get != null ? [""] : []
content {
port = each.value.liveness_http_get
path = coalesce(each.value.liveness_http_get_path, "/")
}
}
initial_delay_seconds = 3
period_seconds = 3
}
}
}
dynamic "dns_config" {
for_each = each.value.dns_nameservers != null ? [1] : []
content {
nameservers = [each.value.dns_nameservers]
}
}
service_account_name = each.value.service_account_name != null ? each.value.service_account_name : null
dynamic "volume" {
for_each = each.value.pvc != null ? each.value.pvc : {}
content {
name = "${volume.value.name}-pvc"
dynamic "persistent_volume_claim" {
for_each = volume.value.pvc ? [1] : []
content {
claim_name = "${volume.value.name}-pvc"
}
}
dynamic "config_map" {
for_each = volume.value.config_map ? [1] : []
content {
name = volume.value.name
}
}
dynamic "host_path" {
for_each = volume.value.host_path != null ? [1] : []
content {
path = volume.value.host_path
}
}
dynamic "secret" {
for_each = volume.value.secret ? [1] : []
content {
secret_name = volume.value.name
}
}
}
}
dynamic "volume" {
for_each = try(each.value.database.engine == "sqlserver", false) && try(each.value.database.shunt, false) ? [1] : []
content {
name = "${each.key}-db-backup"
persistent_volume_claim {
claim_name = "${each.key}-db-backup"
}
}
}
}
}
}
depends_on = [kubernetes_persistent_volume_claim_v1.automatic-pvc]
}
+197
View File
@@ -0,0 +1,197 @@
terraform {
required_version = "> 0.8.0"
required_providers {
bitwarden-secrets = {
source = "bitwarden/bitwarden-secrets"
version = "0.5.4-pre"
}
}
}
provider "kubernetes" {
config_path = "~/.kube/config"
}
provider "bitwarden-secrets" {
api_url = "https://bitwarden.tryton.geeraert.eu/api"
identity_url = "https://bitwarden.tryton.geeraert.eu/identity"
access_token = "0.9f4b7c5f-e6e7-4eff-929e-b474016a2b9c.bMRELajGGb7qMuXXvzgCCJdDfxfTCS:mFDT7tHSi43KJSnkwvTSYg=="
organization_id = "a6361589-badd-4bde-9cb4-af8901161c0d"
}
variable "kubernetes" {
type = map(object({
name = optional(string)
image = string
pvc = optional(map(object({
name = string
pvc = optional(bool, false)
config_map = optional(bool, false)
secret = optional(bool, false)
host_path = optional(string)
pvc_size = optional(string)
storage_class_name = optional(string, "nfs-storage-intelligent")
annotations_fileType = optional(string)
existing_pvc = optional(bool, false)
mount_path = string
sub_path = optional(string)
})))
environment = optional(map(object({
name = optional(string)
value = optional(string)
value_from = optional(object({
secret_key_ref = object({
name = string
key = optional(string, null)
})
}))
})))
replicas = optional(number, 1)
namespace = optional(string)
connected_namespace = optional(string, "")
command = optional(list(string))
service_port = optional(list(number))
service_type = optional(string, "ClusterIP")
service_name = optional(string)
domain_name = optional(list(string))
liveness_tcp_socket = optional(number)
liveness_http_get = optional(string)
liveness_http_get_path = optional(string)
database = optional(map(string))
database_command = optional(list(string))
database_args = optional(list(string))
redis = optional(map(string))
enabled = optional(bool, true)
secret_ref = optional(list(string))
config_map_ref = optional(list(string))
config_map_import = optional(list(string))
secret_import = optional(list(string))
extra_manifest = optional(list(string))
requirements = optional(map(string))
# requirements = optional(map(string), {
# limits-cpu = "800m"
# limits-memory = "500Mi"
# requests-cpu = "200m"
# requests-memory = "200Mi"
# })
dns_nameservers = optional(string)
service_account_name = optional(string)
environment_variables = optional(map(string), { name = "value" })
security_context = optional(bool, false)
}))
}
variable "database_backup_info" {
type = map(object({
image = optional(string)
command = optional(string)
}))
description = "based on DB engine, give the docker image and the command used to backup"
default = {
postgres = {
image = "alpine/psql"
command = "pg_dump |gzip -9 > /backup/$(DB_DATABASE_NAME)-DB-$(date +%Y%m%d).sql.gz"
}
mysql = {
image = "mysql"
command = "mysqldump -h $DB_HOST -u $MYSQL_USER -p$MYSQL_ROOT_PASSWORD $MYSQL_DATABASE |gzip -9 > /backup/$(DB_DATABASE_NAME)-DB-$(date +%Y%m%d).sql.gz"
}
sqlserver = {
image = "mcr.microsoft.com/mssql-tools"
command = "/opt/mssql-tools/bin/sqlcmd -S $DB_HOST -U $DB_USERNAME -P $DB_PASSWORD -Q \"BACKUP DATABASE $DB_DATABASE_NAME TO DISK = '/backup/$DB_DATABASE_NAME-$(date +%Y%m%d).bak' WITH COPY_ONLY, CHECKSUM,FORMAT, MEDIANAME = 'SQLServerBackups',NAME = 'Full Backup of SQLTestDB'\";exit"
}
}
}
locals {
pvc_list = flatten([
for key, value in var.kubernetes : [
for index, pvc in value.pvc : {
key = "${coalesce(value.namespace, value.connected_namespace, key)}/${pvc.name}"
index = index
pvc = pvc.pvc
name = pvc.name
pvc_size = pvc.pvc_size
mount_path = pvc.mount_path
storage_class_name = pvc.storage_class_name
annotations_fileType = pvc.annotations_fileType
existing_pvc = pvc.existing_pvc
sub_path = pvc.sub_path
namespace = coalesce(value.namespace, value.connected_namespace, key)
}] if value.enabled == true && value.pvc != null
])
# group duplicates instead of throwing an error
pvc_map_grouped = {
for p in local.pvc_list :
p.key => p...
}
# keep only one PVC per key (take the first)
pvc_map = {
for k, list in local.pvc_map_grouped :
k => list[0]
}
pvc_details = values(local.pvc_map)
}
locals {
env_details = flatten([
for key, value in var.kubernetes : [
for index, env in value.environment_variables : {
index = index
name = env
}] if value.enabled == true && value.environment_variables != null
])
}
data "kubernetes_all_namespaces" "allns" {}
resource "kubernetes_namespace_v1" "automatic" {
for_each = { for key, value in var.kubernetes : key => value if value.enabled == true && value.connected_namespace == "" }
metadata {
annotations = {
name = coalesce(each.value.namespace, each.key)
}
labels = {
deployment_method = "Terraform"
}
name = coalesce(each.value.namespace, each.key)
}
depends_on = [data.kubernetes_all_namespaces.allns]
}
locals {
kubernetes_manifests = flatten([
for k, obj in var.kubernetes : [
for index, manifest in(obj.extra_manifest != null ? obj.extra_manifest : []) :
{
key = "${k}_${index}"
name = obj.name
manifest = manifest
enabled = obj.enabled
}
if obj.enabled == true
]
])
}
resource "kubernetes_manifest" "manifest" {
for_each = { for item in local.kubernetes_manifests : item.key => item }
manifest = yamldecode(file(each.value.manifest))
provider = kubernetes
}
+90
View File
@@ -0,0 +1,90 @@
############################################
# config file for ${name_site}
############################################
upstream ${name_site}_backend {
server ${name_service};
server 1.1.1.1 backup;
}
server {
server_name ${name_site}.tryton.geeraert.eu www.${name_site}.tryton.geeraert.eu;
location / {
proxy_pass http://${name_site}_backend;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
}
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
access_log /var/log/nginx/access.log my_custom_format;
access_log /var/log/nginx/ip_audit.log ip_audit;
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/live/tryton.geeraert.eu/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/live/tryton.geeraert.eu/privkey.pem;
}
server {
if ($host = www.${name_site}.tryton.geeraert.eu) {
return 301 https://$host$request_uri;
}
if ($host = ${name_site}.tryton.geeraert.eu) {
return 301 https://$host$request_uri;
}
server_name www.${name_site}.tryton.geeraert.eu ${name_site}.tryton.geeraert.eu;
listen 80;
return 404;
}
############################################
# config file for ${name_site}
############################################
upstream ${name_site}_backend_root {
server ${name_service};
server 1.1.1.1 backup;
}
server {
server_name ${name_site}.geeraert.eu www.${name_site}.geeraert.eu;
location / {
proxy_pass http://${name_site}_backend_root;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
}
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
access_log /var/log/nginx/access.log my_custom_format;
access_log /var/log/nginx/ip_audit.log ip_audit;
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/live/geeraert.eu/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/live/geeraert.eu/privkey.pem;
}
server {
if ($host = www.${name_site}.geeraert.eu) {
return 301 https://$host$request_uri;
}
if ($host = ${name_site}.geeraert.eu) {
return 301 https://$host$request_uri;
}
server_name www.${name_site}.geeraert.eu ${name_site}.geeraert.eu;
listen 80;
return 404;
}
+182
View File
@@ -0,0 +1,182 @@
resource "bitwarden-secrets_secret" "automatic_bitwarden_secret_redis_host" {
for_each = { for key, value in var.kubernetes : key => value if value.redis != null && value.enabled == true }
key = "${each.key}__redis__host"
project_id = "b5fc4c48-e951-442f-97ca-b3e800c143cd"
value = try(each.value.redis.host, "${each.key}-redis-svc.${coalesce(each.value.namespace, each.value.connected_namespace, each.key)}.svc")
}
resource "bitwarden-secrets_secret" "automatic_bitwarden_secret_redis_port" {
for_each = { for key, value in var.kubernetes : key => value if value.redis != null && value.enabled == true }
key = "${each.key}__redis__port"
project_id = "b5fc4c48-e951-442f-97ca-b3e800c143cd"
value = try(each.value.redis.port, 5432)
}
##
## Commenting until I use the redis password option
##
#resource "bitwarden-secrets_secret" "automatic_bitwarden_secret_redis_password" {
# for_each = { for key, value in var.kubernetes : key => value if value.redis != null && value.enabled == true }
# key = "${each.key}__redis__password"
# project_id = "b5fc4c48-e951-442f-97ca-b3e800c143cd"
# length = 32
# special = true
# min_special = 5
# avoid_ambiguous = true
#}
resource "bitwarden-secrets_secret" "automatic_bitwarden_secret_redis_REPLICATION_MODE" {
for_each = { for key, value in var.kubernetes : key => value if value.redis != null && value.enabled == true }
key = "${each.key}__redis__REPLICATION_MODE"
project_id = "b5fc4c48-e951-442f-97ca-b3e800c143cd"
value = try(each.value.redis.REPLICATION_MODE, "master")
}
resource "bitwarden-secrets_secret" "automatic_bitwarden_secret_redis_TLS_ENABLED" {
for_each = { for key, value in var.kubernetes : key => value if value.redis != null && value.enabled == true }
key = "${each.key}__redis__TLS_ENABLED"
project_id = "b5fc4c48-e951-442f-97ca-b3e800c143cd"
value = try(each.value.redis.TLS_ENABLED, "no")
}
resource "kubernetes_secret_v1" "automatic-redis-secret" {
for_each = { for key, value in var.kubernetes : key => value if value.redis != null && value.enabled == true }
metadata {
name = "${each.key}-redis-terraform"
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
}
data = {
REDIS_HOSTNAME = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_redis_host[each.key].value}"
REDIS_PORT = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_redis_port[each.key].value}"
REDIS_REPLICATION_MODE = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_redis_REPLICATION_MODE[each.key].value}"
REDIS_TLS_ENABLED = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_redis_TLS_ENABLED[each.key].value}"
}
}
resource "kubernetes_deployment_v1" "redis-automatic" {
for_each = { for key, value in var.kubernetes : key => value if value.redis != null && value.enabled == true }
metadata {
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
name = "${coalesce(each.value.name, each.key)}-redis"
labels = {
app = each.key
deployment_method = "Terraform"
redis = "true"
}
}
spec {
replicas = each.value.replicas
selector {
match_labels = {
app = "${each.key}-redis"
}
}
template {
metadata {
labels = {
app = "${each.key}-redis"
deployment_method = "Terraform"
redis = "true"
}
}
spec {
container {
image = try(each.value.redis.image, "docker.io/library/redis:7")
name = "${coalesce(each.value.name, each.key)}-redis"
port {
container_port = 6379
name = "redis-port"
}
volume_mount {
mount_path = "/data"
name = "${each.key}-redis-pvc"
}
dynamic "env" {
for_each = each.value.environment != null ? each.value.environment : {}
content {
name = env.key
value = env.value.value != null ? env.value.value : null
dynamic "value_from" {
for_each = env.value.value_from != null ? env.value.value_from : {}
content {
dynamic "secret_key_ref" {
for_each = [1]
content {
name = env.value.value_from.secret_key_ref.name
key = env.value.value_from.secret_key_ref.key
# optional = true
}
}
}
}
}
}
# resources {
# limits = {
# cpu = each.value.requirements.limits-cpu
# memory = each.value.requirements.limits-memory
# }
# requests = {
# cpu = each.value.requirements.requests-cpu
# memory = each.value.requirements.requests-memory
# }
# }
# dynamic "liveness_probe" {
# for_each = each.value.liveness_tcp_socket != null || each.value.liveness_http_get != null ? [""] : []
# content {
# dynamic "tcp_socket" {
# for_each = each.value.liveness_tcp_socket != null ? [""] : []
# content {
# port = each.value.liveness_tcp_socket
# }
# }
# dynamic "http_get" {
# for_each = each.value.liveness_http_get != null ? [""] : []
# content {
# port = each.value.liveness_http_get
# path = coalesce(each.value.liveness_http_get_path, "/")
# }
# }
# initial_delay_seconds = 3
# period_seconds = 3
# }
# }
}
volume {
name = "${each.key}-redis-pvc"
persistent_volume_claim {
claim_name = "${each.key}-redis-pvc"
}
}
}
}
}
}
+133
View File
@@ -0,0 +1,133 @@
data "bitwarden-secrets_secret" "configmap_import" {
for_each = {
for pair in flatten([
for k, v in var.kubernetes : [
for id in v.config_map_import : {
map_key = k
secret_id = id
}
] if v.config_map_import != null && v.enabled == true
]) : "${pair.map_key}-${pair.secret_id}" => pair.secret_id
}
id = each.value
}
resource "kubernetes_config_map_v1" "configmap_import" {
for_each = { for key, value in data.bitwarden-secrets_secret.configmap_import : key => value }
metadata {
name = each.value.note
namespace = split("__", each.value.key)[0]
}
data = yamldecode(each.value.value)
}
data "bitwarden-secrets_secret" "secret_import" {
for_each = {
for pair in flatten([
for k, v in var.kubernetes : [
for id in v.secret_import : {
map_key = k
secret_id = id
}
] if v.secret_import != null && v.enabled == true
]) : "${pair.map_key}-${pair.secret_id}" => pair.secret_id
}
id = each.value
}
resource "kubernetes_secret_v1" "secret_import" {
for_each = { for key, value in data.bitwarden-secrets_secret.secret_import : key => value }
metadata {
name = each.value.note
namespace = split("__", each.value.key)[0]
}
data = yamldecode(each.value.value)
}
resource "kubernetes_secret_v1" "automatic-database-secret" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true }
metadata {
name = "${each.key}-db-terraform"
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
}
data = {
DB_DATABASE_NAME = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_name[each.key].value}"
DB_DATABASE = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_name[each.key].value}"
POSTGRES_DB = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_name[each.key].value}"
MYSQL_DATABASE = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_name[each.key].value}"
PGDATABASE = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_name[each.key].value}"
DB_HOST = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_host[each.key].value}"
PGHOST = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_host[each.key].value}"
POSTGRES_HOST = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_host[each.key].value}"
DB_PASSWORD = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_password[each.key].value}"
MYSQL_PASSWORD = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_password[each.key].value}"
MYSQL_ROOT_PASSWORD = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_password[each.key].value}"
POSTGRES_PASSWORD = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_password[each.key].value}"
PGPASSWORD = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_password[each.key].value}"
DB_USERNAME = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_username[each.key].value}"
POSTGRES_USER = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_username[each.key].value}"
MYSQL_USER = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_username[each.key].value}"
PGUSER = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_username[each.key].value}"
DATABASE_URL = "postgresql://${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_username[each.key].value}:${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_password[each.key].value}@${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_host[each.key].value}:${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_port[each.key].value}/${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_name[each.key].value}"
}
}
resource "kubernetes_secret_v1" "automatic-database-mapped-secret" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true }
metadata {
name = "${each.key}-db-mapped-terraform"
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
}
data = {
"${try(each.value.database.map_name, "DB_DATABASE_NAME")}" = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_name[each.key].value}"
"${try(each.value.database.map_host, "DB_DATABASE_NAME")}" = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_host[each.key].value}"
"${try(each.value.database.map_password, "DB_DATABASE_NAME")}" = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_password[each.key].value}"
"${try(each.value.database.map_username, "DB_DATABASE_NAME")}" = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_username[each.key].value}"
}
}
resource "bitwarden-secrets_secret" "automatic_bitwarden_secret_db_username" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true }
key = "${each.key}__db__username"
value = try(each.value.database.username, each.key)
project_id = "b5fc4c48-e951-442f-97ca-b3e800c143cd"
}
resource "bitwarden-secrets_secret" "automatic_bitwarden_secret_db_password" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true }
key = "${each.key}__db__password"
project_id = "b5fc4c48-e951-442f-97ca-b3e800c143cd"
length = 32
special = true
min_special = 5
avoid_ambiguous = true
}
resource "bitwarden-secrets_secret" "automatic_bitwarden_secret_db_host" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true }
key = "${each.key}__db__host"
project_id = "b5fc4c48-e951-442f-97ca-b3e800c143cd"
value = try(each.value.database.host, "${each.key}-db-svc.${coalesce(each.value.namespace, each.value.connected_namespace, each.key)}.svc")
}
resource "bitwarden-secrets_secret" "automatic_bitwarden_secret_db_port" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true }
key = "${each.key}__db__port"
project_id = "b5fc4c48-e951-442f-97ca-b3e800c143cd"
value = try(each.value.database.port, 5432)
}
resource "bitwarden-secrets_secret" "automatic_bitwarden_secret_db_name" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true }
key = "${each.key}__db__name"
project_id = "b5fc4c48-e951-442f-97ca-b3e800c143cd"
value = try(each.value.database.name, each.key)
}
File diff suppressed because it is too large Load Diff
+134
View File
@@ -0,0 +1,134 @@
resource "kubernetes_deployment_v1" "database-automatic" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true && !(try(value.database.shunt, false)) && value.docker != true }
metadata {
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
name = "${coalesce(each.value.name, each.key)}-db"
labels = {
app = each.key
deployment_method = "Terraform"
database = "true"
}
}
spec {
replicas = each.value.replicas
selector {
match_labels = {
app = "${each.key}-db"
}
}
template {
metadata {
labels = {
app = "${each.key}-db"
deployment_method = "Terraform"
database = "true"
}
}
spec {
container {
image = try(each.value.database.image, "docker.io/library/postgres:latest")
name = "${coalesce(each.value.name, each.key)}-db"
port {
container_port = 5432
name = "database-port"
}
volume_mount {
mount_path = try(each.value.database.mountPath, "/var/lib/postgresql/")
name = "${each.key}-db-volume"
}
dynamic "volume_mount" {
for_each = try(each.value.database.engine == "sqlserver", false) && !(try(each.value.database.shunt, false)) ? [1] : []
content {
mount_path = "/backup"
name = "${each.key}-db-backup"
}
}
command = try([each.value.database.command], [])
args = each.value.database_args != null ? each.value.database_args : []
dynamic "env" {
for_each = each.value.environment != null ? each.value.environment : {}
content {
name = env.key
value = env.value.value != null ? env.value.value : null
dynamic "value_from" {
for_each = env.value.value_from != null ? env.value.value_from : {}
content {
dynamic "secret_key_ref" {
for_each = [1]
content {
name = env.value.value_from.secret_key_ref.name
key = env.value.value_from.secret_key_ref.key
}
}
}
}
}
}
}
volume {
name = "${each.key}-db-volume"
host_path {
path = try(each.value.database.host_path, join("/", [var.storage_path.main_storage, coalesce(each.value.namespace, each.value.connected_namespace, each.key), join("-", [each.key, "db"])]))
}
}
dynamic "volume" {
for_each = try(each.value.database.engine == "sqlserver", false) && !(try(each.value.database.shunt, false)) ? [1] : []
content {
name = "${each.key}-db-backup"
host_path {
path = join("/", [var.storage_path.fast_access, "Backup", coalesce(each.value.namespace, each.value.connected_namespace, each.key), "${each.key}-db-backup"])
}
}
}
}
}
}
}
resource "docker_container" "database-automatic" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true && !(try(value.database.shunt, false)) && value.docker == true }
image = try(each.value.database.image, "docker.io/library/postgres:latest")
name = "${coalesce(each.value.name, each.key)}-db"
hostname = "${coalesce(each.value.name, each.key)}-db"
networks_advanced {
name = docker_network.terraform_network[0].name
}
#no ports as they should be able to speak within the same network
volumes {
container_path = try(each.value.database.mountPath, "/var/lib/postgresql/")
host_path = each.value.database.host_path
}
env = [
for key, value in(each.value.environment != null ? each.value.environment : {}) :
"${key}=${value.value != null ? value.value : ""}"
]
}
+250
View File
@@ -0,0 +1,250 @@
resource "kubernetes_deployment_v1" "automatic" {
for_each = { for key, value in var.kubernetes : key => value if value.enabled == true && value.docker != true }
metadata {
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
name = coalesce(each.value.name, each.key)
labels = {
app = each.key
deployment_method = "Terraform"
}
}
spec {
replicas = each.value.replicas
selector {
match_labels = {
app = each.key
}
}
template {
metadata {
labels = {
app = each.key
deployment_method = "Terraform"
}
}
spec {
container {
image = each.value.image
name = coalesce(each.value.name, each.key)
dynamic "port" {
for_each = each.value.service_port != null ? each.value.service_port : []
content {
container_port = port.value
# name = "${each.key}-${port.value}"
name = replace("${port.value}${each.key}", "/(.{0,15})(.*)/", "$1")
}
}
dynamic "volume_mount" {
for_each = each.value.pvc != null ? each.value.pvc : {}
content {
mount_path = volume_mount.value.mount_path
name = "${volume_mount.key}-volume"
sub_path = volume_mount.value.sub_path != null ? volume_mount.value.sub_path : ""
}
}
dynamic "volume_mount" {
for_each = try(each.value.database.engine == "sqlserver", false) && try(each.value.database.shunt, false) ? [1] : []
content {
mount_path = "/backup"
name = "${each.key}-db-backup"
}
}
dynamic "env_from" {
for_each = each.value.secret_ref != null ? each.value.secret_ref : []
content {
dynamic "secret_ref" {
for_each = [1]
content {
name = env_from.value
}
}
}
}
dynamic "env_from" {
for_each = each.value.config_map_ref != null ? each.value.config_map_ref : []
content {
dynamic "config_map_ref" {
for_each = [1]
content {
name = env_from.value
}
}
}
}
command = each.value.command != null ? each.value.command : []
dynamic "env" {
for_each = each.value.environment != null ? each.value.environment : {}
content {
name = env.key
value = env.value.value != null ? env.value.value : null
dynamic "value_from" {
for_each = env.value.value_from != null ? env.value.value_from : {}
content {
dynamic "secret_key_ref" {
for_each = [1]
content {
name = env.value.value_from.secret_key_ref.name
key = env.value.value_from.secret_key_ref.key
}
}
}
}
}
}
dynamic "resources" {
for_each = each.value.requirements != null ? [1] : []
content {
limits = {
cpu = each.value.requirements.limits-cpu
memory = each.value.requirements.limits-memory
}
requests = {
cpu = each.value.requirements.requests-cpu
memory = each.value.requirements.requests-memory
}
}
}
dynamic "security_context" {
for_each = each.value.security_context == true ? [1] : []
content {
privileged = true
#capabilities = {
# add : ["NET_ADMIN", "NET_RAW"]
#}
}
}
dynamic "liveness_probe" {
for_each = each.value.liveness_tcp_socket != null || each.value.liveness_http_get != null ? [""] : []
content {
dynamic "tcp_socket" {
for_each = each.value.liveness_tcp_socket != null ? [""] : []
content {
port = each.value.liveness_tcp_socket
}
}
dynamic "http_get" {
for_each = each.value.liveness_http_get != null ? [""] : []
content {
port = each.value.liveness_http_get
path = coalesce(each.value.liveness_http_get_path, "/")
}
}
initial_delay_seconds = 3
period_seconds = 3
}
}
}
dynamic "dns_config" {
for_each = each.value.dns_nameservers != null ? [1] : []
content {
nameservers = [each.value.dns_nameservers]
}
}
service_account_name = each.value.service_account_name != null ? each.value.service_account_name : null
dynamic "volume" {
for_each = each.value.pvc != null ? each.value.pvc : {}
content {
name = "${volume.key}-volume"
dynamic "config_map" {
for_each = volume.value.config_map ? [1] : []
content {
name = volume.key
}
}
dynamic "host_path" {
for_each = volume.value.host_path != null || (!(volume.value.config_map) && !(volume.value.secret)) ? [1] : []
content {
path = coalesce(volume.value.host_path, join("/", [var.storage_path.main_storage, coalesce(each.value.namespace, each.value.connected_namespace, each.key), volume.key]))
}
}
dynamic "secret" {
for_each = volume.value.secret ? [1] : []
content {
secret_name = volume.key
}
}
}
}
dynamic "volume" {
for_each = try(each.value.database.engine == "sqlserver", false) && try(each.value.database.shunt, false) ? [1] : []
content {
name = "${each.key}-db-backup"
host_path {
path = join("/", [var.storage_path.fast_access, "Backup", coalesce(each.value.namespace, each.value.connected_namespace, each.key), "${each.key}-db-backup"])
}
}
}
}
}
}
}
resource "docker_container" "deployment-automatic" {
for_each = { for key, value in var.kubernetes : key => value if value.enabled == true && value.docker == true }
image = each.value.image
name = coalesce(each.value.name, each.key)
hostname = coalesce(each.value.name, each.key)
depends_on = [docker_container.database-automatic]
networks_advanced {
name = "deployment_network"
}
dynamic "ports" {
for_each = each.value.service_port != null ? each.value.service_port : []
content {
internal = ports.value
external = each.value.external_port ? ports.value : null
}
}
dynamic "volumes" {
for_each = each.value.pvc != null ? each.value.pvc : {}
content {
container_path = volumes.value.mount_path
host_path = volumes.value.host_path
}
}
env = [
for key, value in(each.value.environment != null ? each.value.environment : {}) :
"${key}=${value.value != null ? value.value : ""}"
]
# null keeps the image's default command; [] would differ from it in state and force replacement
command = each.value.command
}
+73
View File
@@ -0,0 +1,73 @@
resource "helm_release" "cert_manager" {
name = "cert-manager"
repository = "oci://quay.io"
chart = "jetstack/charts/cert-manager"
version = "v1.21.2"
namespace = "cert-manager"
create_namespace = true
wait = false
set = [
{
name = "crds.enabled"
value = "true"
}
]
}
resource "helm_release" "nginx_ingress" {
name = "traefik"
repository = "https://traefik.github.io/charts"
chart = "traefik"
version = "v41.7.1"
namespace = "traefik"
create_namespace = true
wait = false
set = [
{
name = "ports.web.nodePort"
value = "80"
},
{
name = "ports.websecure.nodePort"
value = "443"
},
{
name = "service.type"
value = "NodePort"
}
]
}
resource "kubernetes_manifest" "letsencrypt_prod" {
manifest = {
"apiVersion" = "cert-manager.io/v1"
"kind" = "ClusterIssuer"
"metadata" = {
"name" = "letsencrypt-prod"
}
"spec" = {
"acme" = {
"email" = "franckrobbin6@gmail.com"
"privateKeySecretRef" = {
"name" = "letsencrypt-prod-account-key"
}
"server" = "https://acme-v02.api.letsencrypt.org/directory"
"solvers" = [
{
"http01" = {
"ingress" = {
"class" = "traefik"
}
}
}
]
}
}
}
}
+143
View File
@@ -0,0 +1,143 @@
terraform {
required_version = "> 0.8.0"
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "4.6.0"
}
}
}
provider "kubernetes" {
config_path = "~/.kube/config"
}
provider "docker" {
host = "unix:///var/run/docker.sock"
}
provider "helm" {
kubernetes = {
config_path = "~/.kube/config"
}
}
variable "kubernetes" {
type = map(object({
name = optional(string)
docker = optional(bool)
image = string
pvc = optional(map(object({
name = optional(string)
config_map = optional(bool, false)
secret = optional(bool, false)
local_path = optional(bool, false)
host_path = optional(string)
storage_class_name = optional(string, "nfs-storage-intelligent")
annotations_fileType = optional(string)
mount_path = string
sub_path = optional(string)
})))
environment = optional(map(object({
name = optional(string)
value = optional(string)
value_from = optional(object({
secret_key_ref = object({
name = string
key = optional(string, null)
})
}))
})))
replicas = optional(number, 1)
namespace = optional(string)
connected_namespace = optional(string, "")
command = optional(list(string))
service_port = optional(list(number))
external_port = optional(bool, false)
service_type = optional(string, "ClusterIP")
service_name = optional(string)
domain_name = optional(list(string))
legacy_domain = optional(bool, false)
exposed = optional(bool, true)
liveness_tcp_socket = optional(number)
liveness_http_get = optional(string)
liveness_http_get_path = optional(string)
database = optional(map(string))
database_command = optional(list(string))
database_args = optional(list(string))
redis = optional(map(string))
enabled = optional(bool, true)
secret_ref = optional(list(string))
config_map_ref = optional(list(string))
config_map_import = optional(list(string))
secret_import = optional(list(string))
extra_manifest = optional(list(string))
requirements = optional(map(string))
dns_nameservers = optional(string)
service_account_name = optional(string)
environment_variables = optional(map(string), { name = "value" })
security_context = optional(bool, false)
}))
}
variable "shunt_docker" {
type = bool
default = true
}
variable "storage_path" {
type = map(string)
default = {
main_storage = "/data/kubernetes",
fast_access = "/ssd"
}
}
locals {
env_details = flatten([
for key, value in var.kubernetes : [
for index, env in value.environment_variables : {
index = index
name = env
}] if value.enabled == true && value.environment_variables != null && value.docker != true
])
}
locals {
kubernetes_manifests = flatten([
for k, obj in var.kubernetes : [
for index, manifest in(obj.extra_manifest != null ? obj.extra_manifest : []) :
{
key = "${k}_${index}"
name = obj.name
manifest = manifest
enabled = obj.enabled
}
if obj.enabled == true
]
])
}
resource "kubernetes_manifest" "manifest" {
for_each = { for item in local.kubernetes_manifests : item.key => item }
manifest = yamldecode(file(each.value.manifest))
provider = kubernetes
}
resource "kubernetes_namespace_v1" "automatic" {
for_each = { for key, value in var.kubernetes : key => value if value.enabled == true && value.connected_namespace == "" }
metadata {
annotations = {
name = coalesce(each.value.namespace, each.key)
}
labels = {
deployment_method = "Terraform"
}
name = coalesce(each.value.namespace, each.key)
}
}
+125
View File
@@ -0,0 +1,125 @@
resource "kubernetes_deployment_v1" "redis-automatic" {
for_each = { for key, value in var.kubernetes : key => value if value.redis != null && value.enabled == true && value.docker != true }
metadata {
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
name = "${coalesce(each.value.name, each.key)}-redis"
labels = {
app = each.key
deployment_method = "Terraform"
redis = "true"
}
}
spec {
replicas = each.value.replicas
selector {
match_labels = {
app = "${each.key}-redis"
}
}
template {
metadata {
labels = {
app = "${each.key}-redis"
deployment_method = "Terraform"
redis = "true"
}
}
spec {
container {
image = try(each.value.redis.image, "docker.io/library/redis:7")
name = "${coalesce(each.value.name, each.key)}-redis"
port {
container_port = 6379
name = "redis-port"
}
volume_mount {
mount_path = "/data"
name = "${each.key}-redis-volume"
}
dynamic "env" {
for_each = each.value.environment != null ? each.value.environment : {}
content {
name = env.key
value = env.value.value != null ? env.value.value : null
dynamic "value_from" {
for_each = env.value.value_from != null ? env.value.value_from : {}
content {
dynamic "secret_key_ref" {
for_each = [1]
content {
name = env.value.value_from.secret_key_ref.name
key = env.value.value_from.secret_key_ref.key
# optional = true
}
}
}
}
}
}
# resources {
# limits = {
# cpu = each.value.requirements.limits-cpu
# memory = each.value.requirements.limits-memory
# }
# requests = {
# cpu = each.value.requirements.requests-cpu
# memory = each.value.requirements.requests-memory
# }
# }
# dynamic "liveness_probe" {
# for_each = each.value.liveness_tcp_socket != null || each.value.liveness_http_get != null ? [""] : []
# content {
# dynamic "tcp_socket" {
# for_each = each.value.liveness_tcp_socket != null ? [""] : []
# content {
# port = each.value.liveness_tcp_socket
# }
# }
# dynamic "http_get" {
# for_each = each.value.liveness_http_get != null ? [""] : []
# content {
# port = each.value.liveness_http_get
# path = coalesce(each.value.liveness_http_get_path, "/")
# }
# }
# initial_delay_seconds = 3
# period_seconds = 3
# }
# }
}
volume {
name = "${each.key}-redis-volume"
host_path {
path = try(each.value.redis.host_path, join("/", [var.storage_path.main_storage, coalesce(each.value.namespace, each.value.connected_namespace, each.key), join("-", [each.key, "redis"])]))
}
}
}
}
}
}
+18
View File
@@ -0,0 +1,18 @@
module "ingress" {
source = "../modules/ingress"
kubernetes_input = var.kubernetes
}
module "services" {
source = "../modules/services"
kubernetes_input = var.kubernetes
}
resource "docker_network" "terraform_network" {
#avoiding this to create if the shunt_docker is on
count = var.shunt_docker ? 0 : 1
name = "deployment_network"
}
+376
View File
@@ -0,0 +1,376 @@
kubernetes = {
echo = {
#enabled = false
#docker = true
image = "ealen/echo-server:latest"
service_port = [4580]
external_port = true
service_type = "NodePort"
domain_name = ["echo", "hello"]
#command = ["-text=Hello authenticated world!"]
pvc = {
echo-config = {
mount_path = "/app/configs"
}
echo-testing = {
mount_path = "/app/test"
}
}
environment = {
PORT = {
value = 4580
}
PAPERLESS_REDIS = {
value = "redis://paperless-redis-svc:6379"
}
database = {
value = "datgg"
}
}
}
gitea = {
#enabled = false
#docker = true
image = "gitea/gitea:1.27.0"
service_port = [3000]
# no service_port: nginx reaches http://gitea:3000 over deployment_network
database = {
image = "postgres:17"
mountPath = "/var/lib/postgresql/data"
host_path = "/data/kubernetes/gitea/gitea-db-data"
}
# shared by the gitea and gitea-db containers (the db ignores GITEA__*, gitea ignores POSTGRES_*)
environment = {
POSTGRES_USER = { value = "gitea-KY56Q" }
POSTGRES_PASSWORD = { value = "Modulator-Yearning-Gills3" }
POSTGRES_DB = { value = "gitea-database" }
GITEA__database__DB_TYPE = { value = "postgres" }
#GITEA__database__HOST = { value = "gitea-db:5432" } # for docker
GITEA__database__HOST = { value = "gitea-db-svc:5432" } # for k8s
GITEA__database__USER = { value = "gitea-KY56Q" }
GITEA__database__PASSWD = { value = "Modulator-Yearning-Gills3" }
GITEA__database__NAME = { value = "gitea-database" }
}
pvc = {
gitea-data = {
name = "gitea-data"
mount_path = "/data"
host_path = "/data/kubernetes/gitea/gitea-data"
}
gitea-documents-backup = {
name = "gitea-documents-backup"
mount_path = "/backup"
host_path = "/data/kubernetes/gitea/gitea-documents-backup"
}
}
}
gitea-runner = {
#enabled = false
#docker = true
image = "gitea/act_runner:latest"
exposed = false
connected_namespace = "gitea"
environment = {
GITEA_INSTANCE_URL = { value = "https://gitea.geeraert.eu/" }
GITEA_RUNNER_REGISTRATION_TOKEN = { value = "rqi4mFW8LXoc5MhIrUD1rjzdmKVY8n9X14BP6sWd" }
GITEA_RUNNER_NAME = { value = "runner" }
GITEA_RUNNER_LABELS = { value = "label" }
}
pvc = {
gitea-runner-data = {
name = "gitea-runner-data"
mount_path = "/data"
host_path = "/data/kubernetes/gitea/gitea-runner-data"
}
docker-sock = {
name = "docker-sock"
mount_path = "/var/run/docker.sock"
host_path = "/var/run/docker.sock"
}
}
}
bitwarden-admin = {
#enabled = false
namespace = "bitwarden"
replicas = 1
name = "bitwarden-admin"
image = "ghcr.io/bitwarden/admin:2026.1.0"
extra_manifest = ["../external_manifests/bitwarden/config.configmap.yml", "../external_manifests/bitwarden/global.env.configmap.yml", "../external_manifests/bitwarden/global.override.env.configmap.yml", "../external_manifests/bitwarden/mssql.env.configmap.yml", "../external_manifests/bitwarden/mssql.override.env.configmap.yml", "../external_manifests/bitwarden/uid.env.configmap.yml", "../external_manifests/bitwarden/bitwarden-identity-cert-password.secret.yml"]
service_port = [5000]
exposed = false
config_map_ref = ["global.env", "uid.env", "global.override.env"]
environment = {}
pvc = {
bitwarden-ca-certificates-pvc = {
mount_path = "/etc/bitwarden/ca-certificates"
}
bitwarden-core-pvc = {
mount_path = "/etc/bitwarden/core"
}
bitwarden-logs-pvc = {
mount_path = "/etc/bitwarden/logs"
sub_path = "admin"
}
}
}
bitwarden-api = {
#enabled = false
connected_namespace = "bitwarden"
replicas = 1
name = "bitwarden-api"
image = "gitea.tryton.geeraert.eu/pi-ux-ce/bitbetter_api:2026.1.0"
service_port = [5000]
exposed = false
config_map_ref = ["global.env", "uid.env", "global.override.env"]
environment = {}
pvc = {
bitwarden-ca-certificates-pvc = {
mount_path = "/etc/bitwarden/ca-certificates"
}
bitwarden-core-pvc = {
mount_path = "/etc/bitwarden/core"
}
bitwarden-logs-pvc = {
mount_path = "/etc/bitwarden/logs"
sub_path = "api"
}
}
}
bitwarden-attachments = {
#enabled = false
connected_namespace = "bitwarden"
replicas = 1
name = "bitwarden-attachments"
image = "ghcr.io/bitwarden/attachments:2026.1.0"
service_port = [5000]
exposed = false
config_map_ref = ["global.env", "uid.env"]
environment = {}
pvc = {
bitwarden-core-pvc = {
mount_path = "/etc/bitwarden/core/attachments"
sub_path = "attachments"
}
}
}
bitwarden-events = {
#enabled = false
connected_namespace = "bitwarden"
replicas = 1
name = "bitwarden-events"
image = "ghcr.io/bitwarden/events:2026.1.0"
service_port = [5000]
exposed = false
config_map_ref = ["global.env", "uid.env", "global.override.env"]
environment = {}
pvc = {
bitwarden-ca-certificates-pvc = {
mount_path = "/etc/bitwarden/ca-certificates"
}
bitwarden-logs-pvc = {
mount_path = "/etc/bitwarden/logs"
sub_path = "events"
}
}
}
bitwarden-icons = {
#enabled = false
connected_namespace = "bitwarden"
replicas = 1
name = "bitwarden-icons"
image = "ghcr.io/bitwarden/icons:2026.1.0"
service_port = [5000]
exposed = false
config_map_ref = ["global.env", "uid.env"]
environment = {}
pvc = {
bitwarden-ca-certificates-pvc = {
mount_path = "/etc/bitwarden/ca-certificates"
}
bitwarden-logs-pvc = {
mount_path = "/etc/bitwarden/logs"
sub_path = "icons"
}
}
}
bitwarden-identity = {
#enabled = false
connected_namespace = "bitwarden"
replicas = 1
name = "bitwarden-identity"
image = "gitea.tryton.geeraert.eu/pi-ux-ce/bitbetter_identity:2026.1.0"
service_port = [5000]
exposed = false
config_map_ref = ["global.env", "uid.env", "global.override.env"]
environment = {}
pvc = {
bitwarden-identity-pvc = {
mount_path = "/etc/bitwarden/identity"
}
bitwarden-ca-certificates-pvc = {
mount_path = "/etc/bitwarden/ca-certificates"
}
bitwarden-core-pvc = {
mount_path = "/etc/bitwarden/core"
}
bitwarden-logs-pvc = {
mount_path = "/etc/bitwarden/logs"
sub_path = "identity"
}
}
}
bitwarden-mssql = {
#enabled = false
connected_namespace = "bitwarden"
replicas = 1
name = "bitwarden-mssql"
image = "ghcr.io/bitwarden/mssql:2026.1.0"
service_port = [1433, 5000]
exposed = false
config_map_ref = ["mssql.env", "uid.env", "mssql.override.env"]
environment = {}
database = {
shunt = "true"
engine = "sqlserver"
username = "sa"
host = "bitwarden-mssql-svc"
name = "bitwarden_vault"
}
pvc = {
bitwarden-mssql-pvc = {
mount_path = "/var/opt/mssql/data"
sub_path = "data"
}
bitwarden-logs-pvc = {
mount_path = "/etc/bitwarden/logs"
sub_path = "mssql"
}
}
}
bitwarden-nginx = {
#enabled = false
connected_namespace = "bitwarden"
replicas = 1
name = "bitwarden-nginx"
image = "ghcr.io/bitwarden/nginx:2026.1.0"
service_port = [8080, 5000, 8443]
exposed = true #no need to set as true but I did it for easy access
legacy_domain = true
domain_name = ["bitwarden"]
config_map_ref = ["uid.env"]
environment = {}
pvc = {
bitwarden-nginx-pvc = {
mount_path = "/etc/bitwarden/nginx"
}
bitwarden-letsencrypt-pvc = {
mount_path = "/etc/letsencrypt"
}
bitwarden-ssl-pvc = {
mount_path = "/etc/ssl"
}
bitwarden-logs-pvc = {
mount_path = "/var/log/nginx"
sub_path = "nginx"
}
}
}
bitwarden-notifications = {
#enabled = false
connected_namespace = "bitwarden"
replicas = 1
name = "bitwarden-notifications"
image = "ghcr.io/bitwarden/notifications:2026.1.0"
service_port = [5000]
exposed = false
config_map_ref = ["global.env", "uid.env", "global.override.env"]
environment = {}
pvc = {
bitwarden-ca-certificates-pvc = {
mount_path = "/etc/bitwarden/ca-certificates"
name = "bitwarden-ca-certificates-pvc"
}
bitwarden-logs-pvc = {
mount_path = "/etc/bitwarden/logs"
sub_path = "notifications"
}
}
}
bitwarden-sso = {
#enabled = false
connected_namespace = "bitwarden"
replicas = 1
name = "bitwarden-sso"
image = "ghcr.io/bitwarden/sso:2026.1.0"
service_port = [5000]
exposed = false
config_map_ref = ["global.env", "uid.env", "global.override.env"]
environment = {}
pvc = {
bitwarden-identity-pvc = {
mount_path = "/etc/bitwarden/identity"
}
bitwarden-core-pvc = {
mount_path = "/etc/bitwarden/core"
}
bitwarden-ca-certificates-pvc = {
mount_path = "/etc/bitwarden/ca-certificates"
}
bitwarden-logs-pvc = {
mount_path = "/etc/bitwarden/logs"
sub_path = "sso"
}
}
}
bitwarden-web = {
#enabled = false
connected_namespace = "bitwarden"
replicas = 1
name = "bitwarden-web"
image = "ghcr.io/bitwarden/web:2026.1.0"
service_port = [5000]
exposed = false
config_map_ref = ["global.env", "uid.env"]
environment = {}
pvc = {
bitwarden-web-pvc = {
mount_path = "/etc/bitwarden/web"
}
}
}
}
@@ -0,0 +1,6 @@
apiVersion: v1
kind: Secret
metadata:
name: bitwarden-identity-cert-password
namespace: bitwarden
type: Opaque
@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: bitwarden-mssql-nodeport
namespace: bitwarden
spec:
ports:
- name: 1433bitwarden-m
nodePort: 31433
port: 1433
protocol: TCP
targetPort: 1433
selector:
app: bitwarden-mssql
type: NodePort
@@ -0,0 +1,46 @@
apiVersion: batch/v1
kind: CronJob
metadata:
name: bitwarden-calendar-backup
namespace: bitwarden
spec:
schedule: "0 0 * * *"
jobTemplate:
spec:
backoffLimit: 4
ttlSecondsAfterFinished: 100
template:
spec:
containers:
- name: bitwarden-database-backup
image: mcr.microsoft.com/mssql-tools
envFrom:
- secretRef:
name: bitwarden-mssql-db-terraform
optional: false
command: ["/bin/sh","-c"]
#args: ["mysqldump -h $DB_HOST -u $MYSQL_USER -p$MYSQL_ROOT_PASSWORD $MYSQL_DATABASE |gzip -9 > /backup/$(DB_DATABASE_NAME)-DB-$(date +%Y%m%d).sql.gz "]
args: ["sleep 3600"]
volumeMounts:
- name: backup
mountPath: /backup
volumes:
- name: backup
persistentVolumeClaim:
claimName: bitwarden-database-backup
restartPolicy: Never
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: bitwarden-database-backup
namespace: bitwarden
annotations:
fileType: Backup
spec:
storageClassName: nfs-storage-fastaccess
accessModes:
- ReadWriteMany
resources:
requests:
storage: 2Gi
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,11 @@
apiVersion: v1
data:
APP_URL: https://bookstack.tryton.geeraert.eu
LOCAL_GID: "1000"
LOCAL_UID: "1000"
TZ: Europe/London
kind: ConfigMap
metadata:
name: config
namespace: bitwarden
@@ -0,0 +1,20 @@
apiVersion: v1
data:
ACCEPT_EULA: "Y"
ASPNETCORE_ENVIRONMENT: Production
globalSettings__baseServiceUri__vault: http://localhost
globalSettings__pushRelayBaseUri: https://push.bitwarden.com
globalSettings__selfHosted: "true"
globalSettings__baseServiceUri__internalNotifications: "http://bitwarden-notifications-svc:5000"
globalSettings__baseServiceUri__internalAdmin: "http://bitwarden-admin-svc:5000"
globalSettings__baseServiceUri__internalIdentity: "http://bitwarden-identity-svc:5000"
globalSettings__baseServiceUri__internalApi: "http://bitwarden-api-svc:5000"
globalSettings__baseServiceUri__internalVault: "http://bitwarden-web-svc:5000"
globalSettings__baseServiceUri__internalSso: "http://bitwarden-sso-svc:5000"
globalSettings__baseServiceUri__internalScim: "http://bitwarden-self-host-scim:5000"
kind: ConfigMap
metadata:
name: global.env
namespace: bitwarden
@@ -0,0 +1,28 @@
apiVersion: v1
data:
ACCEPT_EULA: "Y"
adminSettings__admins: pierre@geeraert.eu
globalSettings__baseServiceUri__vault: http://bitwarden.tryton.geeraert.eu
globalSettings__disableUserRegistration: "false"
globalSettings__duo__aKey: p9jCHtnG4NZNZu4SThpVlCuOF1oePGhu53Wa4RJwuyeqRAWQ0aJN7GsKYrGbYIYO
globalSettings__hibpApiKey: REPLACE
globalSettings__identityServer__certificatePassword: test
globalSettings__installation__id: c36aded0-b0f1-4252-920b-ac4c008fc920
globalSettings__installation__key: CtQE5U1tMJE4Dzk7N9DU
globalSettings__internalIdentityKey: I5TMbqmEjhw9uBNmFZ9rU6s1KN5xqAKXh7RSPfgyj2XQ4sjlP22SCupFn4IVhYX7
globalSettings__mail__replyToEmail: no-reply@bitwarden.tryton.geeraert.eu
globalSettings__mail__smtp__host: smtp.gmail.com
globalSettings__mail__smtp__password: vmxkiidikqwirpuh
globalSettings__mail__smtp__port: "587"
globalSettings__mail__smtp__ssl: "false"
globalSettings__mail__smtp__username: p3jh6qa2@gmail.com
globalSettings__oidcIdentityClientKey: w47pWOkPa6mrTkiPuKizitsiRTR6NH8ufI01u77zbZt3LUcKWJ4wchMn6ouiwN7V
globalSettings__sqlServer__connectionString: Data Source=tcp:bitwarden-mssql-svc,1433;Initial
Catalog=bitwarden_vault;Persist Security Info=False;User ID=sa;Password=ChQKWDIW73eSHzX1UyvGDAv4pFw6DVKM;MultipleActiveResultSets=False;Connect
Timeout=30;Encrypt=True;TrustServerCertificate=True
globalSettings__yubico__clientId: REPLACE
globalSettings__yubico__key: REPLACE
kind: ConfigMap
metadata:
name: global.override.env
namespace: bitwarden
@@ -0,0 +1,9 @@
globalSettings__duo__aKey=p9jCHtnG4NZNZu4SThpVlCuOF1oePGhu53Wa4RJwuyeqRAWQ0aJN7GsKYrGbYIYO
globalSettings__hibpApiKey=REPLACE
globalSettings__identityServer__certificatePassword=test
globalSettings__installation__key=CtQE5U1tMJE4Dzk7N9DU
globalSettings__internalIdentityKey=I5TMbqmEjhw9uBNmFZ9rU6s1KN5xqAKXh7RSPfgyj2XQ4sjlP22SCupFn4IVhYX7
globalSettings__mail__smtp__password=vmxkiidikqwirpuh
globalSettings__oidcIdentityClientKey=w47pWOkPa6mrTkiPuKizitsiRTR6NH8ufI01u77zbZt3LUcKWJ4wchMn6ouiwN7V
globalSettings__sqlServer__connectionString=Data Source=tcp:bitwarden-mssql-svc,1433;Initial Catalog=bitwarden_vault;Persist Security Info=False;User ID=sa;Password=ChQKWDIW73eSHzX1UyvGDAv4pFw6DVKM;MultipleActiveResultSets=False;Connect Timeout=30;Encrypt=True;TrustServerCertificate=True
globalSettings__yubico__key=REPLACE
@@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
labels:
deployment_method: manually
name: identity
namespace: bitwarden
spec:
ports:
- name: 5000bitwarden-i
port: 5000
protocol: TCP
targetPort: 5000
selector:
app: bitwarden-identity
type: ClusterIP
@@ -0,0 +1,9 @@
apiVersion: v1
data:
ACCEPT_EULA: "Y"
MSSQL_PID: Express
SA_PASSWORD: SECRET
kind: ConfigMap
metadata:
name: mssql.env
namespace: bitwarden
@@ -0,0 +1,7 @@
apiVersion: v1
data:
SA_PASSWORD: ChQKWDIW73eSHzX1UyvGDAv4pFw6DVKM
kind: ConfigMap
metadata:
name: mssql.override.env
namespace: bitwarden
@@ -0,0 +1 @@
SA_PASSWORD=ChQKWDIW73eSHzX1UyvGDAv4pFw6DVKM
@@ -0,0 +1,8 @@
apiVersion: v1
data:
LOCAL_GID: "1001"
LOCAL_UID: "1001"
kind: ConfigMap
metadata:
name: uid.env
namespace: bitwarden
@@ -0,0 +1,10 @@
apiVersion: v1
data:
DB_DATABASE_NAME: ZGphbmdv
DB_HOST: ZGphbmdvLWRiLXN2Yw==
DB_PASSWORD: U3VmZnJhZ2UtTW9uZXliYWdzLUlsbHVzaW9uNw==
DB_USERNAME: ZGphbmdvX3VzZXJuYW1l
kind: Secret
metadata:
name: django-db-credentials
namespace: django
@@ -0,0 +1,17 @@
---
apiVersion: v1
kind: Service
metadata:
name: django-db-nodeport
namespace: django
spec:
ports:
- name: http
nodePort: 32345
port: 5432
protocol: TCP
targetPort: 5432
selector:
app: django-db
type: NodePort
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
kubectl exec -it -n reverse-proxy deploy/reverse-proxy -c reverse-proxy -- nginx -s reload
@@ -0,0 +1,23 @@
apiVersion: v1
data:
nginx-http-auth.local: |
## Version 2022/08/06
# Fail2Ban jail configuration for nginx-http-auth
# To use more aggressive http-auth modes set filter parameter "mode" in jail.local:
# normal (default), aggressive (combines all), auth or fallback
# See "tests/files/logs/nginx-http-auth" or "filter.d/nginx-http-auth.conf" for usage example and details.
[nginx-http-auth]
enabled = false
port = http,https
filter = nginx-unauthorized
action = nginx-block-map
logpath = /var/log/nginx/backend_debug.log
maxretry = 5
kind: ConfigMap
metadata:
creationTimestamp: null
name: fail2ban-nginx-http-auth-jail
namespace: fail2ban
@@ -0,0 +1,30 @@
apiVersion: v1
data:
nginx-unauthorized.local: |
## Version 2022/08/06
# Fail2Ban filter configuration for nginx unauthorized
[INCLUDES]
before = common.conf
[Definition]
#original
#failregex = ^<HOST>.*"(GET|POST|HEAD).*" (401) .*$
#try this one
failregex = ^<HOST> - .* "(?:GET|POST|HEAD) [^"]+" 401
^<HOST> - .* upstream_status=401
#for servarr
^<HOST> -.*"GET /login\?returnUrl=/&loginFailed=true HTTP/.*" 200
^<HOST> -.*"POST /login\?returnUrl=/&loginFailed=true HTTP/.*" 200
#for bitwarden
^<HOST> -.*"POST /identity/accounts/prelogin *HTTP/.*" 200
#actionban = touch /tmp/<name>.ban
#actionunban = touch /tmp/<name>.unban
kind: ConfigMap
metadata:
creationTimestamp: null
name: fail2ban-nginx-unauthorized-filter
namespace: fail2ban
@@ -0,0 +1,19 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: role:service-acc
namespace: reverse-proxy
rules:
- apiGroups: [""]
resources:
- pods
- pods/exec
verbs:
- create
- list
- apiGroups: ["apps"]
resources:
- deployments
verbs:
- get
@@ -0,0 +1,15 @@
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: rolebinding:service-acc
namespace: reverse-proxy
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: role:service-acc
subjects:
- kind: ServiceAccount
name: kubectl-service-account
namespace: fail2ban
@@ -0,0 +1,6 @@
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: kubectl-service-account
namespace: fail2ban
@@ -0,0 +1,58 @@
apiVersion: v1
data:
nginx-block-map.local: "## Version 2022/08/06\n# Fail2Ban configuration file for
black-listing via nginx\n#\n# Author: Serg G. Brester (aka sebres)\n#\n# To use
'nginx-block-map' action you should define some special blocks in your nginx configuration,\n#
and use it hereafter in your locations (to notify fail2ban by failure, resp. nginx
by ban).\n#\n# Example (argument \"token_id\" resp. cookie \"session_id\" used
here as unique identifier for user):\n#\n# http {\n# ...\n# # maps to
check user is blacklisted (banned in f2b):\n# #map $arg_token_id $blck_lst_tok
{ include blacklisted-tokens.map; }\n# map $cookie_session_id $blck_lst_ses
{ include blacklisted-sessions.map; }\n# ...\n# # special log-format to
notify fail2ban about failures:\n# log_format f2b_session_errors '$msec failure
\"$cookie_session_id\" - $remote_addr - $remote_user '\n# ;# '\"$request\"
$status $bytes_sent '\n# # '\"$http_referer\" \"$http_user_agent\"';\n#\n#
\ # location checking blacklisted values:\n# location ... {\n# #
check banned sessionid:\n# if ($blck_lst_ses != \"\") {\n# try_files
\"\" @f2b-banned;\n# }\n# ...\n# # notify fail2ban about a failure
inside nginx:\n# error_page 401 = @notify-f2b;\n# ...\n# }\n#
\ ...\n# # location for return with \"403 Forbidden\" if banned:\n# location
@f2b-banned {\n# default_type text/html;\n# return 403 \"<br/><center>\n#
\ <b style=\\\"color:red; font-size:18pt; border:2pt solid black; padding:5pt;\\\">\n#
\ You are banned!</b></center>\";\n# }\n# ...\n# # location
to notify fail2ban about a failure inside nginx:\n# location @notify-f2b {\n#
\ access_log /var/log/nginx/f2b-auth-errors.log f2b_session_errors;\n# }\n#
\ }\n# ...\n#\n# Note that quote-character (and possibly other special characters)
are not allowed currently as session-id.\n# Thus please add any session-id validation
rule in your locations (or in the corresponding backend-service), \n# like in
example below:\n#\n# location ... {\n# if ($cookie_session_id !~ \"^[\\w\\-]+$\")
{\n# return 403 \"Wrong session-id\"\n# }\n# ...\n# }\n#\n# The
parameters for jail corresponding log-format (f2b_session_errors):\n#\n# [nginx-blck-lst]\n#
\ filter =\n# datepattern = ^Epoch\n# failregex = ^ failure \"<F-ID>[^\"]+</F-ID>\"
- <ADDR>\n# usedns = no\n#\n# The same log-file can be used for IP-related jail
(additionally to session-related, to ban very bad IPs):\n#\n# [nginx-blck-ip]\n#
\ maxretry = 100\n# filter =\n# datepattern = ^Epoch\n# failregex = ^ failure
\"[^\"]+\" - <ADDR>\n# usedns = no\n#\n\n[Definition]\n\n# path to configuration
of nginx (used to target nginx-instance in multi-instance system,\n# and as path
for the blacklisted map):\n#srv_cfg_path = /etc/nginx/\n\nsrv_cfg_path = /blacklisted.d/\n\n#
cmd-line arguments to supply to test/reload nginx:\n#srv_cmd = nginx -c %(srv_cfg_path)s/nginx.conf\nsrv_cmd
= nginx\n\n# pid file (used to check nginx is running):\nsrv_pid = /run/nginx.pid\n\n#
command used to check whether nginx is running and configuration is valid:\nsrv_is_running
= [ -f \"%(srv_pid)s\" ]\nsrv_check_cmd = %(srv_is_running)s && %(srv_cmd)s -qt\n\n#
first test nginx is running and configuration is correct, hereafter send reload
signal:\n#blck_lst_reload = %(srv_check_cmd)s; if [ $? -eq 0 ]; then\n# %(srv_cmd)s
-s reload; if [ $? -ne 0 ]; then echo 'reload failed.'; fi;\n# fi;\n\nrestart_file
= /restart-signal/restart.txt\n\nblck_lst_reload = touch %(restart_file)s;sleep
20; rm %(restart_file)s;\n\n# map-file for nginx, can be redefined using `action
= nginx-block-map[blck_lst_file=\"/path/file.map\"]`:\nblck_lst_file = %(srv_cfg_path)s/blacklisted-sessions.conf\n\n#
Action definition:\n\nactionstart_on_demand = false\nactionstart = touch '%(blck_lst_file)s'\n\nactionflush
= truncate -s 0 '%(blck_lst_file)s'; %(blck_lst_reload)s\n\nactionstop = %(actionflush)s\n\nactioncheck
= \n\n_echo_blck_row = printf '\\%%s 1;\\n' \"<fid>\"\n\nactionban = echo <ip>
| awk -F. '{print \"deny \"$1\".\"$2\".\"$3\".\"$4\";\"}' >> '%(blck_lst_file)s';
%(blck_lst_reload)s\n\nactionunban = id=$(%(_echo_blck_row)s | sed -e 's/[]\\/$*.^|[]/\\\\&/g');
sed -i \"/^$id$/d\" %(blck_lst_file)s; %(blck_lst_reload)s\n"
kind: ConfigMap
metadata:
creationTimestamp: null
name: nginx-block-map-action
namespace: fail2ban
@@ -0,0 +1,124 @@
## Version 2022/08/06
# Fail2Ban configuration file for black-listing via nginx
#
# Author: Serg G. Brester (aka sebres)
#
# To use 'nginx-block-map' action you should define some special blocks in your nginx configuration,
# and use it hereafter in your locations (to notify fail2ban by failure, resp. nginx by ban).
#
# Example (argument "token_id" resp. cookie "session_id" used here as unique identifier for user):
#
# http {
# ...
# # maps to check user is blacklisted (banned in f2b):
# #map $arg_token_id $blck_lst_tok { include blacklisted-tokens.map; }
# map $cookie_session_id $blck_lst_ses { include blacklisted-sessions.map; }
# ...
# # special log-format to notify fail2ban about failures:
# log_format f2b_session_errors '$msec failure "$cookie_session_id" - $remote_addr - $remote_user '
# ;# '"$request" $status $bytes_sent '
# # '"$http_referer" "$http_user_agent"';
#
# # location checking blacklisted values:
# location ... {
# # check banned sessionid:
# if ($blck_lst_ses != "") {
# try_files "" @f2b-banned;
# }
# ...
# # notify fail2ban about a failure inside nginx:
# error_page 401 = @notify-f2b;
# ...
# }
# ...
# # location for return with "403 Forbidden" if banned:
# location @f2b-banned {
# default_type text/html;
# return 403 "<br/><center>
# <b style=\"color:red; font-size:18pt; border:2pt solid black; padding:5pt;\">
# You are banned!</b></center>";
# }
# ...
# # location to notify fail2ban about a failure inside nginx:
# location @notify-f2b {
# access_log /var/log/nginx/f2b-auth-errors.log f2b_session_errors;
# }
# }
# ...
#
# Note that quote-character (and possibly other special characters) are not allowed currently as session-id.
# Thus please add any session-id validation rule in your locations (or in the corresponding backend-service),
# like in example below:
#
# location ... {
# if ($cookie_session_id !~ "^[\w\-]+$") {
# return 403 "Wrong session-id"
# }
# ...
# }
#
# The parameters for jail corresponding log-format (f2b_session_errors):
#
# [nginx-blck-lst]
# filter =
# datepattern = ^Epoch
# failregex = ^ failure "<F-ID>[^"]+</F-ID>" - <ADDR>
# usedns = no
#
# The same log-file can be used for IP-related jail (additionally to session-related, to ban very bad IPs):
#
# [nginx-blck-ip]
# maxretry = 100
# filter =
# datepattern = ^Epoch
# failregex = ^ failure "[^"]+" - <ADDR>
# usedns = no
#
[Definition]
# path to configuration of nginx (used to target nginx-instance in multi-instance system,
# and as path for the blacklisted map):
#srv_cfg_path = /etc/nginx/
srv_cfg_path = /blacklisted.d/
# cmd-line arguments to supply to test/reload nginx:
#srv_cmd = nginx -c %(srv_cfg_path)s/nginx.conf
srv_cmd = nginx
# pid file (used to check nginx is running):
srv_pid = /run/nginx.pid
# command used to check whether nginx is running and configuration is valid:
srv_is_running = [ -f "%(srv_pid)s" ]
srv_check_cmd = %(srv_is_running)s && %(srv_cmd)s -qt
# first test nginx is running and configuration is correct, hereafter send reload signal:
#blck_lst_reload = %(srv_check_cmd)s; if [ $? -eq 0 ]; then
# %(srv_cmd)s -s reload; if [ $? -ne 0 ]; then echo 'reload failed.'; fi;
# fi;
restart_file = /restart-signal/restart.txt
blck_lst_reload = kubectl exec -it -n reverse-proxy deploy/reverse-proxy -c reverse-proxy -- nginx -s reload
# map-file for nginx, can be redefined using `action = nginx-block-map[blck_lst_file="/path/file.map"]`:
blck_lst_file = %(srv_cfg_path)s/blacklisted-sessions.conf
# Action definition:
actionstart_on_demand = false
actionstart = touch '%(blck_lst_file)s'
actionflush = truncate -s 0 '%(blck_lst_file)s'; %(blck_lst_reload)s
actionstop = %(actionflush)s
actioncheck =
_echo_blck_row = printf '\%%s 1;\n' "<fid>"
actionban = kubectl exec -it -n reverse-proxy deploy/reverse-proxy -c reverse-proxy -- sh -c "echo 'deny <ip>;' > /etc/nginx/blacklisted.d/blacklisted-sessions.conf"; %(blck_lst_reload)s
actionunban = id=$(%(_echo_blck_row)s | sed -e 's/[]\/$*.^|[]/\\&/g'); sed -i "/^$id$/d" %(blck_lst_file)s; %(blck_lst_reload)s
@@ -0,0 +1,12 @@
apiVersion: v1
data:
VPN_DNS_IP: MTAuMi4wLjE=
VPN_ENDPOINT_IP: ODkuMTA1LjIxNC4xOTY=
VPN_ENDPOINT_PORT: NTE4MjA=
WIREGUARD_PRIVATE_KEY: Q0h3OHNkVUliaVRPbTgxTzZGOWRyMm9Nc2k1ZFl4SnZValo1Z2Jwd3UzWT0=
WIREGUARD_PUBLIC_KEY: WG4yQkwrdmhJZ2dsMnVKZ29HY2NqMG4wQ3Z3N09hZU5LMXdPZk91dElTUT0=
kind: Secret
metadata:
creationTimestamp: null
name: gluetun-secret-nl-free-280
namespace: gluetun
@@ -0,0 +1,10 @@
apiVersion: v1
data:
DB_DATABASE_NAME: aW1taWNo
DB_HOST: aW1taWNoLWRiLXN2Yw==
DB_PASSWORD: U3Bvb24tQm9yb3VnaC1CYXNpczg=
DB_USERNAME: aW1taWNo
kind: Secret
metadata:
name: immich-db-credentials
namespace: immich
@@ -5,9 +5,9 @@ data:
POSTGRES_PASSWORD: cGFwZXJsZXNz POSTGRES_PASSWORD: cGFwZXJsZXNz
PAPERLESS_ADMIN_USER: YWRtaW4= PAPERLESS_ADMIN_USER: YWRtaW4=
PAPERLESS_ADMIN_PASSWORD: YWRtaW4= PAPERLESS_ADMIN_PASSWORD: YWRtaW4=
POSTGRES_HOST: cGFwZXItZGItc3Zj POSTGRES_HOST: cGFwZXJsZXNzLWRiLXN2Yw==
kind: Secret kind: Secret
metadata: metadata:
name: paperless-credentials name: paperless-credentials
namespace: paper namespace: paperless
type: Opaque type: Opaque
@@ -0,0 +1,5 @@
[IMAP-1993]
documentation = *** note: this server will work for both Office 365 and personal Outlook/Hotmail accounts ***
server_address = outlook.office365.com
server_port = 993
local_address = 127.0.0.1
@@ -0,0 +1,13 @@
apiVersion: v1
data:
emailproxy.config: |
[IMAP-1993]
documentation = *** note: this server will work for both Office 365 and personal Outlook/Hotmail accounts ***
server_address = outlook.office365.com
server_port = 993
local_address = 127.0.0.1
kind: ConfigMap
metadata:
creationTimestamp: null
name: emailproxyconfig
namespace: paperless
@@ -0,0 +1,45 @@
apiVersion: batch/v1
kind: CronJob
metadata:
name: paperless-calendar-backup
namespace: paperless
spec:
schedule: "0 0 * * *"
jobTemplate:
spec:
backoffLimit: 4
ttlSecondsAfterFinished: 100
template:
spec:
containers:
- name: paperless-database-backup
image: alpine/psql
envFrom:
- secretRef:
name: paperless-db-terraform
optional: false
command: ["/bin/sh","-c"]
args: ["pg_dump |gzip -9 > /backup/$(DB_DATABASE_NAME)-DB-$(date +%Y%m%d).sql.gz "]
volumeMounts:
- name: backup
mountPath: /backup
volumes:
- name: backup
persistentVolumeClaim:
claimName: paperless-database-backup
restartPolicy: Never
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: paperless-database-backup
namespace: paperless
annotations:
fileType: Backup
spec:
storageClassName: nfs-storage-fastaccess
accessModes:
- ReadWriteMany
resources:
requests:
storage: 2Gi
@@ -6,6 +6,5 @@ data:
DB_USER: cHJvd2xhcnJfdXNlcm5hbWU= DB_USER: cHJvd2xhcnJfdXNlcm5hbWU=
kind: Secret kind: Secret
metadata: metadata:
creationTimestamp: null
name: prowlarr-credentials name: prowlarr-credentials
namespace: bookstack namespace: bookstack
@@ -6,6 +6,5 @@ data:
DB_USER: c2VydmFycl91c2VybmFtZQ== DB_USER: c2VydmFycl91c2VybmFtZQ==
kind: Secret kind: Secret
metadata: metadata:
creationTimestamp: null
name: servarr-db-credentials name: servarr-db-credentials
namespace: servarr namespace: servarr
+6 -4
View File
@@ -35,8 +35,8 @@ PROXY_HTTP="http://gluetun-svc.gluetun.svc:8888"
#BASE_URL="https://www.pornpics.com/pornstars/eiby-shine/" #BASE_URL="https://www.pornpics.com/pornstars/eiby-shine/"
#pornstars="eiby-shine" #pornstars="eiby-shine"
BASE_URL="https://www.pornpics.com/?q=shy+imp" #BASE_URL="https://www.pornpics.com/pornstars/chloe-camilla/"
pornstars="shy-imp" #pornstars="chloe-camilla"
#BASE_URL="https://www.pornpics.com/pornstars/becky-summer" #BASE_URL="https://www.pornpics.com/pornstars/becky-summer"
#pornstars="becky-summer" #pornstars="becky-summer"
@@ -44,6 +44,9 @@ pornstars="shy-imp"
#clear files beforehand #clear files beforehand
echo "Pornstar: "$pornstars
echo "URL: "$BASE_URL
mkdir -p $DESTINATION_FOLDER/$pornstars mkdir -p $DESTINATION_FOLDER/$pornstars
@@ -63,7 +66,7 @@ echo "" > $DESTINATION_FOLDER/$pornstars-image_to_download.txt
for f in $(cat $DESTINATION_FOLDER/$pornstars-urls_of_galleries.txt ); do for f in $(cat $DESTINATION_FOLDER/$pornstars-urls_of_galleries.txt ); do
$curl_command $f | grep -Eo "(http|https)://[a-zA-Z0-9./?=_%:-]*" | grep "https://cdni.pornpics.com/1280" >> $DESTINATION_FOLDER/$pornstars-image_to_download.txt $curl_command $f | grep -Eo "(http|https)://[a-zA-Z0-9./?=_%:-]*" | grep "https://cdni.pornpics.com/" >> $DESTINATION_FOLDER/$pornstars-image_to_download.txt
echo $f echo $f
done done
@@ -73,4 +76,3 @@ for g in $(cat $DESTINATION_FOLDER/$pornstars-image_to_download.txt ); do
# wget -e use_proxy=yes -e http_proxy=$PROXY_HTTP $g -P $DESTINATION_FOLDER/$pornstars # wget -e use_proxy=yes -e http_proxy=$PROXY_HTTP $g -P $DESTINATION_FOLDER/$pornstars
echo $g echo $g
done done
exit 0
@@ -0,0 +1,85 @@
#!/bin/bash
#install required packages
apk add curl wget
#named argument generation
skip_searching_gallery="${skip_searching_gallery:-false}"
while [ $# -gt 0 ]; do
if [[ $1 == "--"* ]]; then
v="${1/--/}"
declare "$v"="$2"
shift
fi
shift
done
#check if we will use a HTTP proxy or not
if [[ -z $http_proxy ]]; then
echo "not using proxy"
curl_command="curl"
else
echo "using proxy"
echo $http_proxy
curl_command="curl -x $http_proxy"
fi
#dowload from https://www.pornpics.com/pornstars/eiby-shine/
DESTINATION_FOLDER="/data"
PROXY_HTTP="http://gluetun-svc.gluetun.svc:8888"
#BASE_URL="https://www.pornpics.com/pornstars/eiby-shine/"
#pornstars="eiby-shine"
#BASE_URL="https://www.pornpics.com/?q=shy+imp"
#pornstars="shy-imp"
#BASE_URL="https://www.pornpics.com/pornstars/gloria-sol/"
#pornstars="gloria-sol"
#BASE_URL="https://www.pornpics.com/pornstars/becky-summer"
#pornstars="becky-summer"
#clear files beforehand
echo "Pornstar: "$pornstars
echo "URL: "$BASE_URL
mkdir -p $DESTINATION_FOLDER/$pornstars
if [[ $skip_searching_gallery == true ]]; then
echo "not looping through galleries"
echo "using existing file instead"
#because we need to keep the file $DESTINATION_FOLDER/$pornstars-urls_of_galleries.txt with the existing URL , in this condition,
#no deletion of this file
else
echo "looping through galleries"
#because we will re-generate this file, can be emptied
echo "" > $DESTINATION_FOLDER/$pornstars-urls_of_galleries.txt
$curl_command -s $BASE_URL | grep -Eo "(http|https)://[a-zA-Z0-9./?=_%:-]*" | grep "https://www.pornpics.com/galleries/" |sort -u >> $DESTINATION_FOLDER/$pornstars-urls_of_galleries.txt
fi
echo "" > $DESTINATION_FOLDER/$pornstars-image_to_download.txt
for f in $(cat $DESTINATION_FOLDER/$pornstars-urls_of_galleries.txt ); do
echo "$curl_command $f"
$curl_command "$f"
$curl_command "$f" | grep -Eo "(http|https)://[a-zA-Z0-9./?=_%:-]*" | grep "https://cdni.pornpics.com/1280" >> $DESTINATION_FOLDER/$pornstars-image_to_download.txt
echo $f
done
for g in $(cat $DESTINATION_FOLDER/$pornstars-image_to_download.txt ); do
$curl_command -O --output-dir $DESTINATION_FOLDER/$pornstars "$g"
# wget -e use_proxy=yes -e http_proxy=$PROXY_HTTP $g -P $DESTINATION_FOLDER/$pornstars
echo $g
done
exit 0
@@ -6,25 +6,24 @@ data:
\"$v\"=\"$2\"\n shift\n fi\n shift\ndone\n\n#check if we will use \"$v\"=\"$2\"\n shift\n fi\n shift\ndone\n\n#check if we will use
a HTTP proxy or not\n\nif [[ -z $http_proxy ]]; then\n echo \"not using a HTTP proxy or not\n\nif [[ -z $http_proxy ]]; then\n echo \"not using
proxy\"\n curl_command=\"curl\"\nelse\n echo \"using proxy\"\n curl_command=\"curl proxy\"\n curl_command=\"curl\"\nelse\n echo \"using proxy\"\n curl_command=\"curl
-x $http_proxy\"\n\nfi\n\n\n#dowload from https://www.pornpics.com/pornstars/eiby-shine/\nDESTINATION_FOLDER=\"/data\"\nPROXY_HTTP=\"http://gluetun-svc.gluetun.svc:8888\"\n\n#BASE_URL=\"https://www.pornpics.com/pornstars/eiby-shine/\"\n#pornstars=\"eiby-shine\"\n\nBASE_URL=\"https://www.pornpics.com/?q=shy+imp\"\npornstars=\"shy-imp\"\n\n#BASE_URL=\"https://www.pornpics.com/pornstars/becky-summer\"\n#pornstars=\"becky-summer\"\n\n\n#clear -x $http_proxy\"\n\nfi\n\n\n#dowload from https://www.pornpics.com/pornstars/eiby-shine/\nDESTINATION_FOLDER=\"/data\"\nPROXY_HTTP=\"http://gluetun-svc.gluetun.svc:8888\"\n\n#BASE_URL=\"https://www.pornpics.com/pornstars/eiby-shine/\"\n#pornstars=\"eiby-shine\"\n\n#BASE_URL=\"https://www.pornpics.com/pornstars/chloe-camilla/\"\n#pornstars=\"chloe-camilla\"\n\n#BASE_URL=\"https://www.pornpics.com/pornstars/becky-summer\"\n#pornstars=\"becky-summer\"\n\n\n#clear
files beforehand\n\n\nmkdir -p $DESTINATION_FOLDER/$pornstars\n\nif [[ $skip_searching_gallery files beforehand\n\necho \"Pornstar: \"$pornstars\necho \"URL: \"$BASE_URL\n\n\nmkdir
== true ]]; then\n echo \"not looping through galleries\"\n\t\techo \"using -p $DESTINATION_FOLDER/$pornstars\n\nif [[ $skip_searching_gallery == true ]];
existing file instead\"\n\t\t#because we need to keep the file $DESTINATION_FOLDER/$pornstars-urls_of_galleries.txt then\n echo \"not looping through galleries\"\n\t\techo \"using existing
with the existing URL , in this condition, \n\t\t#no deletion of this file\necho file instead\"\n\t\t#because we need to keep the file $DESTINATION_FOLDER/$pornstars-urls_of_galleries.txt
\"https://www.pornpics.com/galleries/onlyfans-shy-imp-starring-shy-imp-naked-porn-pics-90263490/\nhttps://www.pornpics.com/galleries/onlyfans-shy-imp-featuring-shy-imp-xxx-porn-pics-15741579/\nhttps://www.pornpics.com/galleries/onlyfans-shy-imp-starring-shy-imp-naked-photos-68925414/\nhttps://www.pornpics.com/galleries/onlyfans-shy-imp-shy-imp-20862921/\nhttps://www.pornpics.com/galleries/skinny-girl-with-pink-hair-shy-imp-shows-her-small-tits-during-a-solo-show-50988369/\nhttps://www.pornpics.com/galleries/onlyfans-shy-imp-featuring-shy-imp-hot-gallery-86312934/\" with the existing URL , in this condition, \n\t\t#no deletion of this file\nelse\n
>> $DESTINATION_FOLDER/$pornstars-urls_of_galleries.txt\n\nelse\n echo \ echo \"looping through galleries\"\n\t\t#because we will re-generate this
\"looping through galleries\"\n\t\t#because we will re-generate this file, can file, can be emptied\n\t\techo \"\" > $DESTINATION_FOLDER/$pornstars-urls_of_galleries.txt\n
be emptied\n\t\techo \"\" > $DESTINATION_FOLDER/$pornstars-urls_of_galleries.txt\n
\ $curl_command -s $BASE_URL | grep -Eo \"(http|https)://[a-zA-Z0-9./?=_%:-]*\" \ $curl_command -s $BASE_URL | grep -Eo \"(http|https)://[a-zA-Z0-9./?=_%:-]*\"
| grep \"https://www.pornpics.com/galleries/\" |sort -u >> $DESTINATION_FOLDER/$pornstars-urls_of_galleries.txt\nfi\n\necho | grep \"https://www.pornpics.com/galleries/\" |sort -u >> $DESTINATION_FOLDER/$pornstars-urls_of_galleries.txt\nfi\n\necho
\"\" > $DESTINATION_FOLDER/$pornstars-image_to_download.txt\n\n\nfor f in $(cat \"\" > $DESTINATION_FOLDER/$pornstars-image_to_download.txt\n\n\nfor f in $(cat
$DESTINATION_FOLDER/$pornstars-urls_of_galleries.txt ); do\n\t$curl_command $f $DESTINATION_FOLDER/$pornstars-urls_of_galleries.txt ); do\n\t$curl_command $f
| grep -Eo \"(http|https)://[a-zA-Z0-9./?=_%:-]*\" | grep \"https://cdni.pornpics.com/1280\" | grep -Eo \"(http|https)://[a-zA-Z0-9./?=_%:-]*\" | grep \"https://cdni.pornpics.com/\"
>> $DESTINATION_FOLDER/$pornstars-image_to_download.txt\n\techo $f\ndone\n\n\nfor >> $DESTINATION_FOLDER/$pornstars-image_to_download.txt\n\techo $f\ndone\n\n\nfor
g in $(cat $DESTINATION_FOLDER/$pornstars-image_to_download.txt ); do \n\t$curl_command g in $(cat $DESTINATION_FOLDER/$pornstars-image_to_download.txt ); do \n\t$curl_command
-O --output-dir $DESTINATION_FOLDER/$pornstars $g\n# wget -e use_proxy=yes -O --output-dir $DESTINATION_FOLDER/$pornstars $g\n# wget -e use_proxy=yes
-e http_proxy=$PROXY_HTTP $g -P $DESTINATION_FOLDER/$pornstars\n echo $g -e http_proxy=$PROXY_HTTP $g -P $DESTINATION_FOLDER/$pornstars\n echo $g
\ndone\nexit 0\n" \ndone\n"
kind: ConfigMap kind: ConfigMap
metadata: metadata:
creationTimestamp: null creationTimestamp: null
@@ -17,13 +17,17 @@ spec:
mountPropagation: None mountPropagation: None
name: data-pvc name: data-pvc
command: command:
# - /bin/bash
# - -c
# - sleep 3600
- bash - bash
- -c
- sleep 3600
# - bash
- /config/download.sh - /config/download.sh
- --http_proxy - --http_proxy
- "http://gluetun-svc.gluetun.svc:8888" - "http://gluetun-svc.gluetun.svc:8888"
- --BASE_URL
- "https://www.pornpics.com/?q=bretona"
- --pornstars
- "bretona"
restartPolicy: Never restartPolicy: Never
volumes: volumes:
- configMap: - configMap:
+15
View File
@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: tdarr-svc-ext
namespace: servarr
spec:
ports:
- name: tdarr
nodePort: 30266
port: 8266
protocol: TCP
targetPort: 8266
selector:
app: tdarr
type: NodePort
@@ -6,6 +6,5 @@ data:
DB_USER: d2lraWpzX3VzZXJuYW1l DB_USER: d2lraWpzX3VzZXJuYW1l
kind: Secret kind: Secret
metadata: metadata:
creationTimestamp: null
name: wikijs-db-credentials name: wikijs-db-credentials
namespace: wikijs namespace: wikijs
+1
View File
@@ -0,0 +1 @@
terraform 1.16.5
+171
View File
@@ -0,0 +1,171 @@
resource "kubernetes_deployment_v1" "database-automatic" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true && !(try(value.database.shunt, false)) }
metadata {
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
name = "${coalesce(each.value.name, each.key)}-db"
labels = {
app = each.key
deployment_method = "Terraform"
database = "true"
}
}
spec {
replicas = each.value.replicas
selector {
match_labels = {
app = "${each.key}-db"
}
}
template {
metadata {
labels = {
app = "${each.key}-db"
deployment_method = "Terraform"
database = "true"
}
}
spec {
container {
image = try(each.value.database.image, "docker.io/library/postgres:latest")
name = "${coalesce(each.value.name, each.key)}-db"
port {
container_port = 5432
name = "database-port"
}
volume_mount {
mount_path = try(each.value.database.mountPath, "/var/lib/postgresql/")
name = "${each.key}-db-volume"
}
dynamic "volume_mount" {
for_each = try(each.value.database.engine == "sqlserver", false) && !(try(each.value.database.shunt, false)) ? [1] : []
content {
mount_path = "/backup"
name = "${each.key}-db-backup"
}
}
command = try([each.value.database.command], [])
args = each.value.database_args != null ? each.value.database_args : []
dynamic "env_from" {
for_each = each.value.database != null && each.value.enabled == true && !(try(each.value.database.shunt, false)) ? ["${each.key}-db-terraform"] : []
content {
dynamic "secret_ref" {
for_each = [1]
content {
name = env_from.value
}
}
}
}
dynamic "env" {
for_each = each.value.environment != null ? each.value.environment : {}
content {
name = env.key
value = env.value.value != null ? env.value.value : null
dynamic "value_from" {
for_each = env.value.value_from != null ? env.value.value_from : {}
content {
dynamic "secret_key_ref" {
for_each = [1]
content {
name = env.value.value_from.secret_key_ref.name
key = env.value.value_from.secret_key_ref.key
}
}
}
}
}
}
}
volume {
name = "${each.key}-db-volume"
host_path {
path = try(each.value.database.host_path, join("/", [var.storage_path.main_storage, coalesce(each.value.namespace, each.value.connected_namespace, each.key), join("-", [each.key, "db"])]))
}
}
dynamic "volume" {
for_each = try(each.value.database.engine == "sqlserver", false) && !(try(each.value.database.shunt, false)) ? [1] : []
content {
name = "${each.key}-db-backup"
host_path {
path = join("/", [var.storage_path.fast_access, "Backup", coalesce(each.value.namespace, each.value.connected_namespace, each.key), "${each.key}-db-backup"])
}
}
}
}
}
}
}
resource "kubernetes_cron_job_v1" "database-backup" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true }
metadata {
name = "${coalesce(each.value.namespace, each.key)}-db-backup"
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
labels = {
app = each.key
deployment_method = "Terraform"
database = "true"
}
}
spec {
failed_jobs_history_limit = 5
schedule = "1 0 * * *"
timezone = "Etc/UTC"
successful_jobs_history_limit = 5
job_template {
metadata {}
spec {
backoff_limit = 4
ttl_seconds_after_finished = 100
template {
metadata {}
spec {
container {
name = "${coalesce(each.value.namespace, each.key)}-db-backup"
image = try(var.database_backup_info[each.value.database.engine].image, var.database_backup_info.postgres.image)
command = ["/bin/sh", "-c"]
args = [try(var.database_backup_info[each.value.database.engine].command, var.database_backup_info.postgres.command)]
env_from {
secret_ref {
name = "${each.key}-db-terraform"
}
}
volume_mount {
mount_path = "/backup"
name = "${each.key}-db-backup"
}
}
volume {
name = "${each.key}-db-backup"
persistent_volume_claim {
claim_name = "${each.key}-db-backup"
}
}
}
}
}
}
}
}
+242
View File
@@ -0,0 +1,242 @@
module "ingress" {
source = "../modules/ingress"
kubernetes_input = var.kubernetes
}
module "services" {
source = "../modules/services"
kubernetes_input = var.kubernetes
}
resource "kubernetes_deployment_v1" "automatic" {
for_each = { for key, value in var.kubernetes : key => value if value.enabled == true }
metadata {
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
name = coalesce(each.value.name, each.key)
labels = {
app = each.key
deployment_method = "Terraform"
}
}
spec {
replicas = each.value.replicas
selector {
match_labels = {
app = each.key
}
}
template {
metadata {
labels = {
app = each.key
deployment_method = "Terraform"
}
}
spec {
container {
image = each.value.image
name = coalesce(each.value.name, each.key)
dynamic "port" {
for_each = each.value.service_port != null ? each.value.service_port : []
content {
container_port = port.value
# name = "${each.key}-${port.value}"
name = replace("${port.value}${each.key}", "/(.{0,15})(.*)/", "$1")
}
}
dynamic "volume_mount" {
for_each = each.value.pvc != null ? each.value.pvc : {}
content {
mount_path = volume_mount.value.mount_path
name = "${volume_mount.key}-volume"
sub_path = volume_mount.value.sub_path != null ? volume_mount.value.sub_path : ""
}
}
dynamic "volume_mount" {
for_each = try(each.value.database.engine == "sqlserver", false) && try(each.value.database.shunt, false) ? [1] : []
content {
mount_path = "/backup"
name = "${each.key}-db-backup"
}
}
dynamic "env_from" {
for_each = each.value.secret_ref != null ? each.value.secret_ref : []
content {
dynamic "secret_ref" {
for_each = [1]
content {
name = env_from.value
}
}
}
}
dynamic "env_from" {
for_each = each.value.database != null && each.value.enabled == true && !(try(each.value.database.shunt, false)) ? ["${each.key}-db-terraform"] : []
#for_each = each.value.database != null && each.value.enabled == true ? ["${each.key}-db-terraform"] : []
content {
dynamic "secret_ref" {
for_each = [1]
content {
name = env_from.value
}
}
}
}
dynamic "env_from" {
for_each = each.value.database != null && each.value.enabled == true ? ["${each.key}-db-mapped-terraform"] : []
content {
dynamic "secret_ref" {
for_each = [1]
content {
name = env_from.value
}
}
}
}
dynamic "env_from" {
for_each = each.value.config_map_ref != null ? each.value.config_map_ref : []
content {
dynamic "config_map_ref" {
for_each = [1]
content {
name = env_from.value
}
}
}
}
command = each.value.command != null ? each.value.command : []
dynamic "env" {
for_each = each.value.environment != null ? each.value.environment : {}
content {
name = env.key
value = env.value.value != null ? env.value.value : null
dynamic "value_from" {
for_each = env.value.value_from != null ? env.value.value_from : {}
content {
dynamic "secret_key_ref" {
for_each = [1]
content {
name = env.value.value_from.secret_key_ref.name
key = env.value.value_from.secret_key_ref.key
}
}
}
}
}
}
dynamic "resources" {
for_each = each.value.requirements != null ? [1] : []
content {
limits = {
cpu = each.value.requirements.limits-cpu
memory = each.value.requirements.limits-memory
}
requests = {
cpu = each.value.requirements.requests-cpu
memory = each.value.requirements.requests-memory
}
}
}
dynamic "security_context" {
for_each = each.value.security_context == true ? [1] : []
content {
privileged = true
#capabilities = {
# add : ["NET_ADMIN", "NET_RAW"]
#}
}
}
dynamic "liveness_probe" {
for_each = each.value.liveness_tcp_socket != null || each.value.liveness_http_get != null ? [""] : []
content {
dynamic "tcp_socket" {
for_each = each.value.liveness_tcp_socket != null ? [""] : []
content {
port = each.value.liveness_tcp_socket
}
}
dynamic "http_get" {
for_each = each.value.liveness_http_get != null ? [""] : []
content {
port = each.value.liveness_http_get
path = coalesce(each.value.liveness_http_get_path, "/")
}
}
initial_delay_seconds = 3
period_seconds = 3
}
}
}
dynamic "dns_config" {
for_each = each.value.dns_nameservers != null ? [1] : []
content {
nameservers = [each.value.dns_nameservers]
}
}
service_account_name = each.value.service_account_name != null ? each.value.service_account_name : null
dynamic "volume" {
for_each = each.value.pvc != null ? each.value.pvc : {}
content {
name = "${volume.key}-volume"
dynamic "config_map" {
for_each = volume.value.config_map ? [1] : []
content {
name = volume.key
}
}
dynamic "host_path" {
for_each = volume.value.host_path != null || (!(volume.value.config_map) && !(volume.value.secret)) ? [1] : []
content {
path = coalesce(volume.value.host_path, join("/", [var.storage_path.main_storage, coalesce(each.value.namespace, each.value.connected_namespace, each.key), volume.key]))
}
}
dynamic "secret" {
for_each = volume.value.secret ? [1] : []
content {
secret_name = volume.key
}
}
}
}
dynamic "volume" {
for_each = try(each.value.database.engine == "sqlserver", false) && try(each.value.database.shunt, false) ? [1] : []
content {
name = "${each.key}-db-backup"
host_path {
path = join("/", [var.storage_path.fast_access, "Backup", coalesce(each.value.namespace, each.value.connected_namespace, each.key), "${each.key}-db-backup"])
}
}
}
}
}
}
}
+176
View File
@@ -0,0 +1,176 @@
terraform {
required_version = "> 0.8.0"
required_providers {
bitwarden-secrets = {
source = "bitwarden/bitwarden-secrets"
version = "0.5.4-pre"
}
}
}
provider "kubernetes" {
config_path = "~/.kube/config"
}
provider "bitwarden-secrets" {
api_url = "https://bitwarden.tryton.geeraert.eu/api"
identity_url = "https://bitwarden.tryton.geeraert.eu/identity"
access_token = "0.9f4b7c5f-e6e7-4eff-929e-b474016a2b9c.bMRELajGGb7qMuXXvzgCCJdDfxfTCS:mFDT7tHSi43KJSnkwvTSYg=="
organization_id = "a6361589-badd-4bde-9cb4-af8901161c0d"
}
variable "kubernetes" {
type = map(object({
name = optional(string)
docker = optional(bool)
image = string
pvc = optional(map(object({
name = optional(string)
pvc = optional(bool, false)
config_map = optional(bool, false)
secret = optional(bool, false)
host_path = optional(string)
pvc_size = optional(string)
storage_class_name = optional(string, "nfs-storage-intelligent")
annotations_fileType = optional(string)
existing_pvc = optional(bool, false)
mount_path = string
sub_path = optional(string)
})))
environment = optional(map(object({
name = optional(string)
value = optional(string)
value_from = optional(object({
secret_key_ref = object({
name = string
key = optional(string, null)
})
}))
})))
replicas = optional(number, 1)
namespace = optional(string)
connected_namespace = optional(string, "")
command = optional(list(string))
service_port = optional(list(number))
service_type = optional(string, "ClusterIP")
service_name = optional(string)
domain_name = optional(list(string))
legacy_domain = optional(bool, false)
exposed = optional(bool, true)
liveness_tcp_socket = optional(number)
liveness_http_get = optional(string)
liveness_http_get_path = optional(string)
database = optional(map(string))
database_command = optional(list(string))
database_args = optional(list(string))
redis = optional(map(string))
enabled = optional(bool, true)
secret_ref = optional(list(string))
config_map_ref = optional(list(string))
config_map_import = optional(list(string))
secret_import = optional(list(string))
extra_manifest = optional(list(string))
requirements = optional(map(string))
# requirements = optional(map(string), {
# limits-cpu = "800m"
# limits-memory = "500Mi"
# requests-cpu = "200m"
# requests-memory = "200Mi"
# })
dns_nameservers = optional(string)
service_account_name = optional(string)
environment_variables = optional(map(string), { name = "value" })
security_context = optional(bool, false)
import_database_secret = optional(object({
#putting them a non optional as the code doesn't allow optional value
host = string
name = string
password = string
port = string
username = string
}))
}))
}
variable "database_backup_info" {
type = map(object({
image = optional(string)
command = optional(string)
}))
description = "based on DB engine, give the docker image and the command used to backup"
default = {
postgres = {
image = "alpine/psql"
command = "pg_dump |gzip -9 > /backup/$(DB_DATABASE_NAME)-DB-$(date +%Y%m%d).sql.gz"
}
mysql = {
image = "mysql"
command = "mysqldump -h $DB_HOST -u $MYSQL_USER -p$MYSQL_ROOT_PASSWORD $MYSQL_DATABASE |gzip -9 > /backup/$(DB_DATABASE_NAME)-DB-$(date +%Y%m%d).sql.gz"
}
sqlserver = {
image = "mcr.microsoft.com/mssql-tools"
command = "/opt/mssql-tools/bin/sqlcmd -S $DB_HOST -U $DB_USERNAME -P $DB_PASSWORD -Q \"BACKUP DATABASE $DB_DATABASE_NAME TO DISK = '/backup/$DB_DATABASE_NAME-$(date +%Y%m%d).bak' WITH COPY_ONLY, CHECKSUM,FORMAT, MEDIANAME = 'SQLServerBackups',NAME = 'Full Backup of SQLTestDB'\";exit"
}
}
}
variable "storage_path" {
type = map(string)
default = {
main_storage = "/data/kubernetes",
fast_access = "/ssd"
}
}
locals {
env_details = flatten([
for key, value in var.kubernetes : [
for index, env in value.environment_variables : {
index = index
name = env
}] if value.enabled == true && value.environment_variables != null
])
}
resource "kubernetes_namespace_v1" "automatic" {
for_each = { for key, value in var.kubernetes : key => value if value.enabled == true && value.connected_namespace == "" }
metadata {
annotations = {
name = coalesce(each.value.namespace, each.key)
}
labels = {
deployment_method = "Terraform"
}
name = coalesce(each.value.namespace, each.key)
}
}
locals {
kubernetes_manifests = flatten([
for k, obj in var.kubernetes : [
for index, manifest in(obj.extra_manifest != null ? obj.extra_manifest : []) :
{
key = "${k}_${index}"
name = obj.name
manifest = manifest
enabled = obj.enabled
}
if obj.enabled == true
]
])
}
resource "kubernetes_manifest" "manifest" {
for_each = { for item in local.kubernetes_manifests : item.key => item }
manifest = yamldecode(file(each.value.manifest))
provider = kubernetes
}
+123
View File
@@ -0,0 +1,123 @@
resource "kubernetes_deployment_v1" "redis-automatic" {
for_each = { for key, value in var.kubernetes : key => value if value.redis != null && value.enabled == true }
metadata {
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
name = "${coalesce(each.value.name, each.key)}-redis"
labels = {
app = each.key
deployment_method = "Terraform"
redis = "true"
}
}
spec {
replicas = each.value.replicas
selector {
match_labels = {
app = "${each.key}-redis"
}
}
template {
metadata {
labels = {
app = "${each.key}-redis"
deployment_method = "Terraform"
redis = "true"
}
}
spec {
container {
image = try(each.value.redis.image, "docker.io/library/redis:7")
name = "${coalesce(each.value.name, each.key)}-redis"
port {
container_port = 6379
name = "redis-port"
}
volume_mount {
mount_path = "/data"
name = "${each.key}-redis-volume"
}
dynamic "env" {
for_each = each.value.environment != null ? each.value.environment : {}
content {
name = env.key
value = env.value.value != null ? env.value.value : null
dynamic "value_from" {
for_each = env.value.value_from != null ? env.value.value_from : {}
content {
dynamic "secret_key_ref" {
for_each = [1]
content {
name = env.value.value_from.secret_key_ref.name
key = env.value.value_from.secret_key_ref.key
# optional = true
}
}
}
}
}
}
# resources {
# limits = {
# cpu = each.value.requirements.limits-cpu
# memory = each.value.requirements.limits-memory
# }
# requests = {
# cpu = each.value.requirements.requests-cpu
# memory = each.value.requirements.requests-memory
# }
# }
# dynamic "liveness_probe" {
# for_each = each.value.liveness_tcp_socket != null || each.value.liveness_http_get != null ? [""] : []
# content {
# dynamic "tcp_socket" {
# for_each = each.value.liveness_tcp_socket != null ? [""] : []
# content {
# port = each.value.liveness_tcp_socket
# }
# }
# dynamic "http_get" {
# for_each = each.value.liveness_http_get != null ? [""] : []
# content {
# port = each.value.liveness_http_get
# path = coalesce(each.value.liveness_http_get_path, "/")
# }
# }
# initial_delay_seconds = 3
# period_seconds = 3
# }
# }
}
volume {
name = "${each.key}-redis-volume"
host_path {
path = try(each.value.redis.host_path, join("/", [var.storage_path.main_storage, coalesce(each.value.namespace, each.value.connected_namespace, each.key), join("-", [each.key, "redis"])]))
}
}
}
}
}
}
+198
View File
@@ -0,0 +1,198 @@
data "bitwarden-secrets_secret" "configmap_import" {
for_each = {
for pair in flatten([
for k, v in var.kubernetes : [
for id in v.config_map_import : {
map_key = k
secret_id = id
}
] if v.config_map_import != null && v.enabled == true
]) : "${pair.map_key}-${pair.secret_id}" => pair.secret_id
}
id = each.value
}
resource "kubernetes_config_map_v1" "configmap_import" {
for_each = { for key, value in data.bitwarden-secrets_secret.configmap_import : key => value }
metadata {
name = each.value.note
namespace = split("__", each.value.key)[0]
}
data = yamldecode(each.value.value)
}
data "bitwarden-secrets_secret" "secret_import" {
for_each = {
for pair in flatten([
for k, v in var.kubernetes : [
for id in v.secret_import : {
map_key = k
secret_id = id
}
] if v.secret_import != null && v.enabled == true
]) : "${pair.map_key}-${pair.secret_id}" => pair.secret_id
}
id = each.value
}
resource "kubernetes_secret_v1" "secret_import" {
for_each = { for key, value in data.bitwarden-secrets_secret.secret_import : key => value }
metadata {
name = each.value.note
namespace = split("__", each.value.key)[0]
}
data = yamldecode(each.value.value)
}
resource "kubernetes_secret_v1" "automatic-database-secret" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true }
metadata {
name = "${each.key}-db-terraform"
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
}
data = {
DB_DATABASE_NAME = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_name[each.key].value}"
DB_DATABASE = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_name[each.key].value}"
POSTGRES_DB = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_name[each.key].value}"
MYSQL_DATABASE = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_name[each.key].value}"
PGDATABASE = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_name[each.key].value}"
DB_HOST = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_host[each.key].value}"
PGHOST = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_host[each.key].value}"
POSTGRES_HOST = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_host[each.key].value}"
DB_PASSWORD = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_password[each.key].value}"
MYSQL_PASSWORD = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_password[each.key].value}"
MYSQL_ROOT_PASSWORD = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_password[each.key].value}"
POSTGRES_PASSWORD = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_password[each.key].value}"
PGPASSWORD = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_password[each.key].value}"
DB_USERNAME = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_username[each.key].value}"
POSTGRES_USER = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_username[each.key].value}"
MYSQL_USER = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_username[each.key].value}"
PGUSER = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_username[each.key].value}"
DATABASE_URL = "postgresql://${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_username[each.key].value}:${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_password[each.key].value}@${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_host[each.key].value}:${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_port[each.key].value}/${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_name[each.key].value}"
}
}
resource "kubernetes_secret_v1" "automatic-database-mapped-secret" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true }
metadata {
name = "${each.key}-db-mapped-terraform"
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
}
data = {
"${try(each.value.database.map_name, "DB_DATABASE_NAME")}" = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_name[each.key].value}"
"${try(each.value.database.map_host, "DB_DATABASE_NAME")}" = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_host[each.key].value}"
"${try(each.value.database.map_password, "DB_DATABASE_NAME")}" = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_password[each.key].value}"
"${try(each.value.database.map_username, "DB_DATABASE_NAME")}" = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_db_username[each.key].value}"
}
}
resource "bitwarden-secrets_secret" "automatic_bitwarden_secret_db_username" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true }
key = "${each.key}__db__username"
value = try(each.value.database.username, each.key)
project_id = "b5fc4c48-e951-442f-97ca-b3e800c143cd"
lifecycle {
ignore_changes = [
value, key
]
}
}
resource "bitwarden-secrets_secret" "automatic_bitwarden_secret_db_password" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true }
key = "${each.key}__db__password"
project_id = "b5fc4c48-e951-442f-97ca-b3e800c143cd"
length = 32
special = true
min_special = 5
avoid_ambiguous = true
lifecycle {
ignore_changes = [
value, key
]
}
}
resource "bitwarden-secrets_secret" "automatic_bitwarden_secret_db_host" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true }
key = "${each.key}__db__host"
project_id = "b5fc4c48-e951-442f-97ca-b3e800c143cd"
value = try(each.value.database.host, "${each.key}-db-svc.${coalesce(each.value.namespace, each.value.connected_namespace, each.key)}.svc")
lifecycle {
ignore_changes = [
value, key
]
}
}
resource "bitwarden-secrets_secret" "automatic_bitwarden_secret_db_port" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true }
key = "${each.key}__db__port"
project_id = "b5fc4c48-e951-442f-97ca-b3e800c143cd"
value = try(each.value.database.port, 5432)
lifecycle {
ignore_changes = [
value, key
]
}
}
resource "bitwarden-secrets_secret" "automatic_bitwarden_secret_db_name" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true }
key = "${each.key}__db__name"
project_id = "b5fc4c48-e951-442f-97ca-b3e800c143cd"
value = try(each.value.database.name, each.key)
lifecycle {
ignore_changes = [
value, key
]
}
}
# 1. Move the loop logic to a local variable first
locals {
database_secrets_to_import = {
for key, value in var.kubernetes : key => value
if value.database != null && value.enabled == true && can(value.import_database_secret.host)
}
}
# 2. Reference the local map in your import block using each.key and each.value
import {
for_each = local.database_secrets_to_import
to = bitwarden-secrets_secret.automatic_bitwarden_secret_db_host[each.key]
id = each.value.import_database_secret.host
}
import {
for_each = local.database_secrets_to_import
to = bitwarden-secrets_secret.automatic_bitwarden_secret_db_name[each.key]
id = each.value.import_database_secret.name
}
import {
for_each = local.database_secrets_to_import
to = bitwarden-secrets_secret.automatic_bitwarden_secret_db_password[each.key]
id = each.value.import_database_secret.password
}
import {
for_each = local.database_secrets_to_import
to = bitwarden-secrets_secret.automatic_bitwarden_secret_db_port[each.key]
id = each.value.import_database_secret.port
}
import {
for_each = local.database_secrets_to_import
to = bitwarden-secrets_secret.automatic_bitwarden_secret_db_username[each.key]
id = each.value.import_database_secret.username
}
+363
View File
@@ -0,0 +1,363 @@
kubernetes = {
gluetun = {
#enabled = false
dns_nameservers = "1.1.1.1"
replicas = 01
image = "qmcgaw/gluetun:latest"
exposed = false
service_port = [8888]
secret_import = ["5527ba11-07e3-415b-8d1f-b3ee0154eb56", "b0d22160-d81a-4702-a3dd-b40e0168d617", "643dbe99-ace0-4ef5-8a2e-b44f014dccb0"]
security_context = true
environment = {
WIREGUARD_PRIVATE_KEY = {
value_from = {
secret_key_ref = {
name = "gluetun-secret-nl-free-280"
key = "WIREGUARD_PRIVATE_KEY"
}
}
}
HTTPPROXY = {
value = "on"
}
HTTPPROXY_LOG = {
value = "on"
}
HTTPPROXY_LISTENING_ADDRESS = {
value = "0.0.0.0:8888"
}
VPN_SERVICE_PROVIDER = {
value = "protonvpn"
}
VPN_TYPE = {
value = "wireguard"
}
SERVER_COUNTRIES = {
value = "Netherlands"
}
HEALTH_TARGET_ADDRESS = {
value = "0.0.0.0:8888"
}
FREE_ONLY = {
value = "on"
}
FIREWALL_INPUT_PORTS = {
value = "8081,7878,9696,9091,51413,8080,6881,8989,8191,8888,8000"
}
PUBLICIP_API = {
value = "ip2location"
}
}
}
django = {
#enabled = false
namespace = "django"
domain_name = ["django", "admin", "redirect", "streaming", "stash", "simpsons", "kubernetes", "cloudmanager", "podcast"]
image = "gitea.geeraert.eu/pi-ux-ce/django-python:latest"
service_port = [8000]
database = {
image = "docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0"
username = "django_username"
mountPath = "/var/lib/postgresql/data"
}
secret_ref = ["django-bitwarden-credentials"]
secret_import = ["9fc5a725-75f5-4bab-b595-b474017146c3"]
requirements = {
limits-cpu = "800m"
limits-memory = "800Mi"
requests-cpu = "10m"
requests-memory = "300Mi"
}
extra_manifest = ["/opt/kubernetes/Terraform_kube/external_manifests/django/kubeconfig.secret.yaml", "/opt/kubernetes/Terraform_kube/external_manifests/django/django-db.secret.yaml"]
environment = {
ALLOWED_HOSTS = {
value = "django.geeraert.eu,admin.geeraert.eu,redirect.geeraert.eu,streaming.geeraert.eu,stash.geeraert.eu,simpsons.geeraert.eu,kubernetes.geeraert.eu,cloudmanager.geeraert.eu,podcast.geeraert.eu"
}
DEBUG = {
value = "False"
}
ENVIRONMENT = {
value = "PRODUCTION"
}
DB_PASSWORD = {
value_from = {
secret_key_ref = {
name = "django-db-credentials"
key = "DB_PASSWORD"
}
}
}
POSTGRES_DB = {
value_from = {
secret_key_ref = {
name = "django-db-credentials"
key = "DB_DATABASE_NAME"
}
}
}
POSTGRES_USER = {
value_from = {
secret_key_ref = {
name = "django-db-credentials"
key = "DB_USERNAME"
}
}
}
POSTGRES_PASSWORD = {
value_from = {
secret_key_ref = {
name = "django-db-credentials"
key = "DB_PASSWORD"
}
}
}
DB_HOSTNAME = {
value_from = {
secret_key_ref = {
name = "django-db-credentials"
key = "DB_HOST"
}
}
}
}
pvc = {
kubeconfig = {
secret = true
mount_path = "/kubeconfig"
}
stash-django-pvc = {
host_path = "/ssd/stash/data-pvc/"
mount_path = "/stash"
}
}
import_database_secret = {
host = "c73c74e5-b482-4abb-a4b3-b3ed00b0f089"
name = "0a0d6458-86e9-4257-b874-b3ed00b6a11c"
password = "6e947bd5-5646-4838-a93a-b3ed00b0f176"
port = "5e7de818-6131-4372-923c-b3ed00b0efa2"
username = "30ce2424-e67c-42d5-a5ac-b3ed00b0f0fc"
}
}
django-testing = {
#enabled = false
image = "gitea.geeraert.eu/pi-ux-ce/django-testing:latest"
service_port = [8000]
domain_name = ["django-testing", "admin-testing", "redirect-testing", "streaming-testing", "stash-testing", "simpsons-testing", "kubernetes-testing", "cloudmanager-testing", "podcast-testing"]
database = {}
requirements = {
limits-cpu = "800m"
limits-memory = "800Mi"
requests-cpu = "10m"
requests-memory = "300Mi"
}
extra_manifest = ["../external_manifests/django/kubeconfig-testing.secret.yaml"]
secret_ref = ["django-bitwarden-credentials"]
secret_import = ["68dce7aa-8e5f-4483-9083-b474016e34fc"]
environment = {
ALLOWED_HOSTS = {
value = "django-testing.geeraert.eu,admin-testing.geeraert.eu,redirect-testing.geeraert.eu,streaming-testing.geeraert.eu,stash-testing.geeraert.eu,simpsons-testing.geeraert.eu,kubernetes-testing.geeraert.eu,cloudmanager-testing.geeraert.eu,podcast-testing.geeraert.eu"
}
CELERY_BROKER_URL = {
value = "redis://django-testing-redis-svc:6379"
}
DEBUG = {
value = "true"
}
DB_PORT = {
value = 5432
}
CUSTOM_DB_DATABASE = {
value = "cloudmanager" }
}
pvc = {
kubeconfig = {
secret = true
mount_path = "/kubeconfig"
}
}
import_database_secret = {
host = "097f10de-63ee-405c-b46a-b41001781e07"
name = "20530a85-e446-4d79-8985-b41001781e07"
password = "a3385f49-ba92-4478-b6f1-b4e100ff01fb"
port = "e15e00eb-db1e-47ea-ab0e-b41001781e09"
username = "3c67d310-7113-45b7-8f3f-b41001781e08"
}
}
fail2ban = {
enabled = false
#image = "lscr.io/linuxserver/fail2ban:latest"
image = "gitea.tryton.geeraert.eu/pi-ux-ce/fail2ban:latest"
extra_manifest = ["/opt/kubernetes/Terraform_kube/external_manifests/fail2ban/fail2ban.RoleBinding.yaml", "/opt/kubernetes/Terraform_kube/external_manifests/fail2ban/fail2ban.Role.yaml", "/opt/kubernetes/Terraform_kube/external_manifests/fail2ban/fail2ban.ServiceAccount.yaml"]
service_account_name = "kubectl-service-account"
config_map_import = ["9d8ef71a-de74-478b-aa86-b3ee0160dc43", "50814edb-d190-41cb-8950-b3ee01622dcf", "fb11452e-fec1-489f-9144-b3ee0162ccda"]
environment = {
PUID = {
value = "1000"
}
PGID = {
value = "1000"
}
TZ = {
value = "Etc/UTC"
}
VERBOSITY = {
value = "-vv" }
}
security_context = true
pvc = {
fail2ban-config = {
pvc = true
pvc_size = "2Mi"
mount_path = "/config"
name = "fail2ban-config"
}
fail2ban-log = {
pvc = true
pvc_size = "2Mi"
mount_path = "/var/log"
name = "fail2ban-log"
}
nginx-fail2ban-logs = {
host_path = "/data/kubernetes/reverse-proxy/reverse-proxy-log/"
name = "nginx-fail2ban-logs"
pvc_size = "2Mi"
mount_path = "/remotelogs/nginx/"
}
fail2ban-nginx-http-auth-jail = {
config_map = true
name = "fail2ban-nginx-http-auth-jail"
pvc_size = "2Mi"
mount_path = "/config/fail2ban/jail.d/"
}
fail2ban-nginx-unauthorized-filter = {
config_map = true
name = "fail2ban-nginx-unauthorized-filter"
pvc_size = "2Mi"
mount_path = "/config/fail2ban/filter.d/"
}
}
}
netdatat = {
image = "debian"
enabled = false
service_port = [19999]
domain_name = ["netdata"]
command = ["sleep", "3600"]
security_context = true
environment = {
NETDATA_CLAIM_TOKEN = {
value = "wN6wJV1M5jvLbcpQTT78s0WRWiCkxz-s4l9tzeIqwA86upIkVSTk6TbaPbA5L6h_5HH9LoemluBqSPAGzi8DnJ2LBp4e8JGRVuWwOv8EWcKfrV0winCPce4xXtuD780KUW5CR6k"
}
NETDATA_CLAIM_URL = {
value = "https://app.netdata.cloud"
}
NETDATA_CLAIM_ROOMS = {
value = "28654d7b-4767-4b8e-bddc-8d134624bb3b"
}
}
pvc = {
netdata-config = {
name = "netdata-config"
pvc = true
pvc_size = "1Gi"
mount_path = "/etc/netdata"
}
netdata-lib = {
name = "netdata-lib"
pvc = true
pvc_size = "1Gi"
mount_path = "/var/lib/netdata"
}
netdata-cache = {
name = "netdata-cache"
pvc = true
pvc_size = "1Gi"
mount_path = "/var/cache/netdata"
}
netdata-host-root = {
host_path = "/"
name = "netdata-host-root"
mount_path = "/host/root"
}
netdata-host-passwd = {
host_path = "/etc/passwd"
name = "netdata-host-passwd"
mount_path = "/host/etc/passwd"
}
netdata-host-group = {
host_path = "/etc/group"
name = "netdata-host-group"
mount_path = "/host/etc/group"
}
netdata-host-localtime = {
host_path = "/etc/localtime"
name = "netdata-host-localtime"
mount_path = "/etc/localtime"
}
netdata-host-proc = {
host_path = "/proc"
name = "netdata-host-proc"
mount_path = "/host/proc"
}
netdata-host-sys = {
host_path = "/sys"
name = "netdata-host-sys"
mount_path = "/host/sys"
}
netdata-host-os-release = {
host_path = "/etc/os-release"
name = "netdata-host-os-release"
mount_path = "/host/etc/os-release"
}
netdata-host-var-log = {
host_path = "/var/log"
name = "netdata-host-var-log"
mount_path = "/host/var/log"
}
netdata-docker-sock = {
host_path = "/var/run/docker.sock"
name = "netdata-docker-sock"
mount_path = "/var/run/docker.sock"
}
netdata-host-dbus = {
host_path = "/run/dbus"
name = "netdata-host-dbus"
mount_path = "/run/dbus"
}
}
}
}
-772
View File
@@ -1,772 +0,0 @@
terraform {
required_version = "> 0.8.0"
required_providers {
bitwarden = {
source = "maxlaverse/bitwarden"
version = ">= 0.13.6"
}
}
}
provider "kubernetes" {
config_path = "~/.kube/config"
}
provider "bitwarden" {
email = "pierre@geeraert.eu"
master_password = ""
server = "https://bitwarden.tryton.geeraert.eu"
experimental {
embedded_client = true
}
}
#https://stackoverflow.com/questions/66670949/how-to-tell-terraform-to-skip-the-secret-manager-resource-if-it-exists
#for the secret not overwritten (not tested)
data "bitwarden_item_login" "example" {
search = "bookstack.zeus.geeraert.eu"
}
data "bitwarden_item_secure_note" "vpn_preshared_key" {
search = "terraform testing"
}
output "pgpin" {
value = nonsensitive(coalesce(data.bitwarden_item_secure_note.vpn_preshared_key.field.1.hidden,1234))
sensitive = true
}
resource "random_password" "password" {
length = 16
special = true
override_special = "!#$%&*()-_=+[]{}<>:?"
}
resource "bitwarden_item_secure_note" "terraform_upload_testing" {
name = "terraform upload testing"
# notes = <<EOT
#[global]
#secret = "<something sensitive>"
#EOT
organization_id = "a6361589-badd-4bde-9cb4-af8901161c0d"
collection_ids = ["3fa902cd-8244-46bc-a4ea-af8901262d94"]
field {
name = "category"
hidden = random_password.password.result
}
}
variable "kubernetes" {
type = map(object({
name = optional(string)
image = string
pvc = optional(map(object({
name = string
pvc = optional(bool, false)
config_map = optional(bool, false)
host_path = optional(string)
pvc_size = optional(string)
storage_class_name = optional(string, "nfs-storage-intelligent")
mount_path = string
})))
environment = optional(map(object({
name = optional(string)
value = optional(string)
value_from = optional(object({
secret_key_ref = object({
name = string
key = optional(string, null)
})
}))
})))
replicas = optional(number, 1)
namespace = optional(string)
connected_namespace = optional(string, "")
# namespace = optional(string,coalesce(connected_namespace,""))
#block_namespace_creation = optional(bool, false)
service_port = optional(list(number))
service_type = optional(string, "ClusterIP")
service_name = optional(string)
liveness_tcp_socket = optional(number)
liveness_http_get = optional(string)
liveness_http_get_path = optional(string)
database = optional(map(string))
redis = optional(map(string))
enabled = optional(bool, true)
secret_ref = optional(list(string))
config_map_ref = optional(list(string))
extra_manifest = optional(list(string))
requirements = optional(map(string))
# requirements = optional(map(string), {
# limits-cpu = "800m"
# limits-memory = "500Mi"
# requests-cpu = "200m"
# requests-memory = "200Mi"
# })
dns_nameservers = optional(string)
environment_variables = optional(map(string), { name = "value" })
security_context = optional(bool, false)
}))
}
locals {
pvc_details = flatten([
for key, value in var.kubernetes : [
for index, pvc in value.pvc : {
index = index
pvc = pvc.pvc
name = pvc.name
pvc_size = pvc.pvc_size
mount_path = pvc.mount_path
storage_class_name = pvc.storage_class_name
namespace = coalesce(value.namespace, value.connected_namespace, key)
}] if value.enabled == true && value.pvc != null
])
}
locals {
env_details = flatten([
for key, value in var.kubernetes : [
for index, env in value.environment_variables : {
index = index
name = env
}] if value.enabled == true && value.environment_variables != null
])
}
data "kubernetes_all_namespaces" "allns" {}
resource "kubernetes_namespace" "automatic" {
for_each = { for key, value in var.kubernetes : key => value if value.enabled == true && value.connected_namespace == "" }
metadata {
annotations = {
name = coalesce(each.value.namespace, each.key)
}
labels = {
deployment_method = "Terraform"
}
name = coalesce(each.value.namespace, each.key)
}
depends_on = [data.kubernetes_all_namespaces.allns]
}
locals {
kubernetes_manifests = flatten([
for k, obj in var.kubernetes : [
for index, manifest in(obj.extra_manifest != null ? obj.extra_manifest : []) :
{
key = "${k}_${index}"
name = obj.name
manifest = manifest
enabled = obj.enabled
}
if obj.enabled == true
]
])
}
resource "kubernetes_manifest" "manifest" {
for_each = { for item in local.kubernetes_manifests : item.key => item }
manifest = yamldecode(file(each.value.manifest))
provider = kubernetes
}
resource "kubernetes_persistent_volume_claim" "automatic-pvc" {
for_each = { for key, value in local.pvc_details : "${value.index}" => merge(value, { mew_key = value.index }) if value.pvc }
metadata {
namespace = coalesce(each.value.namespace, each.key)
name = "${each.value.name}-pvc"
labels = {
deployment_method = "Terraform"
}
}
spec {
access_modes = ["ReadWriteMany"]
storage_class_name = each.value.storage_class_name
resources {
requests = {
storage = each.value.pvc_size
}
}
}
}
resource "kubernetes_persistent_volume_claim" "automatic-pvc-database" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true }
metadata {
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
name = "${each.key}-db-pvc"
labels = {
deployment_method = "Terraform"
}
}
spec {
access_modes = ["ReadWriteMany"]
storage_class_name = "nfs-storage-intelligent"
resources {
requests = {
storage = "1Gi"
}
}
}
}
resource "kubernetes_persistent_volume_claim" "automatic-pvc-redis" {
for_each = { for key, value in var.kubernetes : key => value if value.redis != null && value.enabled == true }
metadata {
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
name = "${each.key}-redis-pvc"
labels = {
deployment_method = "Terraform"
}
}
spec {
access_modes = ["ReadWriteMany"]
storage_class_name = "nfs-storage-intelligent"
resources {
requests = {
storage = "1Gi"
}
}
}
}
resource "kubernetes_service" "automatic_service" {
for_each = { for key, value in var.kubernetes : key => value if value.service_port != null && value.enabled == true }
metadata {
name = "${each.key}-svc"
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
labels = {
deployment_method = "Terraform"
}
annotations = each.value.service_type == "LoadBalancer" ? {
"metallb.universe.tf/ip-allocated-from-pool" = "first-pool"
} : {}
}
spec {
selector = {
app = each.key
}
dynamic "port" {
for_each = each.value.service_port != null ? each.value.service_port : []
content {
port = port.value
target_port = port.value
name = replace("${each.key}${port.value}", "/(.{0,15})(.*)/", "$1")
}
}
# port {
# port = each.value.service_port
# target_port = each.value.service_port
# }
type = each.value.service_type
}
}
resource "kubernetes_service" "automatic_service_database" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true }
metadata {
name = "${each.key}-db-svc"
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
labels = {
deployment_method = "Terraform"
}
}
spec {
selector = {
app = "${each.key}-db"
}
port {
port = try(each.value.database.port, 5432)
target_port = try(each.value.database.port, 5432)
}
}
}
resource "kubernetes_service" "automatic_service_redis" {
for_each = { for key, value in var.kubernetes : key => value if value.redis != null && value.enabled == true }
metadata {
name = "${each.key}-redis-svc"
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
labels = {
deployment_method = "Terraform"
}
}
spec {
selector = {
app = "${each.key}-redis"
}
port {
port = 6379
target_port = 6379
}
}
}
resource "kubernetes_deployment_v1" "automatic" {
for_each = { for key, value in var.kubernetes : key => value if value.enabled == true }
metadata {
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
name = coalesce(each.value.name, each.key)
labels = {
app = each.key
deployment_method = "Terraform"
}
}
spec {
replicas = each.value.replicas
selector {
match_labels = {
app = each.key
}
}
template {
metadata {
labels = {
app = each.key
deployment_method = "Terraform"
}
}
spec {
container {
image = each.value.image
name = coalesce(each.value.name, each.key)
dynamic "port" {
for_each = each.value.service_port != null ? each.value.service_port : []
content {
container_port = port.value
# name = "${each.key}-${port.value}"
name = replace("${each.key}${port.value}", "/(.{0,15})(.*)/", "$1")
}
}
dynamic "volume_mount" {
for_each = each.value.pvc != null ? each.value.pvc : {}
content {
mount_path = volume_mount.value.mount_path
name = "${volume_mount.value.name}-pvc"
}
}
dynamic "env_from" {
for_each = each.value.secret_ref != null ? each.value.secret_ref : []
content {
dynamic "secret_ref" {
for_each = [1]
content {
name = env_from.value
}
}
}
}
dynamic "env_from" {
for_each = each.value.config_map_ref != null ? each.value.config_map_ref : []
content {
dynamic "config_map_ref" {
for_each = [1]
content {
name = env_from.value
}
}
}
}
dynamic "env" {
for_each = each.value.environment != null ? each.value.environment : {}
content {
name = env.key
value = env.value.value != null ? env.value.value : null
dynamic "value_from" {
for_each = env.value.value_from != null ? env.value.value_from : {}
content {
dynamic "secret_key_ref" {
for_each = [1]
content {
name = env.value.value_from.secret_key_ref.name
key = env.value.value_from.secret_key_ref.key
# optional = true
}
}
}
}
}
}
dynamic "resources" {
for_each = each.value.requirements != null ? [1] : []
content {
limits = {
cpu = each.value.requirements.limits-cpu
memory = each.value.requirements.limits-memory
}
requests = {
cpu = each.value.requirements.requests-cpu
memory = each.value.requirements.requests-memory
}
}
}
# resources {
# limits = {
# cpu = each.value.requirements.limits-cpu
# memory = each.value.requirements.limits-memory
# }
# requests = {
# cpu = each.value.requirements.requests-cpu
# memory = each.value.requirements.requests-memory
# }
# }
dynamic "security_context" {
for_each = each.value.security_context == true ? [1] : []
content {
privileged = true
#capabilities = {
# add : ["NET_ADMIN", "NET_RAW"]
#}
}
}
dynamic "liveness_probe" {
for_each = each.value.liveness_tcp_socket != null || each.value.liveness_http_get != null ? [""] : []
content {
dynamic "tcp_socket" {
for_each = each.value.liveness_tcp_socket != null ? [""] : []
content {
port = each.value.liveness_tcp_socket
}
}
dynamic "http_get" {
for_each = each.value.liveness_http_get != null ? [""] : []
content {
port = each.value.liveness_http_get
path = coalesce(each.value.liveness_http_get_path, "/")
}
}
initial_delay_seconds = 3
period_seconds = 3
}
}
}
dynamic "dns_config" {
for_each = each.value.dns_nameservers != null ? [1] : []
content {
nameservers = [each.value.dns_nameservers]
}
}
dynamic "volume" {
for_each = each.value.pvc != null ? each.value.pvc : {}
content {
name = "${volume.value.name}-pvc"
dynamic "persistent_volume_claim" {
for_each = volume.value.pvc ? [1] : []
content {
claim_name = "${volume.value.name}-pvc"
}
}
dynamic "config_map" {
for_each = volume.value.config_map ? [1] : []
content {
name = volume.value.name
}
}
dynamic "host_path" {
for_each = volume.value.host_path != null ? [1] : []
content {
path = volume.value.host_path
}
}
}
}
}
}
}
}
resource "kubernetes_deployment_v1" "database-automatic" {
for_each = { for key, value in var.kubernetes : key => value if value.database != null && value.enabled == true }
metadata {
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
name = "${coalesce(each.value.namespace, each.key)}-db"
labels = {
app = each.key
deployment_method = "Terraform"
database = "true"
}
}
spec {
replicas = each.value.replicas
selector {
match_labels = {
app = "${each.key}-db"
}
}
template {
metadata {
labels = {
app = "${each.key}-db"
deployment_method = "Terraform"
database = "true"
}
}
spec {
container {
image = try(each.value.database.image, "docker.io/library/postgres:latest")
name = "${coalesce(each.value.name, each.key)}-db"
port {
container_port = 5432
name = "database-port"
}
volume_mount {
mount_path = try(each.value.database.mountPath, "/var/lib/postgresql/data")
name = "${each.key}-db-pvc"
}
dynamic "env" {
for_each = each.value.environment != null ? each.value.environment : {}
content {
name = env.key
value = env.value.value != null ? env.value.value : null
dynamic "value_from" {
for_each = env.value.value_from != null ? env.value.value_from : {}
content {
dynamic "secret_key_ref" {
for_each = [1]
content {
name = env.value.value_from.secret_key_ref.name
key = env.value.value_from.secret_key_ref.key
# optional = true
}
}
}
}
}
}
# resources {
# limits = {
# cpu = each.value.requirements.limits-cpu
# memory = each.value.requirements.limits-memory
# }
# requests = {
# cpu = each.value.requirements.requests-cpu
# memory = each.value.requirements.requests-memory
# }
# }
# dynamic "liveness_probe" {
# for_each = each.value.liveness_tcp_socket != null || each.value.liveness_http_get != null ? [""] : []
# content {
# dynamic "tcp_socket" {
# for_each = each.value.liveness_tcp_socket != null ? [""] : []
# content {
# port = each.value.liveness_tcp_socket
# }
# }
# dynamic "http_get" {
# for_each = each.value.liveness_http_get != null ? [""] : []
# content {
# port = each.value.liveness_http_get
# path = coalesce(each.value.liveness_http_get_path, "/")
# }
# }
# initial_delay_seconds = 3
# period_seconds = 3
# }
# }
}
volume {
name = "${each.key}-db-pvc"
persistent_volume_claim {
claim_name = "${each.key}-db-pvc"
}
}
}
}
}
}
resource "kubernetes_deployment_v1" "redis-automatic" {
for_each = { for key, value in var.kubernetes : key => value if value.redis != null && value.enabled == true }
metadata {
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
name = "${coalesce(each.value.namespace, each.key)}-redis"
labels = {
app = each.key
deployment_method = "Terraform"
redis = "true"
}
}
spec {
replicas = each.value.replicas
selector {
match_labels = {
app = "${each.key}-redis"
}
}
template {
metadata {
labels = {
app = "${each.key}-redis"
deployment_method = "Terraform"
redis = "true"
}
}
spec {
container {
image = try(each.value.redis.image, "docker.io/library/redis:7")
name = "${coalesce(each.value.name, each.key)}-redis"
port {
container_port = 6379
name = "redis-port"
}
volume_mount {
mount_path = "/data"
name = "${each.key}-redis-pvc"
}
dynamic "env" {
for_each = each.value.environment != null ? each.value.environment : {}
content {
name = env.key
value = env.value.value != null ? env.value.value : null
dynamic "value_from" {
for_each = env.value.value_from != null ? env.value.value_from : {}
content {
dynamic "secret_key_ref" {
for_each = [1]
content {
name = env.value.value_from.secret_key_ref.name
key = env.value.value_from.secret_key_ref.key
# optional = true
}
}
}
}
}
}
# resources {
# limits = {
# cpu = each.value.requirements.limits-cpu
# memory = each.value.requirements.limits-memory
# }
# requests = {
# cpu = each.value.requirements.requests-cpu
# memory = each.value.requirements.requests-memory
# }
# }
# dynamic "liveness_probe" {
# for_each = each.value.liveness_tcp_socket != null || each.value.liveness_http_get != null ? [""] : []
# content {
# dynamic "tcp_socket" {
# for_each = each.value.liveness_tcp_socket != null ? [""] : []
# content {
# port = each.value.liveness_tcp_socket
# }
# }
# dynamic "http_get" {
# for_each = each.value.liveness_http_get != null ? [""] : []
# content {
# port = each.value.liveness_http_get
# path = coalesce(each.value.liveness_http_get_path, "/")
# }
# }
# initial_delay_seconds = 3
# period_seconds = 3
# }
# }
}
volume {
name = "${each.key}-redis-pvc"
persistent_volume_claim {
claim_name = "${each.key}-redis-pvc"
}
}
}
}
}
}
-185
View File
@@ -1,185 +0,0 @@
terraform {
required_version = "> 0.8.0"
}
provider "kubernetes" {
config_path = "~/.kube/config"
}
resource "kubernetes_namespace" "screeps" {
metadata {
annotations = {
name = "screeps"
}
name = "screeps"
}
}
resource "kubernetes_persistent_volume_claim" "screeps-pvc" {
metadata {
namespace = "screeps"
name = "screeps-pvc"
}
spec {
access_modes = ["ReadWriteMany"]
storage_class_name = "nfs-storage-intelligent"
resources {
requests = {
storage = "1Gi"
}
}
}
}
resource "kubernetes_deployment_v1" "screeps" {
metadata {
namespace = "screeps"
name = "screeps"
labels = {
app = "screepsserver"
}
}
spec {
replicas = 1
selector {
match_labels = {
app = "screepsserver"
}
}
template {
metadata {
labels = {
app = "screepsserver"
}
}
spec {
container {
image = "screepers/screeps-launcher"
name = "screeps-launcher"
port {
container_port = 21025
name = "screeps-port"
}
volume_mount {
mount_path = "/screeps"
name = "screeps-volume"
}
resources {
limits = {
cpu = "2"
memory = "2Gi"
}
requests = {
cpu = "250m"
memory = "500Mi"
}
}
}
volume {
name = "screeps-volume"
persistent_volume_claim {
claim_name = "screeps-pvc"
}
}
}
}
}
}
resource "kubernetes_service" "screeps_service" {
metadata {
name = "screeps"
namespace = "screeps"
}
spec {
selector = {
app = "screepsserver"
}
port {
port = 21025
}
}
}
variable "kubernetes" {
type = map(object({
service = string
#testingbool= bool
pvc_name = optional(string)
namespace = optional(string)
service_port = optional(number)
LoadBalancerbool = optional(string)
enabled = optional(bool, true)
proxy_cache = optional(bool, false)
extra-value = optional(string, "")
http2_bool = optional(bool, false)
proxy_pass_https = optional(bool, false)
authentication_required = optional(bool, false)
}))
}
resource "kubernetes_namespace" "automatic" {
for_each = { for key, value in var.kubernetes : key => value if value.enabled == true }
metadata {
annotations = {
name = coalesce(each.value.namespace, each.key)
}
name = coalesce(each.value.namespace, each.key)
}
}
resource "kubernetes_persistent_volume_claim" "automatic-pvc" {
for_each = { for key, value in var.kubernetes : key => value if value.pvc_name != null }
metadata {
namespace = coalesce(each.value.namespace, each.key)
name = coalesce(each.value.namespace, each.key)
}
spec {
access_modes = ["ReadWriteMany"]
storage_class_name = "nfs-storage-intelligent"
resources {
requests = {
storage = "1Gi"
}
}
}
}
resource "kubernetes_service" "automatic_service" {
for_each = { for key, value in var.kubernetes : key => value if value.service_port != null }
metadata {
name = coalesce(each.value.namespace, each.key)
namespace = coalesce(each.value.namespace, each.key)
}
spec {
selector = {
app = "screepsserver"
}
port {
port = each.value.service_port
}
if(each.value.LoadBalancerbool == "enabled" ? [type = "LoadBalancer"] :[]
}
}
}
+119
View File
@@ -0,0 +1,119 @@
variable "kubernetes_input" {
type = map(object({
name = optional(string)
docker = optional(bool)
namespace = optional(string)
connected_namespace = optional(string, "")
service_port = optional(list(number))
service_type = optional(string, "ClusterIP")
domain_name = optional(list(string))
legacy_domain = optional(bool, false)
exposed = optional(bool, true)
enabled = optional(bool, true)
}))
}
resource "kubernetes_ingress_v1" "automatic_ingress" {
# Keep your top-level filter for filtering active services
for_each = { for key, value in var.kubernetes_input : key => value if value.service_port != null && value.enabled == true && value.docker != true && value.exposed == true }
metadata {
name = "${each.key}-ingress"
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
annotations = {
"cert-manager.io/cluster-issuer" = "letsencrypt-prod"
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
}
}
spec {
ingress_class_name = "traefik"
# --- DYNAMIC TLS BLOCK ---
# Generates a separate TLS block + secret per domain entry
dynamic "tls" {
for_each = toset(coalesce(each.value.domain_name, [each.key]))
content {
hosts = [join(".", [tls.value, "geeraert.eu"])]
secret_name = "${each.key}-${tls.value}-tls-secret"
}
}
# --- DYNAMIC RULE BLOCK ---
# Loops through the domain list and creates an HTTP path routing rule for each
dynamic "rule" {
for_each = toset(coalesce(each.value.domain_name, [each.key]))
content {
host = join(".", [rule.value, "geeraert.eu"])
http {
path {
path = "/"
backend {
service {
name = "${each.key}-svc"
port {
number = each.value.service_port[0]
}
}
}
}
}
}
}
}
}
resource "kubernetes_ingress_v1" "automatic_ingress_legacy" {
for_each = { for key, value in var.kubernetes_input : key => value if value.service_port != null && value.enabled == true && value.docker != true && value.exposed == true && value.legacy_domain == true }
metadata {
name = "${each.key}-legacy-ingress"
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
annotations = {
"cert-manager.io/cluster-issuer" = "letsencrypt-prod"
"traefik.ingress.kubernetes.io/router.entrypoints" = "websecure"
}
}
spec {
ingress_class_name = "traefik"
# --- DYNAMIC TLS BLOCK ---
# Generates a separate TLS block + secret per domain entry
dynamic "tls" {
for_each = toset(coalesce(each.value.domain_name, [each.key]))
content {
hosts = [join(".", [tls.value, "tryton.geeraert.eu"])]
secret_name = "${each.key}-${tls.value}-tls-secret"
}
}
# --- DYNAMIC RULE BLOCK ---
# Loops through the domain list and creates an HTTP path routing rule for each
dynamic "rule" {
for_each = toset(coalesce(each.value.domain_name, [each.key]))
content {
host = join(".", [rule.value, "tryton.geeraert.eu"])
http {
path {
path = "/"
backend {
service {
name = "${each.key}-svc"
port {
number = each.value.service_port[0]
}
}
}
}
}
}
}
}
}
+97
View File
@@ -0,0 +1,97 @@
variable "kubernetes_input" {
type = map(object({
docker = optional(bool)
namespace = optional(string)
connected_namespace = optional(string, "")
service_port = optional(list(number))
service_type = optional(string, "ClusterIP")
database = optional(map(string))
redis = optional(map(string))
enabled = optional(bool, true)
}))
}
resource "kubernetes_service_v1" "automatic_service" {
for_each = { for key, value in var.kubernetes_input : key => value if value.service_port != null && value.enabled == true && value.docker != true }
metadata {
name = "${each.key}-svc"
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
labels = {
deployment_method = "Terraform"
}
annotations = each.value.service_type == "LoadBalancer" ? {
"metallb.universe.tf/ip-allocated-from-pool" = "first-pool"
} : {}
}
spec {
selector = {
app = each.key
}
dynamic "port" {
for_each = each.value.service_port != null ? each.value.service_port : []
content {
port = port.value
target_port = port.value
name = replace("${port.value}${each.key}", "/(.{0,15})(.*)/", "$1")
node_port = each.value.service_type == "NodePort" ? port.value : 0
}
}
type = each.value.service_type
}
}
resource "kubernetes_service_v1" "automatic_service_database" {
for_each = { for key, value in var.kubernetes_input : key => value if value.database != null && value.enabled == true && !(try(value.database.shunt, false)) && value.docker != true }
metadata {
name = "${each.key}-db-svc"
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
labels = {
deployment_method = "Terraform"
#username = "${resource.bitwarden-secrets_secret.automatic_bitwarden_secret_password[each.key].key}"
}
}
spec {
selector = {
app = "${each.key}-db"
}
port {
port = try(each.value.database.port, 5432)
target_port = try(each.value.database.port, 5432)
}
}
}
resource "kubernetes_service_v1" "automatic_service_redis" {
for_each = { for key, value in var.kubernetes_input : key => value if value.redis != null && value.enabled == true && value.docker != true }
metadata {
name = "${each.key}-redis-svc"
namespace = coalesce(each.value.namespace, each.value.connected_namespace, each.key)
labels = {
deployment_method = "Terraform"
}
}
spec {
selector = {
app = "${each.key}-redis"
}
port {
port = 6379
target_port = 6379
}
}
}
-18
View File
@@ -1,18 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
name: screeps
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: screeps-storage
namespace: screeps
spec:
storageClassName: nfs-storage-intelligent
accessModes:
- ReadWriteMany
resources:
requests:
storage: 20Gi
-6271
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff