Albatross (albatross-cljs) is a declarative deployment library and DSL.
Albatross leverages Weaver extensively to provide flexibility, concision, and code reuse.
An albatross deployment is specified as a template with pre-deploy, deploy, and post-deploy steps.
It is processed with the albatross.core/generate-deployment
function, which returns a map.
This map has a function under :run-deployment
which can be run to perform the entire deployment.
The context can be specified as :weaver/context
at the top level of the map (must be a map literal, but I am considering supporting afilename as well), or as metadata in a similar manner to figwheel-main
(e.g. ^{:config {...}}{:deployment ...}
).
If both are provided, they are merged, and the metadata takes precedence.
A context can also be passed explicitly to albatross.core/generate-deployment
in its two arity version, in which case both metadata and :weaver/context
are ignored.
The first thing that happens when generate-deployment
is called is the templating of the deployment map.
Once the deployment map is templated, there are three major parts, which are top-level keys.
:pre-deploy-hooks
which set up for the deployment, :deployment
which specifies the actual deploying, and :post-deploy-hooks
which manage actions post-deployment (TODO). We will cover these in detail a bit later.
NOTE: post-deploy-hooks are not implemented fully
Deploy hooks are effectful (usually non-deployment) steps that must be performed before or after a deployment. Examples include: generating files from templates, pulling from/pushing to Git, Setting environment variables, building an uberjar, etc.
The only supported hook type at the moment is the :weaver
hook type.
The weaver hook takes a map with :templates
- a vector of templates, and :context
- A context map which will be used by weaver.
See weaver for more detailed documentation on specific templating.
{...
:pre-deploy-hooks [...
{:albatross/type :weaver
:context {:config {:environment "staging"
:version :git/short-hash
:app-name "my-service"
:shortname "my-service"
:external-port 30055
:app-container-port 3000}}
:templates [{:from "k8s-edn/"
:to "target/k8s/json/"}]}
...]
...}
Deployment is where the meat of the deployment happens.
This is vector of maps which are each transformed into a vector of instructions (Only unix shell string commands are supported currently).
Each map returns a vector of one or more instructions which are then concatenated to form a complete deployment instruction set.
Deployment maps are parsed using the deployment-instructions
multimethod, which can be extended as needed.
Note that the deployment step is NOT effectful.
Only calling the generated deployment-fn
or run-deployment
functions will cause the actual deployment to occur.
Deployment type is specified by the :albatross/type key on the instruction map.
Below are a list of deployment-instruction types supported by albatross.
This serves as an escape hatch to perform arbitrary shell instructions.
Should be used responsibly, as with any escape hatch.
Here's an example of a :shell
configuration:
{...
:deployment [...
{:albatross/type :shell
:exec ["echo foo" "pwd" "echo bar"]}
...]
...}
The :exec
key can be either a string or a vector of strings.
Like the entire albatross config, it can also include weaver templating.
The value of exec is either returned directly, or wrapped in a vector if necessary.
The docker deployment step represents deploying a set of docker images with a single connection to a single repository.
It is composed of a URL, credentials (:user
key with username and either :pass
for a literal password, or a :pass-file
for piping in a password from a file into stdin), and :images
, a vector of images.
Each image is a map with :name
(the image's name), :tags
(a list of desired tags), and :workspace
(the directory containing the Dockerfile
).
The :docker
step will do the following:
docker login
using the provided credentials, connecting to the repository.- For each image in
:images
, rundocker build
in the specified workspace, anddocker push
with the specified tags docker logout
to close the session
Here's an example of a :docker
configuration:
{...
:deployment [...
{:albatross/type :docker
:url "docker.mycompany.tld:PORT/"
:user :kw-env/DOCKER_USER ;;weaver => "jenkins"
:pass :kw-env/DOCKER_PASS ;; weaver => "password123"
:images [{:name :config/image-name ;; weaver => "myproject"
:tags ["staging-latest"]
:workspace "./"}]}
...]
...}
The kubernetes deployment step represents a set of actions (performed by kubectl
) associated with a single context (i.e. KUBECONFIG).
The context can also be configured manually (e.g. by using environment variables or :shell
steps) in which case the :kubeconfig
and :use-context
keys should be left blank.
There is a slight difference between :kubeconfig
and :use-context
.
They correspond to attaching a --kubeconfig
flag to each kubectl
command, and to running kubectl config use-context <context>
before other commands respectively.
They can be used together, but this is generally unnecessary and has not been tested.
The kubernetes deployment step consists of a :kubeconfig
and/or a :use-context
, an optional, purely for logging :cluster-name
, and :actions
, a vector of k8s action maps.
Each action in :actions
is handled by the albatross.kubernetes/action-instructions
which can be extended as necessary.
The types are as follows:
:apply-dir
, which is equivalent to runningkubectl apply -f <:dir>
.:secret
, this is equivalent to deleting and recreating a secret from a file or many files.
:apply-dir
is intended to be used with the :weaver
pre-deploy hook which generates JSON files from a source directory of EDN templates.
Since apply
can be used to declaratively specify a set of kubernetes objects desired and allows kubernetes to manage the transition, it is the preferred method of deployment.
However, sometimes specific actions are required
:secret
was added due to a specific need I had. It overwrites an existing secret from a file or a set of files.
Here's an example of a :kubernetes
configuration:
{...
:deployment [...
{:albatross/type :kubernetes
:use-context "my-context@kubernetes"
:cluster-name "my-service"
:actions [{:action-type :secret
:name "my-service-config"
:config-map {"app-config" "dev-config.edn"}}
{:action-type :apply-dir
:dir "target/foo/k8s/json/"}]}
...]
...}
weaver.core/generate-deployment
in and of itself doesn't have any side-effects. It returns a map of functions that perform various tasks, as well as data about these functions.
The keys are: :config
:pre-deploy-hooks
:pre-deploy-fn
:instructions
:deployment-fn
:post-deploy-hooks
:post-deploy-fn
and :run-deployment
This is the fully templated config map (i.e. post-weaver) that was used to generate this deployment.
This is a vector of maps representing the generated pre-deploy hooks. Their shape depends on the hook type, but each will have a :hook-fn
and a :description
.
This is a function that runs all pre-deploy-hooks in order.
This is a vector of strings (specifically bash commands) that comprise the deployment.
This is a function that executes all deployment instructions in order in a shell process
TODO see :pre-deploy-hooks, similar come after a successful deployment
TODO see :pre-deploy-fn, similar but run after a successful deployment
Runs pre-deploy-fn, then deployment-fn, then post-deploy-fn, returning the results in a vector
To get an interactive development environment run:
lein fig:build
This will auto compile and send all changes to the browser without the need to reload. After the compilation process is complete, you will get a Browser Connected REPL. An easy way to try it is:
(js/alert "Am I connected?")
and you should see an alert in the browser window.
To clean all compiled files:
lein clean
To create a production build run:
lein clean
lein fig:min
Copyright © 2018 FIXME
Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.