doc: added BYO image for DigitalOcean
tfvalidate / list terraform addon directories (push) Waiting to run
tfvalidate.yml / terraform validate (${{ fromJson(needs.listaddons.outputs.matrix) }}) (push) Blocked by required conditions

This commit is contained in:
Leon Xu
2026-08-07 19:02:34 -07:00
parent 022e74f2f3
commit d21c6a73f1
7 changed files with 144 additions and 25 deletions
+56
View File
@@ -10,6 +10,62 @@ This Terraform project automates the deployment of Fleet Device Management (Flee
* **DNS** — Domain and CNAME record for Fleet
* **Database Firewalls** — Restricts database and cache access to the App Platform app only
## Using Your Own Image
By default, the module deploys the official `fleetdm/fleet` image from Docker Hub. To deploy your own image (e.g., a custom Fleet build), set `image_tag` in `fleet_config` to a full image reference:
### Docker Hub (public)
```hcl
fleet_config = {
image_tag = "your-org/your-fleet:v1.0.0"
# ...
}
```
### Docker Hub (private)
```hcl
fleet_config = {
image_tag = "your-org/your-fleet:v1.0.0"
image_registry_credentials = "your-username:your-access-token" # Don't commit this!
# ...
}
```
Pass the credentials at deploy time instead of committing them:
```bash
terraform apply -var-file="fleet-10.tfvars" \
-var="fleet_config={image_tag:\"your-org/your-fleet:v1.0.0\",image_registry_credentials:\"$DOCKERHUB_USER:$DOCKERHUB_TOKEN\",instance_size_slug:\"basic-xs\",instance_count:1,debug_logging:false,exec_migration:true}"
```
### DigitalOcean Container Registry (DOCR)
Push your image to DOCR first:
```bash
# One-time: create a registry and log in
doctl registry create my-registry
doctl registry login
# Build, tag, and push your image
docker build -t registry.digitalocean.com/my-registry/fleet:v1.0.0 .
docker push registry.digitalocean.com/my-registry/fleet:v1.0.0
```
Then reference it:
```hcl
fleet_config = {
image_tag = "registry.digitalocean.com/my-registry/fleet:v1.0.0"
image_deploy_on_push = true # Optional: redeploy automatically on every push
# ...
}
```
The module detects the registry automatically from the `image_tag` prefix — anything starting with `registry.digitalocean.com/` uses DOCR, everything else uses Docker Hub. The migration job uses the same image.
## Prerequisites
1. **Terraform:** Version `~> 1.11`. Install from [terraform.io](https://www.terraform.io/downloads.html).
+34 -8
View File
@@ -4,6 +4,22 @@ resource "random_password" "private_key" {
}
locals {
# --------------------------------------------------------------------------
# Image parsing — supports Docker Hub and DigitalOcean Container Registry
#
# Accepted formats for var.fleet_config.image_tag:
# "fleetdm/fleet:v4.90.0" → Docker Hub (official)
# "your-org/your-image:v1.0.0" → Docker Hub (custom)
# "registry.digitalocean.com/<registry>/<repo>:tag" → DOCR
# --------------------------------------------------------------------------
image_tag_parts = split(":", var.fleet_config.image_tag)
image_name_part = local.image_tag_parts[0]
image_tag_part = length(local.image_tag_parts) > 1 ? local.image_tag_parts[length(local.image_tag_parts) - 1] : "latest"
image_segments = split("/", local.image_name_part)
image_is_docr = local.image_segments[0] == "registry.digitalocean.com"
image_repository = local.image_segments[length(local.image_segments) - 1]
image_dh_registry = join("/", slice(local.image_segments, 0, length(local.image_segments) - 1))
base_env_vars = {
FLEET_MYSQL_PROTOCOL = "tcp"
FLEET_MYSQL_ADDRESS = "${local.mysql_host}:${local.mysql_port}"
@@ -60,10 +76,19 @@ resource "digitalocean_app" "fleet" {
http_port = 8080
image {
registry_type = "DOCKER_HUB"
registry = "fleetdm"
repository = "fleet"
tag = trimprefix(var.fleet_config.image_tag, "fleetdm/fleet:")
registry_type = local.image_is_docr ? "DOCR" : "DOCKER_HUB"
registry = local.image_is_docr ? null : local.image_dh_registry
repository = local.image_repository
tag = local.image_tag_part
registry_credentials = var.fleet_config.image_registry_credentials
# Auto-deploy on push is only supported for DOCR
dynamic "deploy_on_push" {
for_each = local.image_is_docr && var.fleet_config.image_deploy_on_push ? [1] : []
content {
enabled = true
}
}
}
health_check {
@@ -107,10 +132,11 @@ resource "digitalocean_app" "fleet" {
instance_size_slug = var.fleet_config.instance_size_slug
image {
registry_type = "DOCKER_HUB"
registry = "fleetdm"
repository = "fleet"
tag = trimprefix(var.fleet_config.image_tag, "fleetdm/fleet:")
registry_type = local.image_is_docr ? "DOCR" : "DOCKER_HUB"
registry = local.image_is_docr ? null : local.image_dh_registry
repository = local.image_repository
tag = local.image_tag_part
registry_credentials = var.fleet_config.image_registry_credentials
}
run_command = "fleet prepare db --no-prompt=true"
+10 -8
View File
@@ -24,15 +24,17 @@ variable "vpc_config" {
}
variable "fleet_config" {
description = "Configuration for the Fleet application deployment."
description = "Configuration for the Fleet application deployment. image_tag accepts full image references from Docker Hub or DOCR."
type = object({
image_tag = string
instance_size_slug = string
instance_count = number
license_key = optional(string)
debug_logging = bool
exec_migration = bool
extra_env_vars = optional(map(string))
image_tag = string
image_registry_credentials = optional(string)
image_deploy_on_push = optional(bool, false)
instance_size_slug = string
instance_count = number
license_key = optional(string)
debug_logging = bool
exec_migration = bool
extra_env_vars = optional(map(string))
})
}
+6
View File
@@ -27,7 +27,13 @@
# App Platform — smallest possible instance
# ----------------------------------------------------------------------------
fleet_config = {
# Image — use the official Fleet image or your own:
# Official: "fleetdm/fleet:v4.90.0"
# Custom Docker Hub: "your-org/your-fleet:v1.0.0"
# DigitalOcean DOCR: "registry.digitalocean.com/your-registry/fleet:v1.0.0"
image_tag = "fleetdm/fleet:v4.90.0"
# image_registry_credentials = "your-username:your-token" # private Docker Hub
# image_deploy_on_push = true # DOCR only
instance_size_slug = "basic-xxs" # $5/mo — 512 MiB, 1 shared vCPU
instance_count = 1
debug_logging = false
+12 -1
View File
@@ -27,7 +27,18 @@
# $10/month — plenty for 10 devices
# ----------------------------------------------------------------------------
fleet_config = {
image_tag = "fleetdm/fleet:v4.90.0"
# Image — use the official Fleet image or your own:
# Official: "fleetdm/fleet:v4.90.0"
# Custom Docker Hub: "your-org/your-fleet:v1.0.0"
# DigitalOcean DOCR: "registry.digitalocean.com/your-registry/fleet:v1.0.0"
image_tag = "fleetdm/fleet:v4.90.0"
# For private Docker Hub repos:
# image_registry_credentials = "your-username:your-token"
# For DOCR: auto-deploy when you push a new image
# image_deploy_on_push = true
instance_size_slug = "basic-xs" # 1 GiB RAM, $10/mo
instance_count = 1
debug_logging = false
+6
View File
@@ -20,7 +20,13 @@
# App Platform — same as default, but without Redis env vars
# ----------------------------------------------------------------------------
fleet_config = {
# Image — use the official Fleet image or your own:
# Official: "fleetdm/fleet:v4.90.0"
# Custom Docker Hub: "your-org/your-fleet:v1.0.0"
# DigitalOcean DOCR: "registry.digitalocean.com/your-registry/fleet:v1.0.0"
image_tag = "fleetdm/fleet:v4.90.0"
# image_registry_credentials = "your-username:your-token" # private Docker Hub
# image_deploy_on_push = true # DOCR only
instance_size_slug = "apps-s-1vcpu-1gb" # $12/mo
instance_count = 1
debug_logging = false
+20 -8
View File
@@ -28,15 +28,27 @@ variable "vpc_config" {
}
variable "fleet_config" {
description = "Configuration for the Fleet application deployment on App Platform."
description = <<-EOT
Configuration for the Fleet application deployment on App Platform.
image_tag accepts a full image reference:
- Docker Hub: "fleetdm/fleet:v4.90.0" (default, official image)
- Docker Hub custom: "your-org/your-image:v1.0.0"
- DOCR: "registry.digitalocean.com/your-registry/your-image:v1.0.0"
image_registry_credentials: "username:token" for private Docker Hub repos.
image_deploy_on_push: auto-deploy when a new image is pushed (DOCR only).
EOT
type = object({
image_tag = string
instance_size_slug = string
instance_count = number
license_key = optional(string)
debug_logging = bool
exec_migration = bool
extra_env_vars = optional(map(string))
image_tag = string
image_registry_credentials = optional(string)
image_deploy_on_push = optional(bool, false)
instance_size_slug = string
instance_count = number
license_key = optional(string)
debug_logging = bool
exec_migration = bool
extra_env_vars = optional(map(string))
})
default = {
image_tag = "fleetdm/fleet:v4.90.0"