feat: Add Kubernetes website module with configuration, resources, and NGINX setup

This commit is contained in:
2025-04-27 19:09:32 +02:00
parent 3c7c95c8ee
commit 761c183ce2
7 changed files with 141 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
locals {
persistent_folder = var.persistent_folder
primary_domain = var.primary_domain
websites = var.websites
}
+13
View File
@@ -0,0 +1,13 @@
terraform {
required_version = "~>1.8"
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = "~>2.18"
}
scaleway = {
source = "scaleway/scaleway"
version = "~>2.13"
}
}
}
@@ -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;
}
+17
View File
@@ -0,0 +1,17 @@
variable "persistent_folder" {
description = "The path to the persistent folder"
type = string
}
variable "primary_domain" {
description = "The primary domain for the websites"
type = string
}
variable "websites" {
description = "A list of websites to be deployed"
type = map(object({
domain_name = string
fqdn = list(string)
}))
}
+201
View File
@@ -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)
}
}
}
}
}
}