Awesome
Capitan
Capitan is a tool for managing multiple Docker containers based largely on crowdr
Capitan is only a wrapper around the docker cli tool, no api usage whatsoever (well... an inspect
command here and there).
This means it will basically work with all versions of docker.
$ capitan up
Run arguments changed, doing blue-green redeploy: capitan_redis_green_1
Running capitan_redis_blue_1
cd939956f332391489d0383610d9da2c420595d495934c3221376dbf68854316
Removing old container capitan_redis_green_1...
Already running capitan_mongo_blue_1
Already running capitan_nats_blue_1
Already running capitan_app_blue_1
Features
- Provides commands which operate on collection of containers.
- Uses predefined description of containers from readable configuration file.
- Can use any docker run option that is provided by your docker version.
- The order of starting containers is defined in configuration file.
- The order of stopping containers is the reverse of the order of starting.
- Easy to install, compiled static go binaries available for linux, and mac. It doesn't require any execution environment or other libraries.
- Allows the use of bash as hooks for many capitan commands.
- Blue/Green deployment - option to only remove original container when starting new version of same container if it starts and passes hook commands.
Installation
Head over to the releases page to download a pre-build binary or deb file.
Or using go:
go get github.com/byrnedo/capitan
Commands
Invasive commands
up
Create then run or update containers Recreates if:
If newer image is found it will remove the old container and run a new oneNo longer does this as capitan can't know which node to check images for when talking to a swarm.- Container config has changed
Starts stopped containers
capitan up
# Optionally can attach to output using `--attach|-a` flag.
capitan up -a
create
Create but don't run containers
capitan create
start
Start stopped containers
capitan start
# Optionally can attach to output using `--attach|-a` flag.
capitan start -a
scale
Start or stop instances of a container until required amount are running
# run 5 instances of mysql
capitan scale mysql 5
NOTE: for containers started via this command to be accepted by further commands, the config output must be altered to state the required instances
restart
Restart containers
capitan restart
# Further arguments passed through to docker, example `capitan start -t 5`
capitan restart -t 10
stop
Stop running containers
capitan stop
# Further arguments passed through to docker, example `capitan stop -t 5`
capitan stop -t 10
kill
Kill running containers using SIGKILL or a specified signal
capitan kill
# Further arguments passed through to docker, example `capitan kill --signal KILL`
capitan kill --signal KILL
rm
Remove stopped containers
capitan rm
# Further arguments passed through to docker, example `capitan rm -f`
capitan rm -fv
Non invasive commands
ps
Show container status
- Further arguments passed through to docker, example `capitan ps -a`
ip
Show container ip addresses
logs
Follow container logs
pull
Pull images for all containers
build
Build any containers with 'build' flag set (WIP)
Configuration
Global options
--cmd, -c "./capitan.cfg.sh" Command used to obtain config
--debug, -d Print extra log messages
--dry-run, --dry Preview outcome, no changes will be made
--filter, -f Filter to run action on a specific container only
--help, -h Show help
--version, -v Print the version
Config file/output
Service config is read from stdout of the command defined with --cmd
.
capitan
by default runs the command ./capitan.cfg.sh
in the current directory to get the config. This can be customized with --cmd|-c
flag.
capitan --cmd ./someotherexecutable <some action>
You could use any command which generates a valid config. It doesn't have to be a bash script like in the example or default.
Filtering
A single service type can specified for an action by using the --filter|-f
flag. So if your conf looked like this:
...
fooapp hostname blah
...
You could filter any command to run on just that service type by doing:
capitan --filter fooapp <some action>
Global options
global project
The project name, defaults to current working directory
global project_sep
String to use to create container name from project
and name specified in config
global blue_green [true/false]
String to deploy using blue/green handover. Defaults to false. This can be turned on/off per container with
CONTAINER_NAME blue-green [true/false]
global hook [hook name] [hook command]
Allows for a custom shell command to be evaluated once at the following points:
- Before/After up (
before.up
,after.up
)- This occurs during the
up
command
- This occurs during the
- Before/After Start (
before.start
,after.start
)- This will occur in the
start
command
- This will occur in the
- Before/After Stop (
before.stop
,after.stop
)- This will occur in the
stop
command
- This will occur in the
- Before/After Kill (
before.kill
,after.kill
)- This will occur in the
kill
command
- This will occur in the
- Before/After Rm (
before.rm
,after.rm
)- This will occur in the
rm
command
- This will occur in the
Container Options
The output format must be:
CONTAINER_NAME COMMAND [ARGS...]
All commands are passed through to docker cli as --COMMAND
EXCEPT the following:
build
This allows a path to be given for a dockerfile. Note, it will attempt to build every time. Use build-args
and pass --no-cache
to force a full clean build each time.
build-args
Any further arguments that need to be passed when building.
hook [hook name] [hook command]
Allows for a custom shell command to be evaluated at the following points for each container
- Before/After Run (
before.run
,after.run
)- This occurs during the
up
command
- This occurs during the
- Before/After Start (
before.start
,after.start
)- This will occur in the
up
,start
andrestart
command
- This will occur in the
- Before/After Stop (
before.stop
,after.stop
)- This will occur in the
stop
command only
- This will occur in the
- Before/After Kill (
before.kill
,after.kill
)- This will occur in the
kill
command only
- This will occur in the
- Before/After Rm (
before.rm
,after.rm
)- This will occur in the
up
andrm
command
- This will occur in the
NOTE hooks do not conform exactly to each command. Example: an up
command may rm
and then run
a container OR just start
a stopped container.
scale
Number of instances of the container to run. Default is 1.
NOTE: this is untested with links ( I don't use links )
link
An attempt to resolve a link to the first instance of a container is made. Otherwise the unresolved name is used.
WARNING: When scaling, if the link resolves to a container defined in capitan's config, it will always resolve to the first instance.
For example: app link mycontainer:some-alias
will always resolve to <project>_mycontainer_1
rm
By default capitan runs all commands with -d
. This flag makes capitan run the command with -rm
instead.
WARNING: This feature is experimental and may result in unexpected failures. A more predictable way is to leverage docker wait
along with a dynamic label.
For example:
mycontainer label $(date +%s)
mycontainer hook after.run docker wait \$CAPITAN_CONTAINER_NAME
volumes-from
An attempt to resolve a volume-from arg to the first instance of a container is made. Otherwise the unresolved name is used.
WARNING: When scaling, if the container name resolves to a container defined in capitan's config, it will always resolve to the first instance.
For example: app volumes-from mycontainer
will always resolve to <project>_mycontainer_1
Environment Variables
The following environment variables are available when creating the containers and when running container hooks
# container name
CAPITAN_CONTAINER_NAME
# container type
CAPITAN_CONTAINER_SERVICE_TYPE
# instance of this type,eg if you have scale = 5 then each container will have their own instance number from 1 -> 5
CAPITAN_CONTAINER_INSTANCE_NUMBER
# the project name
CAPITAN_PROJECT_NAME
The following environment variables are available to all hook scripts
CAPITAN_PROJECT_NAME
CAPITAN_HOOK_NAME
For example, following capitan.cfg.sh
#!/bin/bash
cat <<EOF
global project test
mysql name mymysql
mysql label containerName=\$CAPITAN_CONTAINER_NAME
mysql label containerServiceName=\$CAPITAN_CONTAINER_SERVICE_NAME
mysql label containerInstanceNumber=\$CAPITAN_CONTAINER_INSTANCE_NUMBER
mysql label projectName=\$CAPITAN_PROJECT_NAME
mysql hook after.run echo "hook: \$CAPITAN_HOOK_NAME: ran \$CAPITAN_CONTAINER_NAME in project \$CAPITAN_PROJECT_NAME"
EOF
Would result in the following run command:
docker run -d --name test_mysql_1
--label containerName=test_mysql_1
--label containerServiceName=mysql
--label containerInstanceNumber=1
--label projectName=test
And the following hook ouput
Running test_mysql_1
34e7fffb937c3154c2a963ee605c7958404aa5d80519db4ef3d2a80a06974021
hook: after.run: ran test_mysql_1 in project test
Note that the $
must be escaped if using HEREDOC or double quotes in bash.
Example Config
Check out dev-stack for an example.
Clone it and just run capitan --dry up
.
Or check out the ./example
dir.
Also, here's something to whet your appetite:
#!/bin/bash
PREFIX=dev
cat <<EOF
#
# General redis container
#
redis image redis:latest
redis hostname ${PREFIX}_redis
redis publish 6379
redis hook after.run echo "look everyone, I ran \$CAPITAN_CONTAINER_NAME" && sleep 3
redis hook after.start sleep 3
#
# General mongodb container
#
mongo image mongo:latest
mongo command mongod --smallfiles
mongo hostname ${PREFIX}_mongo
mongo publish 27017
#
# My app
#
app build ./
app publish 80
app link redis
app link mongo:mongodb
EOF
Roadmap
- Tests
- More efficient
up
logic - Helpful aliases in shell env.
- More flexible
build
command