Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/auto-tag.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ name: Auto-tag patch release
on:
push:
branches: [main]
# Trigger on changes that affect the built lantern-box binary only.
# deploy/packer/** intentionally NOT in this list: under Reflog's
# Option B, packer changes don't produce a new .deb, so they don't
# need a version bump. build-images.yaml self-triggers on those.
paths:
- '**.go'
- 'go.mod'
- 'go.sum'
- 'Dockerfile'
- 'Dockerfile.goreleaser'
- 'cmd/release/*.service'
- 'deploy/packer/**'

permissions:
contents: write
Expand Down
74 changes: 54 additions & 20 deletions .github/workflows/build-images.yaml
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
name: Build Packer Images

on:
# Run after a release is published
release:
types: [published]
# Packer image contents changed — rebuild. Under Reflog's Option B the
# lantern-box binary no longer lives in the image, so a plain Go release
# doesn't require an image rebuild. This trigger fires only when
# something in the image itself actually changed (provision.sh,
# cloud-init scripts, packer HCL, otel config, the workflow itself).
push:
branches: [main]
paths:
- 'deploy/packer/**'
- '.github/workflows/build-images.yaml'

# Allow manual trigger for testing
# Allow manual trigger for ad-hoc rebuilds (base-image updates, etc.)
workflow_dispatch:
inputs:
version:
description: "lantern-box version to bake into the image (e.g. 1.2.3)"
required: true
description: "Label to apply to the built image (e.g. 1.2.3 — used only for image naming; the lantern-box binary comes from cloud-init at boot time)"
required: false
type: string
builders:
description: "Comma-separated builders (linode,oracle-oci,alicloud-ecs)"
Expand All @@ -31,33 +38,60 @@ jobs:
version: ${{ steps.version.outputs.version }}
matrix: ${{ steps.matrix.outputs.matrix }}
steps:
- name: Checkout (full history — needed to find the latest tag)
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Determine version
id: version
env:
EVENT_NAME: ${{ github.event_name }}
INPUT_VERSION: ${{ inputs.version }}
REF_NAME: ${{ github.ref_name }}
# github.event.inputs.version resolves on every event type
# (including push, where it's simply empty). Plain
# `inputs.version` is only defined for workflow_dispatch /
# workflow_call — using it on a push trigger risks a stricter
# evaluator rejecting the expression before the shell script
# even runs.
INPUT_VERSION: ${{ github.event.inputs.version }}
run: |
Comment thread
myleshorton marked this conversation as resolved.
if [ "$EVENT_NAME" = "release" ]; then
echo "version=${REF_NAME#v}" >> "$GITHUB_OUTPUT"
else
if [[ "$INPUT_VERSION" == v* ]]; then
echo "::error::Version should not start with 'v' (got '$INPUT_VERSION'). Use e.g. 1.2.3"
exit 1
fi
echo "version=$INPUT_VERSION" >> "$GITHUB_OUTPUT"
fi
case "$EVENT_NAME" in
workflow_dispatch)
if [ -z "$INPUT_VERSION" ]; then
# Operator didn't specify — fall through to "latest tag" path.
:
elif [[ "$INPUT_VERSION" == v* ]]; then
echo "::error::Version should not start with 'v' (got '$INPUT_VERSION'). Use e.g. 1.2.3"
exit 1
else
echo "version=$INPUT_VERSION" >> "$GITHUB_OUTPUT"
exit 0
fi
;;
esac
# push or workflow_dispatch without version: label the image with
# the latest tag on main. The image itself is version-agnostic
# under Option B — this is purely for image-name bookkeeping and
# the per-provider latestImage() helpers that filter on prefix.
latest=$(git tag -l 'v*' --sort=-v:refname | head -1)
latest="${latest:-v0.0.0}"
echo "version=${latest#v}" >> "$GITHUB_OUTPUT"

- name: Build matrix
id: matrix
env:
EVENT_NAME: ${{ github.event_name }}
INPUT_BUILDERS: ${{ inputs.builders }}
# See note on INPUT_VERSION above — same reasoning for using
# github.event.inputs rather than bare inputs so push events
# don't choke on an undefined context.
INPUT_BUILDERS: ${{ github.event.inputs.builders }}
run: |
if [ "$EVENT_NAME" = "release" ]; then
if [ "$EVENT_NAME" = "push" ]; then
builders="linode,oracle-oci,alicloud-ecs"
else
elif [ "$EVENT_NAME" = "workflow_dispatch" ] && [ -n "$INPUT_BUILDERS" ]; then
builders="$INPUT_BUILDERS"
else
builders="linode,oracle-oci,alicloud-ecs"
fi
# Validate that we have at least one builder
if [ -z "$builders" ]; then
Expand Down
13 changes: 6 additions & 7 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,9 @@ jobs:
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
FURY_TOKEN: ${{ secrets.FURY_TOKEN }}

- name: Trigger Packer image builds
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Strip 'v' prefix for the version input
version="${GITHUB_REF_NAME#v}"
gh workflow run build-images.yaml -f "version=$version"
# Under Reflog's Option B the packer image no longer bakes in a
# specific lantern-box version — cloud-init installs the target
# tag on first boot, and the central-orchestration hot-swap
# worker pulls existing boxes forward. So a Go release no longer
# needs a packer image rebuild. build-images.yaml self-triggers
# on deploy/packer/** changes and on manual workflow_dispatch.
27 changes: 24 additions & 3 deletions deploy/packer/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,34 @@
# Packer Images for lantern-box

Pre-baked VM images with lantern-box installed. Boot-to-proxy-ready in ~35-60 seconds (vs 2-4 minutes with a stock image).
Pre-baked VM images with runtime dependencies, systemd drop-ins, and
sidecars (otelcol-contrib, Tailscale) already present. The
`lantern-box` binary itself is **not** baked in — cloud-init apt-installs
it on first boot (Reflog's Option B; see the "Not in the image" section
below). Boot-to-proxy-ready is still fast because the heavy work
(package install, otel config, CA cert, user setup) is done at image
build time; only the small apt-install step runs on first boot.

## What's in the image

- Ubuntu 24.04 LTS
- Runtime deps: ca-certificates, tzdata, nftables, wireguard-tools
- lantern-box binary (from Gemfury .deb)
- systemd service (installed but not enabled — cloud-init starts it)
- otelcol-contrib + systemd drop-in for host metrics
- systemd drop-ins for lantern-box env (OTel, etc.)
- `/etc/lantern-box/` and `/var/lib/lantern-box/` directories

**Not in the image (Reflog's Option B):** the `lantern-box` binary itself.
Under the central-orchestration design in
`lantern-cloud/docs/design/central-vps-updates.md`, cloud-init
apt-installs the target release tag on first boot — decoupling release
cadence (frequent) from base-image cadence (rare). The packer image is
now version-agnostic; only base-image changes (Ubuntu patches, systemd
drop-in updates, new sidecars) need a rebuild.
Comment thread
myleshorton marked this conversation as resolved.

**Operators:** before rolling out a new image built from this code,
ensure `bandit_vps_default_release_tag` (or a per-track override) is set
in the lantern-cloud settings. Otherwise new VMs boot without lantern-box
installed and the provision worker's `systemctl enable --now lantern-box`
call will fail.

## Prerequisites

Expand Down
Loading