Really fast deployer and server automation tool.
Mina works really fast because it's a deploy Bash script generator. It generates an entire procedure as a Bash script and runs it remotely in the server.
Compare this to the likes of Vlad or Capistrano, where each command is run separately on their own SSH sessions. Mina only creates one SSH session per deploy, minimizing the SSH connection overhead.
$ gem install mina
$ mina
Let's deploy a project using Mina.
In your project, type mina init
to create a sample of this file.
$ mina init
Created config/deploy.rb.
This is just a Rake file with tasks! See About deploy.rb for more info on what deploy.rb is. You will want to at least configure your server:
# config/deploy.rb
set :user, 'username'
set :domain, 'your.server.com'
set :deploy_to, '/var/www/flipstack.com'
...
Make a directory in your server called /var/www/flipstack.com
(in deploy_to)
change it's ownership to the correct user.
$ ssh username@your.server.com
# Once in your server, create the deploy folder:
~@your.server.com$ mkdir /var/www/flipstack.com
~@your.server.com$ chown -R username /var/www/flipstack.com
Back at your computer, do mina setup
to set up the folder
structure in this path. This will connect to your server
via SSH and create the right directories.
$ mina setup
-----> Creating folders... done.
See directory structure for more info.
Use mina deploy
to run the deploy
task defined in config/deploy.rb.
$ mina deploy
-----> Deploying to 2012-06-12-040248
...
Lots of things happening...
...
-----> Done.
The file deploy.rb
is simply a Rakefile invoked by Rake. In fact, mina
is
mostly an alias that invokes Rake to load deploy.rb
.
# Sample config/deploy.rb
set :domain, 'your.server.com'
task :restart do
queue 'sudo service restart apache'
end
As it's all Rake, you can define tasks that you can invoke using mina
. In this
example, it provides the mina restart
command.
The magic of Mina is in the new commands it gives you.
The queue
command queues up Bash commands to be run on the remote server.
If you invoke mina restart
, it will invoke the task above and run the queued
commands on the remote server your.server.com
via SSH.
See the command queue for more information on the queue command.
At the heart of it, Mina is merely sugar on top of Rake to queue commands and execute them remotely at the end. Take a look at this minimal deploy.rb configuration:
# config/deploy.rb
set :user, 'john'
set :domain, 'flipstack.com'
task :logs do
queue 'echo "Contents of the log file are as follows:"'
queue "tail -f /var/log/apache.log"
end
Once you type mina logs
in your terminal, it invokes the queued commands
remotely on the server using the command ssh john@flipstack.com
.
$ mina logs --simulate
# Execute the following commands via
# ssh john@flipstack.com:
#
echo "Contents of the log file are as follows:"
tail -f /var/log/apache.log
Mina provides the helper invoke
to invoke other tasks from a
task.
# config/deploy.rb
task :down do
invoke :maintenance_on
invoke :restart
end
task :maintenance_on
queue 'touch maintenance.txt'
end
task :restart
queue 'sudo service restart apache'
end
In this example above, if you type mina down
, it simply invokes the other
subtasks which queues up their commands. The commands will be run after
everything.
The deploy procedures make the assumption that you have a folder like so:
/var/www/flipstack.com/ # The deploy_to path
|- releases/ # Holds releases, one subdir per release
| |- 1/
| |- 2/
| |- 3/
| '- ...
|- shared/ # Holds files shared between releases
| |- logs/ # Log files are usually stored here
| `- ...
'- current/ # A symlink to the current release in releases/
It also assumes that the deploy_to
path is fully writeable/readable for the
user we're going to SSH with.
Mina provides the deploy
command which queues up a deploy script for
you.
# config/deploy.rb
set :domain, 'flipstack.com'
set :user, 'flipstack'
set :deploy_to, '/var/www/flipstack.com'
set :repository, 'http://github.com/flipstack/flipstack.git'
task :deploy do
deploy do
# Put things that prepare the empty release folder here.
# Commands queued here will be run on a new release directory.
invoke :'git:clone'
invoke :'bundle:install'
# These are instructions to start the app after it's been prepared.
to :launch do
queue 'touch tmp/restart.txt'
end
# This optional block defines how a broken release should be cleaned up.
to :clean do
queue 'log "failed deployment"'
end
end
end
It works by capturing the queued commands inside the block, wrapping them in a deploy script, then queueing them back in.
Here is an example of a deploy! (Note that some commands have been simplified to illustrate the point better.)
The deploy process builds a new temp folder with instructions you provide.
In this example, it will do git:clone
and bundle:install
.
$ mina deploy --verbose
-----> Creating the build path
$ mkdir tmp/build-128293482394
-----> Cloning the Git repository
$ git clone https://github.com/flipstack/flipstack.git . -n --recursive
Cloning... done.
-----> Installing gem dependencies using Bundler
$ bundle install --without development:test
Using i18n (0.6.0)
Using multi_json (1.0.4)
...
Your bundle is complete! It was installed to ./vendor/bundle
Once the project has been built, it will be moved to releases/
. A symlink
called current/
will be created to point to the active release.
$
-----> Moving to releases/4
$ mv "./tmp/build-128293482394" "releases/4"
-----> Symlinking to current
$ ln -nfs releases/4 current
Invoke the commands queued up in the to :launch
block. These often
commands to restart the webserver process. Once this in complete, you're done!
$
-----> Launching
$ cd releases/4
$ sudo service nginx restart
-----> Done. Deployed v4
If it fails at any point, the release path will be deleted. If any commands are
queued using the to :clean
block, they will be run. It will be as if nothing
happened. Lets see what happens if a build fails:
$
-----> Launching
$ cd releases/4
$ sudo service nginx restart
Starting nginx... error: can't start service
-----> ERROR: Deploy failed.
-----> Cleaning up build
$ rm -rf tmp/build-128293482394
-----> Unlinking current
$ ln -nfs releases/3 current
OK
Basic usage:
$ mina [OPTIONS] [TASKS] [VAR1=val VAR2=val ...]
-
-v
/--verbose
- This will show commands being done on the server. Off by default. -
-S
/--simulate
- This will not invoke any SSH connections; instead, it will simply output the script it builds. -
-t
/--trace
- Show backtraces when errors occur. -
-f FILE
- Use a custom deploy.rb configuration. -
-V
/--version
- Shows the current version.
There are many tasks available. See the tasks reference, or
type mina tasks
.
You may specify additional variables in the KEY=value
style, just like Rake.
You can add as many variables as needed.
$ mina restart on=staging
# This sets the ENV['on'] variable to 'staging'.
Invokes another Rake task.
Invokes the task given in task
. Returns nothing.
invoke :'git:clone'
invoke :restart
Options: reenable (bool) - Execute the task even next time.
Evaluates an ERB block in the current scope and returns a string.
a = 1
b = 2
# Assuming foo.erb is <%= a %> and <%= b %>
puts erb('foo.erb')
#=> "1 and 2"
Returns the output string of the ERB template.
SSHs into the host and runs the code that has been queued.
This is already automatically invoked before Rake exits to run all commands that have been queued up.
queue "sudo restart"
run!
Returns nothing.
Report time elapsed in the block. Returns the output of the block.
report_time do
sleep 2
# do other things
end
# Output:
# Elapsed time: 2.00 seconds
Measures the time (in seconds) a block takes. Returns a [time, output] tuple.
Internal: Invoked when Rake exits.
Returns nothing.
Exits with a nice looking message. Returns nothing.
die 2
die 2, "Tests failed"
Internal: Prints to stdout.
Consider using print_error
instead.
Queues code to be run.
This queues code to be run to the current code bucket (defaults to :default
).
To get the things that have been queued, use commands[:default]
Returns nothing.
queue "sudo restart"
queue "true"
commands == ['sudo restart', 'true']
Shortcut for queue
ing a command that shows up in verbose mode.
Converts a bash command to a command that echoes before execution. Used to show commands in verbose mode. This does nothing unless verbose mode is on.
Returns a string of the compound bash command, typically in the format of
echo xx && xx
. However, if verbose_mode?
is false, it returns the
input string unharmed.
echo_cmd("ln -nfs releases/2 current")
#=> echo "$ ln -nfs releases/2 current" && ln -nfs releases/2 current
Returns an array of queued code strings.
You may give an optional aspect
.
Returns an array of strings.
queue "sudo restart"
queue "true"
to :clean do
queue "rm"
end
commands == ["sudo restart", "true"]
commands(:clean) == ["rm"]
Starts a new block where new commands
are collected.
Returns nothing.
queue "sudo restart"
queue "true"
commands.should == ['sudo restart', 'true']
isolate do
queue "reload"
commands.should == ['reload']
end
commands.should == ['sudo restart', 'true']
Starts a new block where #commands are collected, to be executed inside path
.
Returns nothing.
in_directory './webapp' do
queue "./reload"
end
commands.should == ['cd ./webapp && (./reload && true)']
Defines instructions on how to do a certain thing.
This makes the commands that are queue
d go into a different bucket in commands.
Returns nothing.
to :prepare do
run "bundle install"
end
to :launch do
run "nginx -s restart"
end
commands(:prepare) == ["bundle install"]
commands(:restart) == ["nginx -s restart"]
Sets settings.
Sets given symbol key
to value in value
.
Returns the value.
set :domain, 'kickflip.me'
Sets default settings.
Sets given symbol key
to value in value
only if the key isn't set yet.
Returns the value.
set_default :term_mode, :pretty
set :term_mode, :system
settings.term_mode.should == :system
set :term_mode, :system
set_default :term_mode, :pretty
settings.term_mode.should == :system
Accesses the settings hash.
set :domain, 'kickflip.me'
settings.domain #=> 'kickflip.me'
domain #=> 'kickflip.me'
Hook to get settings. See #settings for an explanation.
Returns things.
Checks if Rake was invoked with --verbose.
Returns true or false.
if verbose_mode?
queue %[echo "-----> Starting a new process"]
end
Checks if Rake was invoked with --simulate.
Returns true or false.
Indents a given code block with count
spaces before it.
Internal: Normalizes indentation on a given string.
Returns the normalized string without extraneous indentation.
puts unindent %{
Hello
There
}
# Output:
# Hello
# There
Resets the indentation on a given code block.
Returns the output of command via SSH.
Helpers for deployment.
Wraps the things inside it in a deploy script and queues it. This generates a script using deploy_script and queues it.
Returns nothing.
Wraps the things inside it in a deploy script.
script = deploy_script do
invoke :'git:checkout'
end
queue script
Returns the deploy script as a string, ready for queue
ing.
Adds settings and tasks for managing Ruby Bundler.
require 'mina/bundler'
Any and all of these settings can be overriden in your deploy.rb
.
Sets the bundle path.
Sets the path to where the gems are expected to be.
This path will be symlinked to ./shared/bundle
so that the gems cache will
be shared between all releases.
Sets the options for installing gems via Bundler.
These tasks are meant to be invoked inside deploy scripts, not invoked on their own.
Installs gems.
This module is loaded when invoking mina
with or without a project.
Here are some of the common settings. All settings are optional unless otherwise noted.
(Required) Path to deploy to.
(Required) Host name to deploy to.
SSH port number.
If set to true
, enables SSH agent forwarding.
The local path to the SSH private key file.
Switches to be passed to the ssh
command.
Any and all of these settings can be overriden in your deploy.rb
.
Make the :environment
task exist by default. This is meant to be overridden
by users.
Initializes a new Mina project.
$ mina init
Shows the help screen.
Display all tasks in a nice table.
$ mina tasks
This module is automatically loaded for all Mina projects.
Any and all of these settings can be overriden in your deploy.rb
.
(default: 'releases')
(default: 'shared')
(default: 'current_path')
Name of the file to generate while a deploy is currently ongoing. (default: 'deploy.lock')
Number of releases to keep when doing the deploy:cleanup
task.
(default: 5)
Forces a deploy unlock by deleting the lock file.
$ mina deploy:force_unlock
You can also combine that task with deploy
:
$ mina deploy:force_unlock deploy
Links the shared paths in the shared_paths
setting.
Cleans up old releases.
By default, the last 5 releases are kept on each server (though you can change this with the keep_releases setting). All other deployed revisions are removed from the servers."
Sets up a site's directory structure.
Runs a command on a server.
$ mina run[tail -f logs.txt]
Adds settings and tasks for managing projects with foreman.
NOTE: Requires sudo privileges
require 'mina/foreman'
set :application, "app-name"
task :deploy => :environment do
deploy do
# ...
invoke 'foreman:export'
# ...
end
to :launch do
invoke 'foreman:restart'
end
end
Any and all of these settings can be overriden in your deploy.rb
.
Sets the service name that foreman will export to upstart. Uses application variable as a default. It should be set, otherwise export command will fail.
Sets the user under which foreman will execute the service. Defaults to user
Sets the foreman log path. Defaults to shared/log
encoding: utf-8
Adds settings and tasks related to managing Git.
require 'mina/git'
Any and all of these settings can be overriden in your deploy.rb
.
Sets the branch to be deployed.
These tasks are meant to be invoked inside deploy scripts, not invoked on their own.
Clones the Git repository. Meant to be used inside a deploy script.
Adds settings and tasks for managing Rails projects.
require 'mina/rails'
Any and all of these settings can be overriden in your deploy.rb
.
Sets the Rails environment for rake
and rails
commands.
Note that changing this will NOT change the environment that your application is run in.
Prefix for Bundler commands. Often to something like RAILS_ENV=production bundle exec
.
queue! "#{bundle_prefix} annotate -r"
The prefix for rake
commands. Use like so:
queue! "#{rake} db:migrate"
The prefix for rails
commands. Use like so:
queue! "#{rails} console"
The paths to be checked.
Whenever assets are compiled, the asset files are checked if they have changed from the previous release.
If they're unchanged, compiled assets will simply be copied over to the new release.
Override this if you have custom asset paths declared in your Rails's
config.assets.paths
setting.
The command to invoke when precompiling assets. Override me if you like.
Macro used later by :rails, :rake, etc
These tasks can be invoked in the command line.
Invokes a rails command.
$ mina rails[console]
Invokes a rake command.
$ mina rake db:cleanup
Opens the Ruby console for the currently-deployed version.
$ mina console
These tasks are meant to be invoked inside deploy scripts, not invoked on their own.
Adds settings and tasks for managing rbenv installations.
require 'mina/rbenv'
task :environment do
invoke :'rbenv:load'
end
task :deploy => :environment do
...
end
Any and all of these settings can be overriden in your deploy.rb
.
Sets the path where rbenv is installed.
You may override this if rbenv is placed elsewhere in your setup.
Loads the rbenv runtime.
Adds settings and tasks for managing RVM installations.
require 'mina/rvm'
task :environment do
invoke :'rvm:use[ruby-1.9.3-p125@gemset_name]'
end
task :deploy => :environment do
...
end
Any and all of these settings can be overriden in your deploy.rb
.
Sets the path to RVM.
You can override this in your projects if RVM is installed in a different path, say, if you have a system-wide RVM install.
Uses a given RVM environment provided as an argument.
This is usually placed in the :environment
task.
task :environment do
invoke :'rvm:use[ruby-1.9.3-p125@gemset_name]'
end
Creates a rvm wrapper for a given executable.
This is usually placed in the :setup
task.
task ::setup => :environment do
...
invoke :'rvm:wrapper[ruby-1.9.3-p125@gemset_name,wrapper_name,binary_name]'
end
Adds settings and tasks for managing projects with [whenever]. [whenever]: http://rubygems.org/gems/whenever
© 2012-2013, Nadarei. Released under the MIT License.
Mina is authored and maintained by Rico Sta. Cruz and Michael Galero with help from its contributors. It is sponsored by our startup, Nadarei.
Rico:
- My website (ricostacruz.com)
- Github (@rstacruz)
- Twitter (@rstacruz)
Michael:
- My website (michaelgalero.com)
- Github (@mikong)