feat: Implement MariaDB and backup job modules with configuration and secrets management
This commit is contained in:
@@ -0,0 +1,244 @@
|
||||
resource "kubernetes_secret" "root_password" {
|
||||
metadata {
|
||||
name = "${var.app_name}-root-credentials"
|
||||
namespace = var.namespace
|
||||
}
|
||||
data = {
|
||||
username = "root"
|
||||
password = var.root_password
|
||||
}
|
||||
type = "Opaque"
|
||||
}
|
||||
|
||||
resource "kubernetes_service_account" "service_account" {
|
||||
|
||||
metadata {
|
||||
name = "${var.app_name}-mariadb-sa"
|
||||
namespace = var.namespace
|
||||
}
|
||||
|
||||
automount_service_account_token = false
|
||||
}
|
||||
|
||||
resource "kubernetes_secret" "app_password" {
|
||||
metadata {
|
||||
name = "${var.app_name}-app-credentials"
|
||||
namespace = var.namespace
|
||||
}
|
||||
data = {
|
||||
username = var.app_name
|
||||
password = var.app_password
|
||||
}
|
||||
type = "Opaque"
|
||||
}
|
||||
|
||||
resource "kubernetes_service" "service" {
|
||||
metadata {
|
||||
name = "mariadb"
|
||||
namespace = var.namespace
|
||||
}
|
||||
spec {
|
||||
port {
|
||||
port = 3306
|
||||
}
|
||||
selector = {
|
||||
app = "mariadb"
|
||||
}
|
||||
cluster_ip = "None"
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_deployment" "deployment" {
|
||||
metadata {
|
||||
name = "mariadb"
|
||||
namespace = var.namespace
|
||||
}
|
||||
spec {
|
||||
selector {
|
||||
match_labels = {
|
||||
app = "mariadb"
|
||||
}
|
||||
}
|
||||
strategy {
|
||||
type = "Recreate"
|
||||
}
|
||||
template {
|
||||
metadata {
|
||||
labels = {
|
||||
app = "mariadb"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
service_account_name = kubernetes_service_account.service_account.metadata[0].name
|
||||
container {
|
||||
name = "mariadb"
|
||||
image = "mariadb:${var.current_version}"
|
||||
|
||||
resources {
|
||||
requests = {
|
||||
memory = "100Mi"
|
||||
}
|
||||
}
|
||||
|
||||
liveness_probe {
|
||||
exec {
|
||||
command = ["sh", "-c", "mysqladmin status -uroot -p$MARIADB_ROOT_PASSWORD"]
|
||||
}
|
||||
initial_delay_seconds = 30
|
||||
period_seconds = 300
|
||||
timeout_seconds = 1
|
||||
failure_threshold = 15
|
||||
}
|
||||
|
||||
readiness_probe {
|
||||
exec {
|
||||
command = ["sh", "-c", "mysqladmin status -uroot -p$MARIADB_ROOT_PASSWORD"]
|
||||
}
|
||||
initial_delay_seconds = 120
|
||||
period_seconds = 10
|
||||
timeout_seconds = 1
|
||||
failure_threshold = 15
|
||||
}
|
||||
|
||||
env {
|
||||
name = "MARIADB_ROOT_PASSWORD"
|
||||
value_from {
|
||||
secret_key_ref {
|
||||
key = "password"
|
||||
name = kubernetes_secret.root_password.metadata[0].name
|
||||
}
|
||||
}
|
||||
}
|
||||
env {
|
||||
name = "MARIADB_ROOT_HOST"
|
||||
value = "10.%"
|
||||
}
|
||||
env {
|
||||
name = "MARIADB_USER"
|
||||
value_from {
|
||||
secret_key_ref {
|
||||
key = "username"
|
||||
name = kubernetes_secret.app_password.metadata[0].name
|
||||
}
|
||||
}
|
||||
}
|
||||
env {
|
||||
name = "MARIADB_PASSWORD"
|
||||
value_from {
|
||||
secret_key_ref {
|
||||
key = "password"
|
||||
name = kubernetes_secret.app_password.metadata[0].name
|
||||
}
|
||||
}
|
||||
}
|
||||
env {
|
||||
name = "MARIADB_DATABASE"
|
||||
value = var.app_name
|
||||
}
|
||||
port {
|
||||
container_port = 3306
|
||||
name = "mariadb"
|
||||
}
|
||||
volume_mount {
|
||||
mount_path = "/var/lib/mysql"
|
||||
name = "persistent-storage"
|
||||
}
|
||||
volume_mount {
|
||||
mount_path = "/docker-entrypoint-initdb.d"
|
||||
name = "initdb-storage"
|
||||
}
|
||||
}
|
||||
volume {
|
||||
name = "persistent-storage"
|
||||
host_path {
|
||||
path = "${var.database_folder}/${var.app_name}.data"
|
||||
}
|
||||
}
|
||||
volume {
|
||||
name = "initdb-storage"
|
||||
host_path {
|
||||
path = "${var.database_folder}/${var.app_name}.initdb.d"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# TODO: This should move out of here
|
||||
resource "kubernetes_cron_job_v1" "backup_data_cron" {
|
||||
metadata {
|
||||
name = "mariadb-backup-job"
|
||||
namespace = var.namespace
|
||||
}
|
||||
spec {
|
||||
concurrency_policy = "Forbid"
|
||||
schedule = var.cron_schedule
|
||||
failed_jobs_history_limit = 2
|
||||
successful_jobs_history_limit = 2
|
||||
job_template {
|
||||
metadata {
|
||||
labels = {
|
||||
app = "mariadb"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
backoff_limit = 1
|
||||
parallelism = 1
|
||||
completions = 1
|
||||
active_deadline_seconds = 1800
|
||||
template {
|
||||
metadata {}
|
||||
spec {
|
||||
container {
|
||||
name = "sql-cron-job"
|
||||
image = "mariadb:${var.current_version}"
|
||||
env {
|
||||
name = "MARIADB_USER"
|
||||
value_from {
|
||||
secret_key_ref {
|
||||
key = "username"
|
||||
name = kubernetes_secret.app_password.metadata[0].name
|
||||
}
|
||||
}
|
||||
}
|
||||
env {
|
||||
name = "MARIADB_PASSWORD"
|
||||
value_from {
|
||||
secret_key_ref {
|
||||
key = "password"
|
||||
name = kubernetes_secret.app_password.metadata[0].name
|
||||
}
|
||||
}
|
||||
}
|
||||
env {
|
||||
name = "MARIADB_DATABASE"
|
||||
value = var.app_name
|
||||
}
|
||||
security_context {
|
||||
allow_privilege_escalation = false
|
||||
}
|
||||
command = ["/bin/sh", "-c"]
|
||||
args = [join(";", [
|
||||
"/usr/bin/mariadb-dump --single-transaction -h mariadb -u $MARIADB_USER -p$MARIADB_PASSWORD $MARIADB_DATABASE | gzip > /backups/${var.app_name}-sql-`date +\"%Y%m%d\"`.sql.gz",
|
||||
"find /backups -type f -name '${var.app_name}-sql-*.sql.gz' -mtime +${var.retention_days} | xargs --no-run-if-empty rm"
|
||||
])]
|
||||
volume_mount {
|
||||
mount_path = "/backups"
|
||||
name = "backups-storage"
|
||||
}
|
||||
}
|
||||
volume {
|
||||
name = "backups-storage"
|
||||
host_path {
|
||||
path = var.backup_folder
|
||||
}
|
||||
}
|
||||
restart_policy = "Never"
|
||||
termination_grace_period_seconds = 30
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
output "host" {
|
||||
value = "mariadb"
|
||||
}
|
||||
|
||||
output "port" {
|
||||
value = 3306
|
||||
}
|
||||
|
||||
output "root_crendentials_name" {
|
||||
value = kubernetes_secret.root_password.metadata[0].name
|
||||
}
|
||||
|
||||
output "app_crendentials_name" {
|
||||
value = kubernetes_secret.app_password.metadata[0].name
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
terraform {
|
||||
required_version = "~>1.8"
|
||||
required_providers {
|
||||
kubernetes = {
|
||||
source = "hashicorp/kubernetes"
|
||||
version = "~>2.18"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
variable "namespace" {
|
||||
description = "namespace"
|
||||
sensitive = false
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "app_name" {
|
||||
description = "database name"
|
||||
sensitive = false
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "root_password" {
|
||||
description = "root password"
|
||||
sensitive = true
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "app_password" {
|
||||
description = "user password"
|
||||
sensitive = true
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "database_folder" {
|
||||
description = "host storage path"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "cron_schedule" {
|
||||
description = "Cronjob schedule for data backups"
|
||||
default = "* 2 * * *"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "retention_days" {
|
||||
description = "Backup retention days"
|
||||
default = 14
|
||||
type = number
|
||||
}
|
||||
|
||||
variable "current_version" {
|
||||
description = "version"
|
||||
default = "10.7.8"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "backup_folder" {
|
||||
description = "Backup source location"
|
||||
type = string
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
locals {
|
||||
rclone_version = "1.61.1"
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
resource "kubernetes_service_account" "service_account" {
|
||||
metadata {
|
||||
name = "${var.app_name}-backup-sa"
|
||||
namespace = var.namespace
|
||||
}
|
||||
|
||||
automount_service_account_token = false
|
||||
}
|
||||
|
||||
resource "kubernetes_secret" "scaleway_api_credentials" {
|
||||
metadata {
|
||||
name = "${var.app_name}-scaleway-api-credentials"
|
||||
namespace = var.namespace
|
||||
}
|
||||
data = {
|
||||
access_key = var.access_key
|
||||
secret_key = var.secret_key
|
||||
}
|
||||
type = "Opaque"
|
||||
}
|
||||
|
||||
resource "kubernetes_config_map" "rclone_config" {
|
||||
metadata {
|
||||
name = "rclone-config"
|
||||
namespace = var.namespace
|
||||
}
|
||||
data = {
|
||||
"rclone.conf" = file("${path.module}/resources/rclone.conf")
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_cron_job_v1" "backup_job" {
|
||||
metadata {
|
||||
name = "${var.app_name}-backup"
|
||||
namespace = var.namespace
|
||||
}
|
||||
spec {
|
||||
concurrency_policy = "Forbid"
|
||||
schedule = var.cron_schedule
|
||||
failed_jobs_history_limit = 2
|
||||
successful_jobs_history_limit = 2
|
||||
job_template {
|
||||
metadata {
|
||||
labels = {
|
||||
app = "${var.app_name}-backup"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
backoff_limit = 1
|
||||
parallelism = 1
|
||||
completions = 1
|
||||
active_deadline_seconds = 1800
|
||||
template {
|
||||
metadata {
|
||||
labels = {
|
||||
app = "${var.app_name}-backup"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
service_account_name = kubernetes_service_account.service_account.metadata[0].name
|
||||
security_context {
|
||||
run_as_user = 0
|
||||
}
|
||||
container {
|
||||
|
||||
name = "${var.app_name}-backup"
|
||||
image = "rclone/rclone:${local.rclone_version}"
|
||||
image_pull_policy = "Always"
|
||||
|
||||
resources {
|
||||
requests = {
|
||||
memory = "100Mi"
|
||||
}
|
||||
}
|
||||
|
||||
env {
|
||||
name = "SCW_ACCESS_KEY"
|
||||
value_from {
|
||||
secret_key_ref {
|
||||
key = "access_key"
|
||||
name = kubernetes_secret.scaleway_api_credentials.metadata[0].name
|
||||
}
|
||||
}
|
||||
}
|
||||
env {
|
||||
name = "SCW_SECRET_KEY"
|
||||
value_from {
|
||||
secret_key_ref {
|
||||
key = "secret_key"
|
||||
name = kubernetes_secret.scaleway_api_credentials.metadata[0].name
|
||||
}
|
||||
}
|
||||
}
|
||||
env {
|
||||
name = "SCW_DEFAULT_PROJECT_ID"
|
||||
value = var.scaleway_project_id
|
||||
}
|
||||
env {
|
||||
name = "SCW_DEFAULT_ORGANIZATION_ID"
|
||||
value = var.scaleway_organization_id
|
||||
}
|
||||
env {
|
||||
name = "SCW_DEFAULT_REGION"
|
||||
value = var.scaleway_region
|
||||
}
|
||||
env {
|
||||
name = "SCW_DEFAULT_ZONE"
|
||||
value = var.scaleway_zone
|
||||
}
|
||||
env {
|
||||
name = "BUCKET_NAME"
|
||||
value = var.bucket_name
|
||||
}
|
||||
command = ["/bin/sh", "-c"]
|
||||
args = [join(";", [
|
||||
"apk update",
|
||||
"apk add gettext",
|
||||
"envsubst</etc/rclone.conf.tmpl>/etc/rclone.conf",
|
||||
"tar -zcvpf /backup/${var.app_name}-files-`date +\"%Y%m%d\"`.tar.gz /files",
|
||||
"find /backup -type f -name '${var.app_name}-files-*.tar.gz' -mtime +${var.retention_days} | xargs --no-run-if-empty rm",
|
||||
"/usr/local/bin/rclone --config=/etc/rclone.conf sync --progress /backup scaleway:$BUCKET_NAME/${var.app_name}-backup"
|
||||
])]
|
||||
security_context {
|
||||
allow_privilege_escalation = false
|
||||
}
|
||||
volume_mount {
|
||||
name = "backup-storage"
|
||||
mount_path = "/backup"
|
||||
}
|
||||
volume_mount {
|
||||
name = "persistent-storage"
|
||||
mount_path = "/files"
|
||||
read_only = true
|
||||
}
|
||||
volume_mount {
|
||||
name = "rclone-conf"
|
||||
mount_path = "/etc/rclone.conf.tmpl"
|
||||
sub_path = "rclone.conf"
|
||||
read_only = true
|
||||
}
|
||||
}
|
||||
volume {
|
||||
name = "backup-storage"
|
||||
host_path {
|
||||
path = var.target_folder
|
||||
}
|
||||
}
|
||||
volume {
|
||||
name = "persistent-storage"
|
||||
host_path {
|
||||
path = var.source_folder
|
||||
}
|
||||
}
|
||||
volume {
|
||||
name = "rclone-conf"
|
||||
config_map {
|
||||
name = kubernetes_config_map.rclone_config.metadata[0].name
|
||||
}
|
||||
}
|
||||
restart_policy = "Never"
|
||||
termination_grace_period_seconds = 30
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
terraform {
|
||||
required_version = "~>1.8"
|
||||
required_providers {
|
||||
kubernetes = {
|
||||
source = "hashicorp/kubernetes"
|
||||
version = "~>2.18"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
[scaleway]
|
||||
type = s3
|
||||
provider = Scaleway
|
||||
env_auth = false
|
||||
access_key_id = $SCW_ACCESS_KEY
|
||||
secret_access_key = $SCW_SECRET_KEY
|
||||
region = $SCW_DEFAULT_REGION
|
||||
endpoint = s3.$SCW_DEFAULT_REGION.scw.cloud
|
||||
acl = private
|
||||
storage_class = STANDARD
|
||||
@@ -0,0 +1,70 @@
|
||||
variable "bucket_name" {
|
||||
description = "Backup bucket name"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "namespace" {
|
||||
description = "Namespace"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "scaleway_project_id" {
|
||||
description = "Scaleway project id"
|
||||
sensitive = true
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "scaleway_organization_id" {
|
||||
description = "Scaleway organization id"
|
||||
sensitive = true
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "scaleway_region" {
|
||||
description = "Scaleway region"
|
||||
default = "fr-par"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "scaleway_zone" {
|
||||
default = "fr-par-2"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "cron_schedule" {
|
||||
description = "Cronjob schedule for data backups"
|
||||
default = "* 2 * * *"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "access_key" {
|
||||
description = "Access key"
|
||||
sensitive = true
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "secret_key" {
|
||||
description = "Secret key"
|
||||
sensitive = true
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "app_name" {
|
||||
description = "Name of the app to backup"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "source_folder" {
|
||||
description = "Name of host folder"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "target_folder" {
|
||||
description = "Backup source location"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "retention_days" {
|
||||
description = "backup retention days"
|
||||
type = string
|
||||
}
|
||||
Reference in New Issue
Block a user