feat: Enhance website deployment and build process
- Added rsync installation in setup-env action for file synchronization. - Excluded playbook_websites.yml from ansible-apply-playbook workflow. - Created a new workflow for building and releasing the Hugo website. - Added submodule for Hugo theme in .gitmodules. - Updated host_vars for production to include websites configuration. - Introduced playbook_websites.yml for managing static files deployment. - Implemented hugo_build script for building and archiving Hugo sites. - Updated inventory to include a new web group for website deployment. - Refactored Terraform configuration to support new website structure. - Removed deprecated WordPress Terraform configuration. - Added .gitignore files for websites and specific Hugo site. - Created archetype and configuration files for the Hugo site. - Added static assets including CV and images for the Hugo site. - Integrated Hugo profile theme as a submodule for the website.
This commit is contained in:
+12
-11
@@ -1,25 +1,26 @@
|
||||
locals {
|
||||
|
||||
# general
|
||||
domain_name = "alexpires.me"
|
||||
|
||||
# storage
|
||||
persistent_folder = "/mnt/microk8s_persistent"
|
||||
database_folder = "/var/lib"
|
||||
|
||||
# apps
|
||||
wordpress_version = "6.7.2"
|
||||
wordpress_fqdns = ["blog.${local.domain_name}", "www.${local.domain_name}", "${local.domain_name}"]
|
||||
wordpress_sql_backup_cron_schedule = "0 2 * * *"
|
||||
wordpress_files_backup_cron_schedule = "10 2 * * *"
|
||||
# domains
|
||||
primary_domain = "alexpires.me"
|
||||
websites = {
|
||||
"alexpires.me" = {
|
||||
domain_name = "alexpires.me"
|
||||
fqdn = ["blog.alexpires.me", "www.alexpires.me", "alexpires.me"]
|
||||
}
|
||||
}
|
||||
|
||||
gitea_version = "1.23.4"
|
||||
gitea_fqdn = "code.${local.domain_name}"
|
||||
gitea_fqdn = "code.${local.primary_domain}"
|
||||
gitea_sql_backup_cron_schedule = "20 2 * * *"
|
||||
gitea_files_backup_cron_schedule = "30 2 * * *"
|
||||
|
||||
nextcloud_version = "30.0.0-apache"
|
||||
nextcloud_fqdn = "cloud.${local.domain_name}"
|
||||
nextcloud_fqdn = "cloud.${local.primary_domain}"
|
||||
nextcloud_sql_backup_cron_schedule = "40 2 * * *"
|
||||
nextcloud_files_backup_cron_schedule = "50 2 * * *"
|
||||
|
||||
@@ -34,7 +35,7 @@ locals {
|
||||
m3uproxy_version = "latest"
|
||||
wireguard_version = "1.0.20210914-r4-ls54"
|
||||
squid_version = "6.1-23.10_edge"
|
||||
m3uproxy_fqdn = "tv.${local.domain_name}"
|
||||
m3uproxy_fqdn = "tv.${local.primary_domain}"
|
||||
geoip_image = "maxmindinc/geoipupdate"
|
||||
geoip_version = "latest"
|
||||
|
||||
@@ -47,7 +48,7 @@ locals {
|
||||
|
||||
# rustdesk
|
||||
rustdesk_version = "latest"
|
||||
rustdesk_fqdn = "rustdesk.${local.domain_name}"
|
||||
rustdesk_fqdn = "rustdesk.${local.primary_domain}"
|
||||
|
||||
# backup
|
||||
local_backup_retention_days = 2
|
||||
|
||||
@@ -25,10 +25,10 @@ locals {
|
||||
# Email configuration
|
||||
SMTP_HOST = local.scaleway_smtp_host
|
||||
SMTP_PORT = 465
|
||||
MY_PRIMARY_DOMAIN = local.domain_name
|
||||
MY_PRIMARY_DOMAIN = local.primary_domain
|
||||
MY_DESTINATION = join(",", [for account in local.email_accounts : account.domain])
|
||||
MY_NETWORKS = "127.0.0.0/8"
|
||||
MAILNAME = "smtp.${local.domain_name}"
|
||||
MAILNAME = "smtp.${local.primary_domain}"
|
||||
DOVECOT_AUTH_ADDRESS = "dovecot-auth.mail.svc.cluster.local"
|
||||
DOVECOT_AUTH_PORT = 31000
|
||||
DOVECOT_LMTP_ADDRESS = "dovecot-lmtp.mail.svc.cluster.local"
|
||||
@@ -201,8 +201,8 @@ resource "kubernetes_manifest" "mail_certificate" {
|
||||
name = "letsencrypt-prod"
|
||||
kind = "ClusterIssuer"
|
||||
}
|
||||
commonName = "imap.${local.domain_name}"
|
||||
dnsNames = ["imap.${local.domain_name}", "smtp.${local.domain_name}"]
|
||||
commonName = "imap.${local.primary_domain}"
|
||||
dnsNames = flatten([for account in local.email_accounts : ["imap.${account.domain}", "smtp.${account.domain}"]])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
server {
|
||||
listen 8080;
|
||||
server_name localhost;
|
||||
|
||||
gzip on;
|
||||
gzip_comp_level 9;
|
||||
gzip_types
|
||||
text/html
|
||||
text/plain
|
||||
text/css
|
||||
text/js
|
||||
text/xml
|
||||
text/javascript
|
||||
application/javascript
|
||||
application/json
|
||||
application/xml
|
||||
application/rss+xml
|
||||
image/svg+xml;
|
||||
|
||||
root /tmp/site;
|
||||
|
||||
location / {
|
||||
index index.html index.htm;
|
||||
}
|
||||
|
||||
location ~* ^/([^/]+) {
|
||||
index index.html index.htm;
|
||||
error_page 404 = @error;
|
||||
}
|
||||
|
||||
error_page 404 /404.html;
|
||||
location @error {
|
||||
try_files /$1/404.html /404.html =404;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
worker_processes auto;
|
||||
|
||||
error_log /var/log/nginx/error.log notice;
|
||||
pid /tmp/nginx.pid;
|
||||
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
proxy_temp_path /tmp/proxy_temp;
|
||||
client_body_temp_path /tmp/client_temp;
|
||||
fastcgi_temp_path /tmp/fastcgi_temp;
|
||||
uwsgi_temp_path /tmp/uwsgi_temp;
|
||||
scgi_temp_path /tmp/scgi_temp;
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
sendfile on;
|
||||
|
||||
keepalive_timeout 65;
|
||||
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
locals {
|
||||
websites_path = "${local.persistent_folder}/web"
|
||||
}
|
||||
|
||||
resource "kubernetes_namespace" "website" {
|
||||
metadata {
|
||||
annotations = {
|
||||
name = "website"
|
||||
}
|
||||
|
||||
labels = {
|
||||
name = "website"
|
||||
}
|
||||
|
||||
name = "website"
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_service_account" "website_service_account" {
|
||||
|
||||
metadata {
|
||||
name = "website-app-sa"
|
||||
namespace = kubernetes_namespace.website.metadata[0].name
|
||||
}
|
||||
|
||||
automount_service_account_token = false
|
||||
}
|
||||
|
||||
|
||||
resource "kubernetes_service" "website" {
|
||||
for_each = local.websites
|
||||
metadata {
|
||||
name = format("website-%s", replace(each.key, ".", "-"))
|
||||
namespace = kubernetes_namespace.website.metadata[0].name
|
||||
}
|
||||
spec {
|
||||
port {
|
||||
port = 80
|
||||
target_port = "http"
|
||||
}
|
||||
selector = {
|
||||
app = format("website-%s", replace(each.key, ".", "-"))
|
||||
}
|
||||
cluster_ip = "None"
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_config_map" "nginx_config" {
|
||||
metadata {
|
||||
name = "nginx-config"
|
||||
namespace = kubernetes_namespace.website.metadata[0].name
|
||||
}
|
||||
|
||||
data = {
|
||||
"nginx.conf" = file("${path.module}/resources/nginx/nginx.conf")
|
||||
"default.conf" = file("${path.module}/resources/nginx/conf.d/default.conf")
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_ingress_v1" "website_ingress" {
|
||||
for_each = local.websites
|
||||
metadata {
|
||||
name = "website-ingress"
|
||||
namespace = kubernetes_namespace.website.metadata[0].name
|
||||
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "public"
|
||||
"cert-manager.io/cluster-issuer" = "letsencrypt-prod"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
tls {
|
||||
hosts = each.value.fqdn
|
||||
secret_name = format("website-%s-tls", replace(each.key, ".", "-"))
|
||||
}
|
||||
dynamic "rule" {
|
||||
for_each = each.value.fqdn
|
||||
content {
|
||||
host = rule.value
|
||||
http {
|
||||
path {
|
||||
backend {
|
||||
service {
|
||||
name = format("website-%s", replace(each.key, ".", "-"))
|
||||
port {
|
||||
number = 80
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_deployment" "website" {
|
||||
for_each = local.websites
|
||||
|
||||
metadata {
|
||||
name = "website-app"
|
||||
namespace = kubernetes_namespace.website.metadata[0].name
|
||||
}
|
||||
spec {
|
||||
selector {
|
||||
match_labels = {
|
||||
app = format("website-%s", replace(each.key, ".", "-"))
|
||||
}
|
||||
}
|
||||
strategy {
|
||||
type = "RollingUpdate"
|
||||
}
|
||||
template {
|
||||
metadata {
|
||||
labels = {
|
||||
app = format("website-%s", replace(each.key, ".", "-"))
|
||||
}
|
||||
}
|
||||
spec {
|
||||
service_account_name = kubernetes_service_account.website_service_account.metadata[0].name
|
||||
|
||||
security_context {
|
||||
fs_group = 1000
|
||||
run_as_user = 1000
|
||||
}
|
||||
|
||||
container {
|
||||
name = "website"
|
||||
image = "nginx:stable-alpine"
|
||||
image_pull_policy = "Always"
|
||||
|
||||
resources {
|
||||
requests = {
|
||||
memory = "100Mi"
|
||||
}
|
||||
limits = {
|
||||
memory = "500Mi"
|
||||
}
|
||||
}
|
||||
|
||||
readiness_probe {
|
||||
http_get {
|
||||
path = "/"
|
||||
port = 8080
|
||||
}
|
||||
initial_delay_seconds = 5
|
||||
period_seconds = 10
|
||||
}
|
||||
|
||||
liveness_probe {
|
||||
http_get {
|
||||
path = "/"
|
||||
port = 8080
|
||||
}
|
||||
initial_delay_seconds = 5
|
||||
period_seconds = 10
|
||||
}
|
||||
|
||||
security_context {
|
||||
allow_privilege_escalation = false
|
||||
}
|
||||
|
||||
port {
|
||||
container_port = 8080
|
||||
name = "http"
|
||||
}
|
||||
volume_mount {
|
||||
name = "nginx-config"
|
||||
mount_path = "/etc/nginx/nginx.conf"
|
||||
sub_path = "nginx.conf"
|
||||
read_only = true
|
||||
}
|
||||
volume_mount {
|
||||
name = "nginx-config"
|
||||
mount_path = "/etc/nginx/conf.d/default.conf"
|
||||
sub_path = "default.conf"
|
||||
read_only = true
|
||||
}
|
||||
volume_mount {
|
||||
name = "website"
|
||||
mount_path = "/tmp/site"
|
||||
read_only = true
|
||||
}
|
||||
}
|
||||
volume {
|
||||
name = "nginx-config"
|
||||
config_map {
|
||||
name = kubernetes_config_map.nginx_config.metadata[0].name
|
||||
}
|
||||
}
|
||||
volume {
|
||||
name = "website"
|
||||
host_path {
|
||||
path = format("%s/%s", local.websites_path, each.key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,239 +0,0 @@
|
||||
locals {
|
||||
wordpress_path = "${local.persistent_folder}/wordpress"
|
||||
wordpress_db_path = "${local.database_folder}/mysql.wordpress"
|
||||
wordpress_backup_path = "${local.persistent_folder}/backup.wordpress"
|
||||
}
|
||||
|
||||
resource "kubernetes_namespace" "wordpress" {
|
||||
metadata {
|
||||
annotations = {
|
||||
name = "wordpress"
|
||||
}
|
||||
|
||||
labels = {
|
||||
name = "wordpress"
|
||||
}
|
||||
|
||||
name = "wordpress"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Setup MariaDB database
|
||||
#
|
||||
module "wordpress_database" {
|
||||
source = "./modules/k8s_mariadb"
|
||||
|
||||
namespace = kubernetes_namespace.wordpress.metadata[0].name
|
||||
app_name = "wordpress"
|
||||
|
||||
app_password = var.wordpress_mysql_password
|
||||
root_password = var.mysql_root_password
|
||||
|
||||
retention_days = local.local_backup_retention_days
|
||||
cron_schedule = local.wordpress_sql_backup_cron_schedule
|
||||
|
||||
database_folder = local.wordpress_db_path
|
||||
backup_folder = local.wordpress_backup_path
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Setup rsync backup job to scaleway bucket
|
||||
#
|
||||
module "wordpress_backup" {
|
||||
source = "./modules/scw_backup_job"
|
||||
|
||||
namespace = kubernetes_namespace.wordpress.metadata[0].name
|
||||
app_name = "wordpress"
|
||||
|
||||
scaleway_organization_id = var.scaleway_organization_id
|
||||
scaleway_project_id = var.scaleway_organization_id
|
||||
access_key = scaleway_iam_api_key.backup_app_api.access_key
|
||||
secret_key = scaleway_iam_api_key.backup_app_api.secret_key
|
||||
bucket_name = scaleway_object_bucket.backup.name
|
||||
|
||||
retention_days = local.local_backup_retention_days
|
||||
cron_schedule = local.wordpress_files_backup_cron_schedule
|
||||
|
||||
source_folder = local.wordpress_path
|
||||
target_folder = local.wordpress_backup_path
|
||||
}
|
||||
|
||||
#
|
||||
# Gitea service, ingress, deployment and file backup job
|
||||
#
|
||||
resource "kubernetes_service_account" "wordpress_service_account" {
|
||||
|
||||
metadata {
|
||||
name = "wordpress-app-sa"
|
||||
namespace = kubernetes_namespace.wordpress.metadata[0].name
|
||||
}
|
||||
|
||||
automount_service_account_token = false
|
||||
}
|
||||
|
||||
|
||||
resource "kubernetes_service" "wordpress" {
|
||||
metadata {
|
||||
name = "http"
|
||||
namespace = kubernetes_namespace.wordpress.metadata[0].name
|
||||
}
|
||||
spec {
|
||||
port {
|
||||
port = 80
|
||||
target_port = "http"
|
||||
}
|
||||
selector = {
|
||||
app = "wordpress"
|
||||
}
|
||||
cluster_ip = "None"
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_ingress_v1" "wordpress_ingress" {
|
||||
metadata {
|
||||
name = "wordpress-ingress"
|
||||
namespace = kubernetes_namespace.wordpress.metadata[0].name
|
||||
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "public"
|
||||
"cert-manager.io/cluster-issuer" = "letsencrypt-prod"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
tls {
|
||||
hosts = local.wordpress_fqdns
|
||||
secret_name = "wordpress-le-tls"
|
||||
}
|
||||
dynamic "rule" {
|
||||
for_each = local.wordpress_fqdns
|
||||
content {
|
||||
host = rule.value
|
||||
http {
|
||||
path {
|
||||
backend {
|
||||
service {
|
||||
name = "http"
|
||||
port {
|
||||
number = 80
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_deployment" "wordpress" {
|
||||
|
||||
depends_on = [module.wordpress_database]
|
||||
|
||||
metadata {
|
||||
name = "wordpress-app"
|
||||
namespace = kubernetes_namespace.wordpress.metadata[0].name
|
||||
}
|
||||
spec {
|
||||
selector {
|
||||
match_labels = {
|
||||
app = "wordpress"
|
||||
}
|
||||
}
|
||||
strategy {
|
||||
type = "RollingUpdate"
|
||||
}
|
||||
template {
|
||||
metadata {
|
||||
labels = {
|
||||
app = "wordpress"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
service_account_name = kubernetes_service_account.wordpress_service_account.metadata[0].name
|
||||
|
||||
container {
|
||||
name = "wordpress"
|
||||
image = "wordpress:${local.wordpress_version}"
|
||||
image_pull_policy = "IfNotPresent"
|
||||
|
||||
resources {
|
||||
requests = {
|
||||
memory = "100Mi"
|
||||
}
|
||||
limits = {
|
||||
memory = "500Mi"
|
||||
}
|
||||
}
|
||||
|
||||
# readiness_probe {
|
||||
# http_get {
|
||||
# path = "/?nocache"
|
||||
# port = "http"
|
||||
# }
|
||||
# initial_delay_seconds = 20
|
||||
# period_seconds = 10
|
||||
# success_threshold = 1
|
||||
# failure_threshold = 5
|
||||
# }
|
||||
|
||||
# liveness_probe {
|
||||
# tcp_socket {
|
||||
# port = "http"
|
||||
# }
|
||||
# initial_delay_seconds = 30
|
||||
# period_seconds = 60
|
||||
# success_threshold = 1
|
||||
# failure_threshold = 10
|
||||
# }
|
||||
security_context {
|
||||
allow_privilege_escalation = false
|
||||
}
|
||||
|
||||
env {
|
||||
name = "WORDPRESS_DB_NAME"
|
||||
value = "wordpress"
|
||||
}
|
||||
env {
|
||||
name = "WORDPRESS_DB_HOST"
|
||||
value = "${module.wordpress_database.host}:${module.wordpress_database.port}"
|
||||
}
|
||||
env {
|
||||
name = "WORDPRESS_DB_USER"
|
||||
value_from {
|
||||
secret_key_ref {
|
||||
key = "username"
|
||||
name = module.wordpress_database.app_crendentials_name
|
||||
}
|
||||
}
|
||||
}
|
||||
env {
|
||||
name = "WORDPRESS_DB_PASSWORD"
|
||||
value_from {
|
||||
secret_key_ref {
|
||||
key = "password"
|
||||
name = module.wordpress_database.app_crendentials_name
|
||||
}
|
||||
}
|
||||
}
|
||||
port {
|
||||
container_port = 80
|
||||
name = "http"
|
||||
}
|
||||
volume_mount {
|
||||
mount_path = "/var/www/html"
|
||||
name = "persistent-storage"
|
||||
}
|
||||
}
|
||||
volume {
|
||||
name = "persistent-storage"
|
||||
host_path {
|
||||
path = local.wordpress_path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user