sbt-rancher-deploy
is a plugin for sbt that allows deployment of
Docker images to Rancher environments.
You can use a plugin like sbt-docker
to build Docker images of your projects and push them to a Docker image repository of your liking, and then use sbt-rancher-deploy
to deploy these images to a Rancher stack.
To enable the plugin, create a file project/rancherDeployment.sbt
with the following content:
lazy val root = (project in file(".")).dependsOn(rancherDeployPlugin)
lazy val rancherDeployPlugin = RootProject(uri("ssh://git@github.com/focuscura/sbt-rancher-deploy.git#0.2"))
Then, in your main build.sbt
file, you can use the following settings in your projects (assuming you use sbt-docker
to build the Docker images:
lazy val `my-project` = project.in(file("my-project"))
.settings(
dockerFile in docker := {
// task definition for building the Docker image
// ...
},
imageNames in docker := Seq(ImageName(s"user/my-image")),
rancherServices := Seq("my-service-1", "my-service-2" /*, ... */), // The rancher services to deploy this project to
rancherDockerImage := Def.task {
(imageNames in docker).value.head.toString()
}.dependsOn(sbtdocker.DockerKeys.dockerPush).dependsOn(sbtdocker.DockerKeys.docker).value,
/*
further settings
...
*/
)
A task returning a Boolean
that indicates whether a deployment must be simulated.
When this task returns true
, a dry-run deployment is performed, ie. no actual API calls are done at the selected rancher environment.
The default value returned by this task is false
.
A task returning a String
containing the name of the Docker image that should be deployed at the Rancher service(s) returned by the rancherServices
task. It is advisable to make this task depend on the task(s) that build and push the Docker image for this project (as shown in the above code sample), so that when a deployment is performed, these tasks are run before the actual deployment.
A task returning a Seq[String]
containing the names of the Rancher service(s) this project's Docker image is deployed to. When this task returns an empty Seq
, no deployment will be performed for this project.
The default return value for this task is Seq()
A task returning a Boolean
indicating whether an upgrade of the services in rancherServices
should be finished (when true
) or should be rolled back (when false
). This task is a logical location to run your integration tests against the Rancher environment that is being updated.
The default return value for this task is true
In your project's base directory, create a file with the following contents, changing the values applicable to your Rancher environments:
environments {
# an object with environment names as its keys, each
# mapping to an object like the one below
test {
# Which git branches are accepted to be deployed to this environment?
# "*" counts as a wildcard
allowed-branches = ["*"]
# Allow uncommitted changes to be deployed to this environment?
allow-uncommitted-changes = true
#rancher settings for this environment
rancher {
# The URL where rancher server can be reached, no path after the hostname
url = "[test env Rancher URL]"
# The rancher stack where the deployed services can be found
stack = "my-stack-test"
basic-auth {
username = "[my Rancher api access key]"
password = "[my Rancher api secret key]"
}
}
}
accept {
allowed-branches = ["accept"]
allow-uncommitted-changes = false
rancher {
url = "[accept env Rancher URL]"
stack = "my-stack-accept"
basic-auth {
username = "[my Rancher api access key]"
password = "[my Rancher api secret key]"
}
}
}
production {
allowed-branches = ["production"]
allow-uncommitted-changes = false
rancher {
url = "[production env Rancher URL]"
stack = "my-stack-production"
basic-auth {
username = "[my Rancher api access key]"
password = "[my Rancher api secret key]"
}
}
}
}
The keys of the environments (test
, accept
and production
in the above configuration) are the same as the ones used when a deployment is performed, as described below. You can use other names for the keys, eg. staging
, live
, etc.
You can use the rancher-deploy-to
sbt command to perform a deployment to the environment you give as this command's first argument. So to deploy to the test environment, use rancher-deploy-to test
.
Running this command will first check if the git branch of the working copy from which the command is run is one of the branches in environment.[name].allowed-branches
, and if environment.[name].allow-uncommitted-changes
corresponds with the state of your working copy. If neither of these checks succeed, deployment is aborted.
Next, the project's unit tests (when present) are run, and if any test fails, the deployment is aborted.
A Rancher service upgrade is performed for all services, and depending on the return value of rancherShouldFinishUpgrade
, finishes the service upgrade, or rolls back the upgrade.
The rancher-deploy-to
command performs the tasks below on the currently selected project and its aggregates in the following order:
- Run unit tests for the current project and all its aggregates, abort if any test fails.
- Upgrade all services for the current project and its aggregates.
- Collect the results of the
rancherShouldFinishUpgrade
of the current project and its aggregates. If any of these results isfalse
, roll back all the upgraded services and abort. If all of these results aretrue
, finish the upgrades of all services, and return success.
In the src/sbt-test
folder there are several projects that are used as test cases for the sbt-scripted
plugin. A description of how this works can be found here.
Basically it boils down to this:
Each folder in src/sbt-test/sbt-rancher-deploy
is a separate sbt test project that makes use of the sbt-rancher-deploy
plugin. Each of these test projects contains a test script, conveniently named test
. This file contains sbt commands that are executed on a test run when the scripted
sbt task is started from the sbt-rancher-deploy
root. The test project directory is copied to a temporary location, scripted
then starts a separate sbt process in which the commands from the test script are run on the test project copy. The tests produce a lot of output, but if the scripted
task finishes with success
this means all tests passed.
The format of the test
file is this:
#
starts a one-line comment> <sbt-task-or-command> [arg ...]
sends a task to sbt (and tests if it succeeds)$ <file-command> [arg ...]
performs a file command (and tests if it succeeds)-> <sbt-task-or-command> [arg ...]
sends a task to sbt, but expects it to fail-$ <file-command> [arg ...]
performs a file command, but expects it to fail
A file command is one of the following
touch path [path ...]
creates or updates the timestamp on the filesdelete path [path ...]
deletes the filesexists path [path ...]
checks if the files existmkdir path [path ...]
creates dirsabsent path [path ...]
checks if the files don't existnewer source target
checks if source is newerpause
pauses until enter is pressedsleep time
sleepsexec command [args ...]
runs the command in another processcopy-file fromPath toPath
copies the filecopy fromPath [fromPath ...] toDir
copies the paths to toDir preserving relative structurecopy-flat fromPath [fromPath ...] toDir
copies the paths to toDir flat