Compare commits
3 Commits
3471374cb6
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
911bc3eb76 | ||
|
|
35b78f672c | ||
|
|
10528dd7bb |
@@ -5,17 +5,43 @@ resource "digitalocean_kubernetes_cluster" "main" {
|
|||||||
region = var.region
|
region = var.region
|
||||||
version = var.k8s_version
|
version = var.k8s_version
|
||||||
|
|
||||||
|
# Required by provider but managed externally — do not let Terraform recreate
|
||||||
node_pool {
|
node_pool {
|
||||||
name = "workers"
|
name = "workers"
|
||||||
size = var.k8s_node_size
|
size = "s-2vcpu-4gb"
|
||||||
min_nodes = var.k8s_min_nodes
|
node_count = 0
|
||||||
max_nodes = var.k8s_max_nodes
|
}
|
||||||
auto_scale = true
|
|
||||||
|
lifecycle {
|
||||||
|
ignore_changes = [node_pool]
|
||||||
}
|
}
|
||||||
|
|
||||||
tags = ["lunarfront", "k8s"]
|
tags = ["lunarfront", "k8s"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Customer pool — auto-scales for customer app instances
|
||||||
|
resource "digitalocean_kubernetes_node_pool" "system" {
|
||||||
|
cluster_id = digitalocean_kubernetes_cluster.main.id
|
||||||
|
name = "system"
|
||||||
|
size = var.k8s_system_node_size
|
||||||
|
node_count = 2
|
||||||
|
labels = {
|
||||||
|
role = "system"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "digitalocean_kubernetes_node_pool" "customers" {
|
||||||
|
cluster_id = digitalocean_kubernetes_cluster.main.id
|
||||||
|
name = "customers"
|
||||||
|
size = var.k8s_customer_node_size
|
||||||
|
min_nodes = 0
|
||||||
|
max_nodes = var.k8s_max_customer_nodes
|
||||||
|
auto_scale = true
|
||||||
|
labels = {
|
||||||
|
role = "customer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# ─── DNS — wildcard for customer subdomains → cluster load balancer ───────────
|
# ─── DNS — wildcard for customer subdomains → cluster load balancer ───────────
|
||||||
# Uncomment after the cluster is up and nginx ingress load balancer IP is known.
|
# Uncomment after the cluster is up and nginx ingress load balancer IP is known.
|
||||||
# Set cluster_lb_ip in terraform.tfvars then re-run terraform apply.
|
# Set cluster_lb_ip in terraform.tfvars then re-run terraform apply.
|
||||||
|
|||||||
@@ -39,135 +39,24 @@ data "cloudflare_zone" "main" {
|
|||||||
name = var.domain
|
name = var.domain
|
||||||
}
|
}
|
||||||
|
|
||||||
# ─── Droplet ──────────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
data "digitalocean_ssh_key" "main" {
|
|
||||||
name = var.ssh_key_name
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "digitalocean_droplet" "gitea" {
|
|
||||||
name = "gitea"
|
|
||||||
region = var.region
|
|
||||||
size = var.droplet_size
|
|
||||||
image = "ubuntu-24-04-x64"
|
|
||||||
ssh_keys = [data.digitalocean_ssh_key.main.id]
|
|
||||||
|
|
||||||
tags = ["infra", "gitea"]
|
|
||||||
}
|
|
||||||
|
|
||||||
# ─── Firewall ─────────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
# Cloudflare IPv4 ranges — http://www.cloudflare.com/ips-v4
|
|
||||||
locals {
|
|
||||||
cloudflare_ipv4 = [
|
|
||||||
"173.245.48.0/20",
|
|
||||||
"103.21.244.0/22",
|
|
||||||
"103.22.200.0/22",
|
|
||||||
"103.31.4.0/22",
|
|
||||||
"141.101.64.0/18",
|
|
||||||
"108.162.192.0/18",
|
|
||||||
"190.93.240.0/20",
|
|
||||||
"188.114.96.0/20",
|
|
||||||
"197.234.240.0/22",
|
|
||||||
"198.41.128.0/17",
|
|
||||||
"162.158.0.0/15",
|
|
||||||
"104.16.0.0/13",
|
|
||||||
"104.24.0.0/14",
|
|
||||||
"172.64.0.0/13",
|
|
||||||
"131.0.72.0/22",
|
|
||||||
]
|
|
||||||
cloudflare_ipv6 = [
|
|
||||||
"2400:cb00::/32",
|
|
||||||
"2606:4700::/32",
|
|
||||||
"2803:f800::/32",
|
|
||||||
"2405:b500::/32",
|
|
||||||
"2405:8100::/32",
|
|
||||||
"2a06:98c0::/29",
|
|
||||||
"2c0f:f248::/32",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "digitalocean_firewall" "gitea" {
|
|
||||||
name = "gitea-firewall"
|
|
||||||
droplet_ids = [digitalocean_droplet.gitea.id]
|
|
||||||
|
|
||||||
# SSH — your IP only
|
|
||||||
inbound_rule {
|
|
||||||
protocol = "tcp"
|
|
||||||
port_range = "22"
|
|
||||||
source_addresses = ["${var.admin_ip}/32"]
|
|
||||||
}
|
|
||||||
|
|
||||||
# HTTP — Cloudflare IPs only (web UI)
|
|
||||||
inbound_rule {
|
|
||||||
protocol = "tcp"
|
|
||||||
port_range = "80"
|
|
||||||
source_addresses = concat(local.cloudflare_ipv4, local.cloudflare_ipv6)
|
|
||||||
}
|
|
||||||
|
|
||||||
# HTTPS — Cloudflare IPs for proxied domains + all IPs for registry (DNS-only)
|
|
||||||
inbound_rule {
|
|
||||||
protocol = "tcp"
|
|
||||||
port_range = "443"
|
|
||||||
source_addresses = ["0.0.0.0/0", "::/0"]
|
|
||||||
}
|
|
||||||
|
|
||||||
# Gitea SSH for git push/pull — open until Gitea is migrated to DOKS
|
|
||||||
inbound_rule {
|
|
||||||
protocol = "tcp"
|
|
||||||
port_range = "2222"
|
|
||||||
source_addresses = ["0.0.0.0/0", "::/0"]
|
|
||||||
}
|
|
||||||
|
|
||||||
outbound_rule {
|
|
||||||
protocol = "tcp"
|
|
||||||
port_range = "1-65535"
|
|
||||||
destination_addresses = ["0.0.0.0/0", "::/0"]
|
|
||||||
}
|
|
||||||
|
|
||||||
outbound_rule {
|
|
||||||
protocol = "udp"
|
|
||||||
port_range = "1-65535"
|
|
||||||
destination_addresses = ["0.0.0.0/0", "::/0"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# ─── DNS records ──────────────────────────────────────────────────────────────
|
# ─── DNS records ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
# Proxied through Cloudflare — web UI
|
||||||
resource "cloudflare_record" "gitea" {
|
resource "cloudflare_record" "gitea" {
|
||||||
zone_id = data.cloudflare_zone.main.id
|
zone_id = data.cloudflare_zone.main.id
|
||||||
name = "git"
|
name = "git"
|
||||||
type = "A"
|
type = "A"
|
||||||
content = digitalocean_droplet.gitea.ipv4_address
|
content = var.cluster_lb_ip
|
||||||
proxied = true
|
proxied = false
|
||||||
ttl = 1
|
ttl = 3600
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "cloudflare_record" "vaultwarden" {
|
# DNS only — no Cloudflare proxy, for SSH git access
|
||||||
zone_id = data.cloudflare_zone.main.id
|
|
||||||
name = "vault"
|
|
||||||
type = "A"
|
|
||||||
content = digitalocean_droplet.gitea.ipv4_address
|
|
||||||
proxied = true
|
|
||||||
ttl = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# DNS only — no Cloudflare proxy, for direct SSH/git access
|
|
||||||
resource "cloudflare_record" "git_ssh" {
|
resource "cloudflare_record" "git_ssh" {
|
||||||
zone_id = data.cloudflare_zone.main.id
|
zone_id = data.cloudflare_zone.main.id
|
||||||
name = "git-ssh"
|
name = "git-ssh"
|
||||||
type = "A"
|
type = "A"
|
||||||
content = digitalocean_droplet.gitea.ipv4_address
|
content = var.cluster_lb_ip
|
||||||
proxied = false
|
|
||||||
ttl = 3600
|
|
||||||
}
|
|
||||||
|
|
||||||
# DNS only — no Cloudflare proxy, for container registry (no 100MB upload limit)
|
|
||||||
resource "cloudflare_record" "registry" {
|
|
||||||
zone_id = data.cloudflare_zone.main.id
|
|
||||||
name = "registry"
|
|
||||||
type = "A"
|
|
||||||
content = digitalocean_droplet.gitea.ipv4_address
|
|
||||||
proxied = false
|
proxied = false
|
||||||
ttl = 3600
|
ttl = 3600
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
output "gitea_ip" {
|
|
||||||
description = "Public IP of the Gitea droplet"
|
|
||||||
value = digitalocean_droplet.gitea.ipv4_address
|
|
||||||
}
|
|
||||||
|
|
||||||
output "k8s_cluster_id" {
|
output "k8s_cluster_id" {
|
||||||
description = "DOKS cluster ID"
|
description = "DOKS cluster ID"
|
||||||
value = digitalocean_kubernetes_cluster.main.id
|
value = digitalocean_kubernetes_cluster.main.id
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ data "digitalocean_project" "main" {
|
|||||||
resource "digitalocean_project_resources" "main" {
|
resource "digitalocean_project_resources" "main" {
|
||||||
project = data.digitalocean_project.main.id
|
project = data.digitalocean_project.main.id
|
||||||
resources = [
|
resources = [
|
||||||
digitalocean_droplet.gitea.urn,
|
|
||||||
digitalocean_kubernetes_cluster.main.urn,
|
digitalocean_kubernetes_cluster.main.urn,
|
||||||
digitalocean_database_cluster.postgres.urn,
|
digitalocean_database_cluster.postgres.urn,
|
||||||
digitalocean_database_cluster.redis.urn,
|
digitalocean_database_cluster.redis.urn,
|
||||||
|
|||||||
@@ -46,22 +46,22 @@ variable "k8s_version" {
|
|||||||
default = "1.32.13-do.2"
|
default = "1.32.13-do.2"
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "k8s_node_size" {
|
variable "k8s_system_node_size" {
|
||||||
description = "Node pool droplet size"
|
description = "System node pool droplet size (infra workloads)"
|
||||||
type = string
|
type = string
|
||||||
default = "s-2vcpu-4gb"
|
default = "s-2vcpu-4gb"
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "k8s_min_nodes" {
|
variable "k8s_customer_node_size" {
|
||||||
description = "Minimum nodes in the pool"
|
description = "Customer node pool droplet size (app instances)"
|
||||||
type = number
|
type = string
|
||||||
default = 1
|
default = "s-1vcpu-2gb"
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "k8s_max_nodes" {
|
variable "k8s_max_customer_nodes" {
|
||||||
description = "Maximum nodes in the pool"
|
description = "Maximum nodes in the customer pool"
|
||||||
type = number
|
type = number
|
||||||
default = 3
|
default = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "cluster_lb_ip" {
|
variable "cluster_lb_ip" {
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ resource "cloudflare_ruleset" "admin_ip_allowlist" {
|
|||||||
expression = <<-EOT
|
expression = <<-EOT
|
||||||
(
|
(
|
||||||
http.host in {
|
http.host in {
|
||||||
"git.${var.domain}"
|
|
||||||
"vault.${var.domain}"
|
"vault.${var.domain}"
|
||||||
"argocd.${var.domain}"
|
"argocd.${var.domain}"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user