Is anyone using Bootleg for deployment instead of Edeliver?

I’ve had nothing but trouble with Edeliver since moving to Phoenix 1.3, so I’m now about to try Bootleg: Simple deployment and server automation for Elixir.

I can’t find any tutorials/examples of use in blogs and am just wondering if anyone in this community knows of any or could give any advice on using it or why they think I should use a different deployment tool instead.

2 Likes

I would love to see the community find/create and nurture an alternative to the Capistrano-like workflows espoused by both of these tools, and most other language ecosystems. That mental model just doesn’t jive with the way I see the world, or the way I want to work and ship code. I’ve worked in infrastructure/operations for multiple polyglot organizations where human-instigated, push-based deploys over SSH were on their way out in favor of configuration management, then immutable infrastructure, then containers and container schedulers.

1 Like

Interested in deploy perspectives as well. Edeliver seems good but wasn’t what I was looking for personally. To get to know the BEAM I wrote custom tools using gulp. Half of them I haven’t got working yet but the half that do take out quite a bit of labor already for me. Doesn’t seem like a stretch to think a more customizable approach can be taken to go anywhere from push button to some point in between a manual ssh launch without backbreaking labor. Bootleg involves git as well which I don’t want meself

@shanesveller I agree, but it’s important to remember that such tools also have their place in small shops, or even personal projects, not to mention in organizations which don’t yet buy in to containers. I’m all about containers and orchestration, and having that tooling automate deployments, but it’s a high barrier to entry to expect everyone to go that route. It requires a fairly well-rounded knowledge of containers, the various orchestration technologies available, as well as the servers to run all of it. It’s generally (at this point) non-trivial to set up and maintain something like Kubernetes, and that’s only part of the equation. For those of us which are taking advantage of such tools, you really don’t need much more than what you already get at Distillery’s level, at least I can’t think of anything I’ve felt like I’ve needed - tools like Bootleg, Edeliver, etc., cover the needs of anyone not able, or not willing to go down that road.

In my opinion, if I had to use one of these automation tools, I would be looking at Bootleg; but I’m a bit old school, so I prefer to automate things myself using lower-level primitives (in this case, releases provided by Distillery and shell scripts), since most of the time the automation I need is ad-hoc anyway, I may as well own it as part of the application. That said, that’s clearly not the case for everyone, so if you find yourself in a pretty typical deployment scenario, something like Bootleg is probably exactly what you need. Personally, my opinion is that if you find yourself fighting the tools, it’s probably because your situation isn’t well suited for them, and you should either build the tool you need, open source it so you can help others in the same situation and benefit from their work as well, or whip something together ad-hoc for your specific situation.

1 Like

This is how I do it, I have a release.sh script that I run after git clone/pull’ing the repo, it grabs deps, npm, compiles, builds production files, releases, updates systemd with the new version and forces a reload/swap from the old to the new system. :slight_smile:

I initially went for edeliver, but if I remember correctly I had an issue or two and I didn’t quite feel comfortable with it, so I’ve since moved to using a bash script I wrote (below in case it’s of any use - I hope I’m not embarrassing myself too much!) that runs Distillery which I run from my workstation and which is enough for my simple needs at the moment. So far I’m only using one server per app.

I’m one of those people @bitwalker mentions who isn’t comfortable with containers. I do plan to look at Bootleg at some point.

build_and_deploy_release.sh:

#!/usr/bin/env bash

# Usage: ./build_and_deploy_release.sh app version environment
# Usage example: ./build_and_deploy_release.sh my_app 0.0.1 prod

# Set to exit on error
set -ue -o pipefail

# Ensure the present working directory is that of the script
cd "${0%/*}"

# Source required functions
. $HOME/sh_scripts/functions/ask.sh

# Check for correct number of command line arguments
if [[ $# -ne 3 ]] ; then
	echo "Usage: $0 app version environment"
fi

app="$1"
version="$2"
environment="$3"
releases_dir="_build/prod/rel/${app}/releases"
archive="${app}.tar.gz"

case $app:$environment in
	app_name:prod)
		server="example.com"
		sudo_ssh_profile="user@${server}"
		app_ssh_profile="app-name@${server}"
		;;
	app_name:staging)
		server="staging.example.com"
		sudo_ssh_profile="user@${server}"
		app_ssh_profile="app-name@${server}"
		;;
	*)
		echo "No server found for ${app} at ${environment}"; exit 1 ;;
esac

if ask "Build release of ${app} ${version} for ${environment}?" ; then
	MIX_ENV=prod mix release --profile=${app}:${environment}
else
	exit 1
fi

if ask "Copy release archive to ${app_ssh_profile} and extract?" ; then
	# Copy the release archive to the server
	scp -q "${releases_dir}/${version}/${archive}" "${app_ssh_profile}:~/app/"
	# Extract and delete the release archive on the server
	ssh -qt "${app_ssh_profile}" "tar -C ~/app -xzf ~/app/${archive} && rm ~/app/${archive}"
else
	exit 1
fi

if ask "Restart ${app} app at ${app_ssh_profile}?" ; then
	echo "Restarting app; provide password for sudo for ${sudo_ssh_profile}"
	ssh -qt "${sudo_ssh_profile}" "sudo systemctl restart ${app}_app.service"
else
	exit 1
fi

echo "Deployment completed"

ask.sh:

################################################################################
# Ask yes/no questions, with or without a default answer.
# http://djm.me/ask
# Globals:
#   None
# Arguments:
#   1: question
#   2: default answer: Y or N (optional)
# Returns:
#   None
# Example usage:
#   if ask "Do you want to do such-and-such?"; then
#       echo "Answer is yes"
#   else
#       echo "Answer is no"
#   fi
################################################################################
ask() {
	local prompt default REPLY

	while true; do

		if [ "${2:-}" = "Y" ]; then
			prompt="Y/n"
			default=Y
		elif [ "${2:-}" = "N" ]; then
			prompt="y/N"
			default=N
		else
			prompt="y/n"
			default=
		fi

		# Ask the question (not using "read -p" as it uses stderr not stdout)
		echo -n "$1 [$prompt] "

		# Read the answer (use /dev/tty in case stdin is redirected from somewhere else)
		read REPLY </dev/tty

		# Default?
		if [ -z "$REPLY" ]; then
			REPLY=$default
		fi

		# Check if the reply is valid
		case "$REPLY" in
			Y*|y*) return 0 ;;
			N*|n*) return 1 ;;
		esac

	done
}
5 Likes