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 ran 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'
endAs 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 ran 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"
endOnce 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.logMina 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'
endIn this example above, if you type mina down, it simply invokes the other
subtasks which queues up their commands. The commands will be ran 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 ran 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
endIt 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 ran. 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 :restartOptions: 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.0 secondsMeasures the time (in ms) 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 ran.
This queues code to be ran 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 queueing 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 currentReturns 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 queued 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 == :systemAccesses 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"]
endChecks 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
# ThereResets 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 scriptReturns the deploy script as a string, ready for queueing.
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 initShows the help screen.
Display all tasks in a nice table.
$ mina tasksThis 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_unlockYou can also combine that task with deploy:
$ mina deploy:force_unlock deployLinks 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'
endend
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 ran 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:cleanupOpens the Ruby console for the currently-deployed version.
$ mina consoleThese 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
...
endAny 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
...
endAny 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]'
endCreates 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]'
endAdds 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)

