Somewhat drama-free deployments.
Please note, this document (and the project, duh) are very WIP.
This project aims to be a lightweight, easy-to-use deployment system somewhere between a shell script/Rakefile and something like Chef or Ansible. It's pretty much a sort of wrapper around shell commands.
I wanted to still be able to keep my deployments inside the project repositories themselves but move away from giant Rakefiles and shell commands.
To install from this source, just run
gem build lcdeploy.gemspec
gem install gemspec-<version>.gem
Rake tasks build and install are also available. Just run bundle
to install rake and run rake. This will build and install the latest
version of the Gem. You can also probably add lcdeploy as a
dependency in a Gemfile by providing a github option pointing to
this repository:
gem 'lcdeploy', github: 'axocomm/lcdeploy'Either way, the lcd executable should now be available for use in
projects.
An lcdfile just contains the steps to take for deploying your
application. It is basically just Ruby code, e.g.:
configure from_json: 'resources/site-config.json'
repo_dir = '/home/deploy/xyzy-site'
clone_repository 'git@github.com:axocomm/xyzy-site',
target: repo_dir,
branch: 'master'
run_command 'npm i', cwd: repo_dir
run_command 'gulp build', cwd: repo_dir
build_docker_image 'xyzy-site',
path: repo_dir
run_docker_container 'xyzy-site',
image: 'xyzy-site',
ports: [[5000, 5000]],
volumes: [["#{repo_dir}/resources/pages", '/pages']]With an lcdfile populated, you can now run lcdeploy preview to get
a list of commands that will be run. lcdeploy deploy will actually
execute the deployment.
Configuration is done either right in the lcdfile or via a
JSON/YAML file. Right now this just contains SSH connection
information but may be extended to support more.
To configure in the lcdfile, just call the configure function with
a hash of options, e.g.:
configure ssh_host: 'winds', ssh_user: 'deploy', ssh_key: '~/.ssh/id_rsa.pub'You can also pass a filename to from_json to read from a JSON file
with this information, e.g.
{
"ssh_host": "winds",
"ssh_user": "deploy",
"ssh_key": "~/.ssh/id_rsa.pub"
}or from_yaml to read from a YAML:
---
ssh_host: winds
ssh_user: deploy
ssh_key: ~/.ssh/id_rsa.pubssh_host: the target machine hostname or IPssh_user: the user to connect asssh_password(optional): the SSH passwordssh_key(optional): the SSH public key
One of ssh_password or ssh_key must be provided. Soon this should
be prompting for a username and password if necessary.
Steps are pretty self-explanatory. They will typically follow the form
step_name '<label argument>', foo: 'bar', baz: 'quux'The label argument right now maps to one of the required parameters
for the step. Eventually this will probably move to being an actual
label (also serving as a default value for a target directory,
filename, etc.).
Parameters are subject to change and there isn't really a convention yet about source/destination.
The following are the currently-supported steps and their parameters.
These steps execute commands (or otherwise do something) on the local machine.
Copy a local file to the remote server using SCP
source(label argument): the local source filetarget: the remote target
copy_file 'config.prod.yml', target: '/home/deploy/foo.bar/config.yml'would copy config.prod.yml to
<ssh_user>@<ssh_host>:/home/deploy/foo.bar/config.yml.
Render an ERB template
template(label argument): the template nametarget: the target fileparams: a hash of template parametersuser(optional, defaults tossh_user): the user of the filegroup(optional, defaults tossh_user): the group of the filemode(optional, defaults to 644): the permissions of the file
render_template 'config.json.erb',
target: '/home/deploy/foo.bar/config.json',
params: {
db_host: '22.22.22.22',
db_user: 'foo',
db_password: 'bar',
db_name: 'foobar'
}Run a command locally
command(label argument): the command to run
run_local_command 'lein uberjar'These steps connect to the host via SSH for command execution.
Create a directory if it does not exist
target(label argument): the remote targetuser(optional, defaults tossh_user): the user of the directorygroup(optional, defaults tossh_user): the group of the directorymode(optional, defaults to 644): the mode of the directory
create_directory '/www/foo.bar', user: 'deploy', group: 'www-data'Clone a repository
source(label argument): the repository URL (TODO: might swap withtarget)target: where to clone the repositorybranch(optional, defaults to 'master'): which branch to checkoutuser(optional, defaults tossh_user): the usergroup(optional, defaults tossh_user): the group
clone_repository 'git@gitlab.com:axocomm/foo.bar',
target: '/home/deploy/foo.bar',
user: 'deploy',
branch: 'dev'Build a Docker image
name(label argument): the image namepath: where to find theDockerfiletag(optional, defaults to 'latest'): the image tagrebuild(optional, defaults to false): rebuild the image if it exists
build_docker_image 'foo-bar', tag: 'dev', path: repo_dirStart a Docker container
name(label argument): the name of the containerimage: the image nametag(optional, defaults to 'latest'): the image tagports(optional): an array of ports to forward from the container Each element can be an integer port or an array of[<host port>, <container port>]volumes(optional): an array of volumes to add to the container Each element must be an array containing the host directory and mount point
run_docker_container 'foo-bar',
image: 'foo-bar',
tag: 'dev',
ports: [5000, [1234, 4567]],
volumes: [[Dir.pwd, '/app']]Run a command remotely
command(label argument): the commandcwd(optional): where to run the commanduser(optional, defaults tossh_user): the user to run the command as
run_command 'npm i', cwd: repo_dir- Better error handling
- More flexible condition checking
- Move away from trying to make everything a shell command
- Pull from repository if it already exists in
clone_repository - Add user and group for
render_template - General cleanup, including better permission/ownership handling