Recipes

deploy a service with kamal

The pedantic way – resolve each value by hand and wire them explicitly:

#!/bin/bash
set -euo pipefail

SERVICE="$1"; shift

SERVER_IP=$(confit resolve credentials.server.ip --reveal)
DOCKER_HUB_TOKEN=$(confit resolve credentials.cloud.docker_hub_token --reveal)

confit ssh --key credentials.ssh.deploy -- \
  env SERVER_IP="$SERVER_IP" DOCKER_HUB_TOKEN="$DOCKER_HUB_TOKEN" \
    kamal "$@" -c "config/deploy/${SERVICE}.yml"

Or let confit handle it – ssh loads the key, run injects all cloud credentials as env vars:

#!/bin/bash
set -euo pipefail

SERVICE="$1"; shift

confit ssh --key credentials.ssh.deploy -- \
  confit run credentials.cloud --upper -- \
    kamal "$@" -c "config/deploy/${SERVICE}.yml"

iterate over services

for svc in $(confit keys services); do
  confit log "checking $svc"
  domain=$(confit resolve "services.${svc}.domain")
  port=$(confit resolve "services.${svc}.port")
  echo "$svc -> $domain:$port"
done

source env in a shell script

eval "$(confit show services.web.env --export --upper --reveal)"
echo "BASE_URL is $BASE_URL"

run ansible with ssh-agent

server_ip=$(confit resolve credentials.server.ip --reveal)

confit ssh --key credentials.ssh.admin.private_key -- \
  ansible-playbook playbooks/bootstrap.yml \
    -i "${server_ip}," \
    -u admin

validate vault access

Check that all credentials can be resolved before running a deploy:

confit log "validating vault access..."
confit validate credentials
confit log --ok "all credentials accessible"

use terraform outputs

[providers.tf]
cmd = "terraform -chdir=iac/stages/{stage} output -raw {path}"

[vars]
stage = "dev"

[infra]
server_ip = "tf://server_ip"
db_endpoint = "tf://db_endpoint"
cdn_domain = "tf://cdn_domain"
# Dev (default)
$ confit resolve infra.server_ip
10.0.0.1

# Production
$ confit --set stage=production resolve infra.server_ip
65.108.67.19

multi-environment configs

Use variables to switch between environments without separate config files:

[vars]
stage = "dev"

[providers.op]
cmd = "op read {uri}"

[providers.tf]
cmd = "terraform -chdir=iac/stages/{stage} output -raw {path}"

[vaults]
sites = "myapp-sites-{vars.stage}"

[credentials]
api_key = "secret://op://{vaults.sites}/API_KEY/credential"

[infra]
endpoint = "tf://api_endpoint"
# Dev environment (secret masked)
$ confit resolve credentials.api_key
***

# Production environment (revealed)
$ confit --set stage=production resolve credentials.api_key --reveal
sk-prod-abc123

styled script output

Replace hand-rolled echo coloring with confit log:

#!/bin/bash
set -euo pipefail

confit log "starting deploy for $SERVICE"

if deploy_service "$SERVICE"; then
  confit log --ok "deployed $SERVICE"
else
  confit log --err "failed to deploy $SERVICE"
  exit 1
fi

Output goes to stderr, so it doesn’t interfere with piped data on stdout.