Use a channel to deliver your application, infrastructure and scripts to the cloud.
A channel delivers your application to development, test and production targets. Conceptually a channel is similar to the deploy/release portion of a pipeline.
The recommended naming convention for channels is
<repository>-<branch> (Example: munchii.com-master
)
A standard unit for delivering an application. It is typically produced as an output of a build process and may include infrastructure code, configuration and scripts.
A destination like AWS, Azure, Google Cloud, an app store or even a database (for backfills and database
upgrade scripts). A target unpacks a release
and invokes the main script or executable in an ubuntu
Docker Image.
A directed graph that expresses dependencies between targets.
You can follow these steps to create a channel named HelloWorld
and release to a target
named test
.
Note: The curl
commands must be executed with an authorization header (not shown).
Create a channel
curl -X PUT \
-H "Content-Type: application/json" \
-d '{ "data": { "name": "HelloWorld" } }' \
https://api.munchii.com/channels/HelloWorld
Add a target
curl -X PUT \
-H "Content-Type: application/json" \
-d '{ "data": { "name": "test" } }' \
https://api.munchii.com/channels/HelloWorld/targets/test
Create a release file (typically an output of your build process)
cat << EOF > /var/tmp/main
#!/bin/sh
echo "Hello World!"
EOF
chmod +x /var/tmp/main
tar --create --gzip --file /var/tmp/helloWorld.tar.gz \
--directory /var/tmp main
Start a release
curl -X GET --silent --show-error \
https://api.munchii.com/channels/HelloWorld/releases/tail \
| jq --raw-output ".links.put" \
| xargs curl -X PUT \
--upload-file /var/tmp/helloWorld.tar.gz
View the release log
curl -X GET \
https://api.munchii.com/channels/HelloWorld/targets/test/logs
Next steps:
Cleanup (Optional):
Delete target
curl -X GET --include --silent --show-error \
https://api.munchii.com/channels/HelloWorld/targets/test \
| sed -n "s/ETag/If-Match/ip" \
| tr -d "\r" \
| xargs --delimiter "\n" -I '{}' curl -X DELETE -H '{}' \
https://api.munchii.com/channels/HelloWorld/targets/test
Delete channel
curl -X GET --include --silent --show-error \
https://api.munchii.com/channels/HelloWorld \
| sed -n "s/ETag/If-Match/ip" \
| tr -d "\r" \
| xargs --delimiter "\n" -I '{}' curl -X DELETE -H '{}' \
https://api.munchii.com/channels/HelloWorld
A channel behaves like a queue that accepts and delivers releases to targets. By default targets are scheduled sequentially in the order they were added to a channel. Targets can be reordered and more complex dependencies can be expressed as a directed graph (referred to as a topology). Releases always occur one-by-one and in-order for any given target - even if targets are reordered.
The release file format is designed to be simple and flexible. A minimal release file is a tar.gz with an
executable main
(script or binary). The main
script or binary is freeform.
For example: you can write a script that uses the AWS CLI, the Serverless Framework or execute your own
compiled program.
The tar.gz file may include other artifacts like templates, scripts, config and data. The entire tar.gz will
be unpacked and available alongside the main
script or executable. For example: you might include
a compiled ZIP file for your application to deploy to AWS Lambda.
Reserved: release.yaml
in the tar.gz is reserved for future use (like specifying a Docker
image or different main script or executable name).
You can develop and test release files locally. You can test a release file in a Docker container like:
docker run --mount type=bind,src=`pwd`/task,dst=/var/task \
--env CHANNEL_NAME=HelloWorld \
--env TARGET_NAME=local \
--env RELEASE_ORDINAL=1 \
--workdir /var/task ubuntu /var/task/main
Note: This command assumes `pwd`/task
exists and contains an executable main
.
Best Practice: Don't store secrets in source code and don't test a release file against a production target.
If you choose to use a main
script in your release file, these patterns may be helpful:
Load Configuration
Source target-specific environment variables/configuration that are needed by the release process.
. configuration/$TARGET_NAME
Reduce Log Verbosity
Buffers the stdout and stderr output of a command to a file and only display the output if the command fails. We like to use this for commands that set up the release environment - like installing new packages.
suppress () {
/bin/rm --force /tmp/suppress.out 2> /dev/null;
${1+"$@"} > /tmp/suppress.out 2>&1 || cat /tmp/suppress.out;
/bin/rm /tmp/suppress.out;
}
Credit: https://serverfault.com/a/607903
Organize into Smaller Scripts
Version sort and execute scripts. We like to use this to organize releases into phases
like 1_setup
, 2_install
, 3_test
and 4_cleanup.
COMMANDS=$(find "smaller-scripts" -type f -print | sort -V)
for COMMAND in $COMMANDS
do
. $COMMAND
done
Secrets (like AWS credentials) can be added to a target. Secrets are encrypted and stored at rest using one AES 256 key per target. Secrets cannot be retrieved programtically, but they are decrypted and made available as environment variables for a release.
Best Practice: Rotate secrets periodically. Any time a secret is created, updated or deleted, the AES 256 encryption key for the affected target is rotated.
The following environment variables are available (in addition to secrets) and may be useful for conditional release logic or configuring an application:
A simple way to manually approve changes between targets (e.g. between a test and production environment) is to model each target as a separate source code branch and create a corresponding channel for each source code branch. This is similar to Gitflow Workflows.
Caution: Running a build process at different times for an identical commit may not produce an identical release file. Dependencies are a common example of input to a build process that may change over time. If you prefer to promote an identical release file between targets, skip creating separate source code branches and, instead, release the same release file to the next channel and target after manually verifying the prior channel and target.