A Terraform provider for Dokploy
Plugin-framework provider covering projects, environments, applications, Compose stacks, managed databases, domains, mounts, ports, redirects, basic auth, registries, SSH keys, certificates and backup destinations, over Dokploy's tRPC-over-REST API. The shim package exposes the provider to other Go modules, which is how pulumi-dokploy bridges it.
This commit is contained in:
113
modules/web-service/main.tf
Normal file
113
modules/web-service/main.tf
Normal file
@@ -0,0 +1,113 @@
|
||||
terraform {
|
||||
required_version = ">= 1.5"
|
||||
required_providers {
|
||||
dokploy = {
|
||||
source = "maxvojtkov/dokploy"
|
||||
version = ">= 0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
# Exactly one source block is populated, chosen by var.service_source.type.
|
||||
is_docker = var.service_source.type == "docker"
|
||||
is_github = var.service_source.type == "github"
|
||||
is_git = var.service_source.type == "git"
|
||||
}
|
||||
|
||||
resource "dokploy_application" "this" {
|
||||
name = var.name
|
||||
description = var.description
|
||||
environment_id = var.environment_id
|
||||
server_id = var.server_id
|
||||
|
||||
source_type = var.service_source.type
|
||||
|
||||
# Docker image source
|
||||
docker_image = local.is_docker ? var.service_source.image : null
|
||||
username = local.is_docker ? var.service_source.registry_username : null
|
||||
password = local.is_docker ? var.service_source.registry_password : null
|
||||
registry_url = local.is_docker ? var.service_source.registry_url : null
|
||||
|
||||
# GitHub source
|
||||
github_id = local.is_github ? var.service_source.github_id : null
|
||||
owner = local.is_github ? var.service_source.owner : null
|
||||
repository = local.is_github ? var.service_source.repository : null
|
||||
branch = local.is_github ? var.service_source.branch : null
|
||||
build_path = local.is_github ? var.service_source.build_path : null
|
||||
|
||||
# Plain Git source
|
||||
custom_git_url = local.is_git ? var.service_source.url : null
|
||||
custom_git_branch = local.is_git ? var.service_source.branch : null
|
||||
custom_git_build_path = local.is_git ? var.service_source.build_path : null
|
||||
custom_git_ssh_key_id = local.is_git ? var.service_source.ssh_key_id : null
|
||||
|
||||
build_type = var.build_type
|
||||
dockerfile = var.dockerfile
|
||||
|
||||
env = var.env
|
||||
build_args = var.build_args
|
||||
auto_deploy = var.auto_deploy
|
||||
|
||||
replicas = var.replicas
|
||||
memory_reservation = var.resources.memory_reservation
|
||||
memory_limit = var.resources.memory_limit
|
||||
cpu_reservation = var.resources.cpu_reservation
|
||||
cpu_limit = var.resources.cpu_limit
|
||||
}
|
||||
|
||||
resource "dokploy_domain" "this" {
|
||||
for_each = { for domain in var.domains : domain.host => domain }
|
||||
|
||||
application_id = dokploy_application.this.id
|
||||
domain_type = "application"
|
||||
host = each.value.host
|
||||
path = each.value.path
|
||||
port = each.value.port
|
||||
https = each.value.https
|
||||
certificate_type = each.value.https ? each.value.certificate_type : "none"
|
||||
strip_path = each.value.strip_path
|
||||
internal_path = each.value.internal_path
|
||||
}
|
||||
|
||||
resource "dokploy_port" "this" {
|
||||
for_each = { for port in var.published_ports : "${port.protocol}-${port.published_port}" => port }
|
||||
|
||||
application_id = dokploy_application.this.id
|
||||
published_port = each.value.published_port
|
||||
target_port = each.value.target_port
|
||||
protocol = each.value.protocol
|
||||
publish_mode = each.value.publish_mode
|
||||
}
|
||||
|
||||
resource "dokploy_mount" "this" {
|
||||
for_each = { for mount in var.mounts : mount.mount_path => mount }
|
||||
|
||||
service_id = dokploy_application.this.id
|
||||
service_type = "application"
|
||||
type = each.value.type
|
||||
mount_path = each.value.mount_path
|
||||
volume_name = each.value.volume_name
|
||||
host_path = each.value.host_path
|
||||
file_path = each.value.file_path
|
||||
content = each.value.content
|
||||
}
|
||||
|
||||
# count rather than for_each: basic_auth is sensitive, and Terraform refuses to
|
||||
# derive resource instance keys from sensitive values.
|
||||
resource "dokploy_security" "this" {
|
||||
count = var.basic_auth == null ? 0 : 1
|
||||
|
||||
application_id = dokploy_application.this.id
|
||||
username = var.basic_auth.username
|
||||
password = var.basic_auth.password
|
||||
}
|
||||
|
||||
resource "dokploy_redirect" "this" {
|
||||
for_each = { for redirect in var.redirects : redirect.regex => redirect }
|
||||
|
||||
application_id = dokploy_application.this.id
|
||||
regex = each.value.regex
|
||||
replacement = each.value.replacement
|
||||
permanent = each.value.permanent
|
||||
}
|
||||
29
modules/web-service/outputs.tf
Normal file
29
modules/web-service/outputs.tf
Normal file
@@ -0,0 +1,29 @@
|
||||
output "id" {
|
||||
description = "Application identifier."
|
||||
value = dokploy_application.this.id
|
||||
}
|
||||
|
||||
output "app_name" {
|
||||
description = "Docker service name Dokploy assigned to the application."
|
||||
value = dokploy_application.this.app_name
|
||||
}
|
||||
|
||||
output "status" {
|
||||
description = "Current application status reported by Dokploy."
|
||||
value = dokploy_application.this.application_status
|
||||
}
|
||||
|
||||
output "domain_ids" {
|
||||
description = "Domain identifiers keyed by hostname."
|
||||
value = { for host, domain in dokploy_domain.this : host => domain.id }
|
||||
}
|
||||
|
||||
output "urls" {
|
||||
description = "Public URLs the service is reachable on."
|
||||
value = [for domain in var.domains : "${domain.https ? "https" : "http"}://${domain.host}${domain.path}"]
|
||||
}
|
||||
|
||||
output "mount_ids" {
|
||||
description = "Mount identifiers keyed by container path."
|
||||
value = { for path, mount in dokploy_mount.this : path => mount.id }
|
||||
}
|
||||
186
modules/web-service/variables.tf
Normal file
186
modules/web-service/variables.tf
Normal file
@@ -0,0 +1,186 @@
|
||||
variable "name" {
|
||||
description = "Display name of the application."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "description" {
|
||||
description = "Free-form description shown in the Dokploy UI."
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "environment_id" {
|
||||
description = "Environment the service belongs to. Usually dokploy_project.<x>.default_environment_id."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "server_id" {
|
||||
description = "Remote server to deploy on. Leave null to use the Dokploy host itself."
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "service_source" {
|
||||
description = <<-DESC
|
||||
Where the service comes from. Set `type` to one of `docker`, `github` or `git`
|
||||
and populate the matching fields; the rest are ignored.
|
||||
DESC
|
||||
type = object({
|
||||
type = string
|
||||
|
||||
# type = "docker"
|
||||
image = optional(string)
|
||||
registry_username = optional(string)
|
||||
registry_password = optional(string)
|
||||
registry_url = optional(string)
|
||||
|
||||
# type = "github"
|
||||
github_id = optional(string)
|
||||
owner = optional(string)
|
||||
repository = optional(string)
|
||||
|
||||
# type = "git"
|
||||
url = optional(string)
|
||||
ssh_key_id = optional(string)
|
||||
|
||||
# shared by the git-backed types
|
||||
branch = optional(string)
|
||||
build_path = optional(string)
|
||||
})
|
||||
|
||||
validation {
|
||||
condition = contains(["docker", "github", "git"], var.service_source.type)
|
||||
error_message = "service_source.type must be one of: docker, github, git."
|
||||
}
|
||||
|
||||
validation {
|
||||
condition = var.service_source.type != "docker" || var.service_source.image != null
|
||||
error_message = "service_source.image is required when source.type is \"docker\"."
|
||||
}
|
||||
|
||||
validation {
|
||||
condition = var.service_source.type != "github" || (
|
||||
var.service_source.owner != null && var.service_source.repository != null && var.service_source.branch != null
|
||||
)
|
||||
error_message = "service_source.owner, source.repository and source.branch are required when source.type is \"github\"."
|
||||
}
|
||||
|
||||
validation {
|
||||
condition = var.service_source.type != "git" || (var.service_source.url != null && var.service_source.branch != null)
|
||||
error_message = "service_source.url and source.branch are required when source.type is \"git\"."
|
||||
}
|
||||
}
|
||||
|
||||
variable "build_type" {
|
||||
description = "How the application is built. Ignored when the source is a prebuilt Docker image."
|
||||
type = string
|
||||
default = null
|
||||
|
||||
validation {
|
||||
condition = var.build_type == null || contains(
|
||||
["dockerfile", "heroku_buildpacks", "paketo_buildpacks", "nixpacks", "static", "railpack"],
|
||||
coalesce(var.build_type, "nixpacks")
|
||||
)
|
||||
error_message = "build_type must be one of: dockerfile, heroku_buildpacks, paketo_buildpacks, nixpacks, static, railpack."
|
||||
}
|
||||
}
|
||||
|
||||
variable "dockerfile" {
|
||||
description = "Path to the Dockerfile, when build_type is \"dockerfile\"."
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "env" {
|
||||
description = "Runtime environment variables in KEY=value form, one per line."
|
||||
type = string
|
||||
default = null
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "build_args" {
|
||||
description = "Docker build arguments in KEY=value form, one per line."
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "auto_deploy" {
|
||||
description = "Redeploy automatically when the configured Git trigger fires."
|
||||
type = bool
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "replicas" {
|
||||
description = "Number of replicas to run."
|
||||
type = number
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "resources" {
|
||||
description = "Container resource reservations and limits, as Docker-style strings such as \"512m\" or \"1.5\"."
|
||||
type = object({
|
||||
memory_reservation = optional(string)
|
||||
memory_limit = optional(string)
|
||||
cpu_reservation = optional(string)
|
||||
cpu_limit = optional(string)
|
||||
})
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "domains" {
|
||||
description = "Domains routed to this service through Traefik."
|
||||
type = list(object({
|
||||
host = string
|
||||
port = optional(number, 3000)
|
||||
path = optional(string, "/")
|
||||
https = optional(bool, true)
|
||||
certificate_type = optional(string, "letsencrypt")
|
||||
strip_path = optional(bool, false)
|
||||
internal_path = optional(string, "/")
|
||||
}))
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "published_ports" {
|
||||
description = "Ports published directly on the host, bypassing Traefik."
|
||||
type = list(object({
|
||||
published_port = number
|
||||
target_port = number
|
||||
protocol = optional(string, "tcp")
|
||||
publish_mode = optional(string, "host")
|
||||
}))
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "mounts" {
|
||||
description = "Volumes, bind mounts and config files attached to the service."
|
||||
type = list(object({
|
||||
mount_path = string
|
||||
type = optional(string, "volume")
|
||||
volume_name = optional(string)
|
||||
host_path = optional(string)
|
||||
file_path = optional(string)
|
||||
content = optional(string)
|
||||
}))
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "basic_auth" {
|
||||
description = "HTTP basic auth credentials protecting the service's domains. Null disables it."
|
||||
type = object({
|
||||
username = string
|
||||
password = string
|
||||
})
|
||||
default = null
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "redirects" {
|
||||
description = "Traefik redirect rules attached to the service."
|
||||
type = list(object({
|
||||
regex = string
|
||||
replacement = string
|
||||
permanent = optional(bool, true)
|
||||
}))
|
||||
default = []
|
||||
}
|
||||
Reference in New Issue
Block a user