190 lines
6.2 KiB
HCL
190 lines
6.2 KiB
HCL
terraform {
|
|
required_providers {
|
|
docker = {
|
|
source = "kreuzwerker/docker"
|
|
version = "~> 3.9"
|
|
}
|
|
}
|
|
}
|
|
|
|
locals {
|
|
persistent = var.environment == "prod"
|
|
|
|
# Inject oauth2 token into git URL for private repos
|
|
git_repo_url = (
|
|
var.openresty_git_token != ""
|
|
? replace(var.openresty_git_repo, "://", "://oauth2:${var.openresty_git_token}@")
|
|
: var.openresty_git_repo
|
|
)
|
|
|
|
# Entrypoint for git_clone mode: installs git via apk, clones the pinned ref,
|
|
# then hands off to openresty. The cloned repo must have an 'openresty/' subdirectory
|
|
# containing a valid nginx.conf (used as the -p prefix path).
|
|
git_clone_entrypoint = [
|
|
"/bin/sh", "-c",
|
|
"apk add --no-cache git && git clone --depth 1 --branch '${var.openresty_git_ref}' '${local.git_repo_url}' /tmp/app && exec openresty -g 'daemon off;' -p /tmp/app/openresty"
|
|
]
|
|
}
|
|
|
|
# ─── Network ──────────────────────────────────────────────────────────────────
|
|
# Each app gets its own isolated bridge network. Postgres and Redis are not
|
|
# exposed externally; only OpenResty has a published port.
|
|
|
|
resource "docker_network" "app" {
|
|
name = "${var.app_name}-network"
|
|
driver = "bridge"
|
|
}
|
|
|
|
# ─── Volumes (prod only) ──────────────────────────────────────────────────────
|
|
# In dev mode containers are ephemeral; volumes are created only for prod.
|
|
|
|
resource "docker_volume" "postgres" {
|
|
count = local.persistent ? 1 : 0
|
|
name = "${var.app_name}-postgres-data"
|
|
}
|
|
|
|
resource "docker_volume" "redis" {
|
|
count = local.persistent ? 1 : 0
|
|
name = "${var.app_name}-redis-data"
|
|
}
|
|
|
|
# ─── Images ───────────────────────────────────────────────────────────────────
|
|
|
|
# Standard OpenResty image — used for bind_mount and git_clone modes.
|
|
resource "docker_image" "openresty" {
|
|
count = var.openresty_source_type != "local_build" ? 1 : 0
|
|
name = var.openresty_image
|
|
keep_locally = true
|
|
}
|
|
|
|
# Custom-built OpenResty image — used for local_build mode.
|
|
# The build context is transferred from the local machine to the remote Docker
|
|
# daemon over SSH and built there. Rebuilds are triggered by changes to any
|
|
# file in the context directory.
|
|
resource "docker_image" "openresty_custom" {
|
|
count = var.openresty_source_type == "local_build" ? 1 : 0
|
|
name = "${var.app_name}-openresty:latest"
|
|
keep_locally = true
|
|
|
|
build {
|
|
context = var.openresty_local_build_context
|
|
dockerfile = var.openresty_dockerfile
|
|
}
|
|
|
|
triggers = {
|
|
# Rebuild when any file in the build context changes.
|
|
context_hash = sha1(join("", [
|
|
for f in sort(fileset(var.openresty_local_build_context, "**/*")) :
|
|
filesha1("${var.openresty_local_build_context}/${f}")
|
|
]))
|
|
}
|
|
}
|
|
|
|
resource "docker_image" "postgres" {
|
|
name = var.postgres_image
|
|
keep_locally = true
|
|
}
|
|
|
|
resource "docker_image" "redis" {
|
|
name = var.redis_image
|
|
keep_locally = true
|
|
}
|
|
|
|
# ─── PostgreSQL ───────────────────────────────────────────────────────────────
|
|
|
|
resource "docker_container" "postgres" {
|
|
image = docker_image.postgres.image_id
|
|
name = "${var.app_name}-postgres"
|
|
restart = "unless-stopped"
|
|
|
|
networks_advanced {
|
|
name = docker_network.app.name
|
|
}
|
|
|
|
env = [
|
|
"POSTGRES_DB=${var.db_name}",
|
|
"POSTGRES_USER=${var.db_user}",
|
|
"POSTGRES_PASSWORD=${var.db_password}",
|
|
]
|
|
|
|
dynamic "volumes" {
|
|
for_each = local.persistent ? [1] : []
|
|
content {
|
|
volume_name = docker_volume.postgres[0].name
|
|
container_path = "/var/lib/postgresql/data"
|
|
}
|
|
}
|
|
}
|
|
|
|
# ─── Redis ────────────────────────────────────────────────────────────────────
|
|
|
|
resource "docker_container" "redis" {
|
|
image = docker_image.redis.image_id
|
|
name = "${var.app_name}-redis"
|
|
restart = "unless-stopped"
|
|
|
|
networks_advanced {
|
|
name = docker_network.app.name
|
|
}
|
|
|
|
dynamic "volumes" {
|
|
for_each = local.persistent ? [1] : []
|
|
content {
|
|
volume_name = docker_volume.redis[0].name
|
|
container_path = "/data"
|
|
}
|
|
}
|
|
}
|
|
|
|
# ─── OpenResty ────────────────────────────────────────────────────────────────
|
|
|
|
resource "docker_container" "openresty" {
|
|
image = (
|
|
var.openresty_source_type == "local_build"
|
|
? docker_image.openresty_custom[0].image_id
|
|
: docker_image.openresty[0].image_id
|
|
)
|
|
name = "${var.app_name}-openresty"
|
|
restart = "unless-stopped"
|
|
|
|
networks_advanced {
|
|
name = docker_network.app.name
|
|
}
|
|
|
|
ports {
|
|
internal = 80
|
|
external = var.openresty_external_port
|
|
}
|
|
|
|
# bind_mount: mount a pre-existing directory from the remote host.
|
|
# The directory must contain a valid nginx.conf and any Lua files.
|
|
dynamic "volumes" {
|
|
for_each = var.openresty_source_type == "bind_mount" ? [1] : []
|
|
content {
|
|
host_path = var.openresty_remote_config_path
|
|
container_path = "/usr/local/openresty/nginx/conf"
|
|
read_only = true
|
|
}
|
|
}
|
|
|
|
# git_clone: override the container entrypoint to clone the repo and start openresty.
|
|
# The base image must support apk (Alpine). The cloned repo must have an openresty/
|
|
# subdirectory with nginx.conf.
|
|
entrypoint = var.openresty_source_type == "git_clone" ? local.git_clone_entrypoint : null
|
|
|
|
# Expose service connection info as env vars so Lua code can use them via os.getenv().
|
|
env = [
|
|
"APP_NAME=${var.app_name}",
|
|
"POSTGRES_HOST=${var.app_name}-postgres",
|
|
"POSTGRES_DB=${var.db_name}",
|
|
"POSTGRES_USER=${var.db_user}",
|
|
"POSTGRES_PASSWORD=${var.db_password}",
|
|
"REDIS_HOST=${var.app_name}-redis",
|
|
]
|
|
|
|
depends_on = [
|
|
docker_container.postgres,
|
|
docker_container.redis,
|
|
]
|
|
}
|