Before you start
Collect three things from the person who deploys today:- The tools they have installed:
aws,docker,jq, a language runtime for the scripts. - The commands, in order, including the login.
- The inputs: every environment variable or prompt, which ones are secret, which ones differ per client or environment, and where each value comes from.
1
Define the environment
Write a Dockerfile that installs the tools. Start from the vendor’s CLI
image when there is one:Pin versions. The whole point is that the deployment behaves the same on
every machine, and “latest” defeats that. More patterns are in
Environment images.
deploy/aws.Dockerfile
Images whose
ENTRYPOINT is the CLI itself (as amazon/aws-cli is)
need ENTRYPOINT [] so Keel can run a shell in them.2
Write the steps
Keep the steps short and keep the logic in scripts that live in the
repository. Make the login the first step.
keel.yaml
aws sts get-caller-identity at the end of the login step fails fast
with a clear message when the credentials are wrong, before anything is
built.3
Declare the variables
One declaration per input. Give each a type, mark the secrets, and write
the text a client will read.A few decisions worth making deliberately:
keel.yaml
- Use
selectfor anything with a fixed set of values. A region typo is a wasted run; a dropdown is not. - Give safe defaults to tuning values so the form is short for the common case.
- Put the format in
validation. The form shows it as a hint, the manifest renders it, and Keel enforces it. - Add a
manifestblock to every value a client must supply, and leave it off internal switches.
4
Add outputs
If the deployment produces something people ask for afterwards, export
it and declare it:
keel.yaml
5
Validate and try it
6
Hand it over
Export the manifest and send it to whoever supplies the real values:Commit
keel.yaml and deploy/. From now on the deployment is code:
reviewed in pull requests, versioned with the application, and runnable by
anyone with a browser.Practices that hold up
- Idempotent steps. A re-run after a failure should converge, not duplicate. Most cloud CLIs are idempotent by nature; scripts that create resources should check first.
- Print progress, not secrets. Secret values are masked in logs, but
derived values (a URL that embeds a token) are not unless they contain the
secret verbatim. Do not
echocredentials. - One deployment per operation. A
database-migratedeployment next toaws-productionis clearer than aRUN_MIGRATIONSboolean, unless the operations genuinely share a procedure — then a deploy-timeselectis the right tool. - Test the environment image in CI. A failing
docker buildis a failing deploy; a quickdocker build -f deploy/aws.Dockerfile .in CI catches broken package pins early.