├── Rakefile ├── lib ├── mina-stack │ ├── version.rb │ ├── base.rb │ ├── setup.rb │ └── defaults.rb ├── templates │ ├── application.yml.erb │ ├── private_pub.yml.erb │ ├── monit │ │ ├── redis.erb │ │ ├── nginx.erb │ │ ├── postgresql.erb │ │ ├── sidekiq.erb │ │ ├── puma.erb │ │ ├── memcached.erb │ │ ├── private_pub.erb │ │ ├── monitrc.erb │ │ └── unicorn.erb │ ├── database.yml.erb │ ├── sidekiq.yml.erb │ ├── memcached.conf.erb │ ├── puma.rb.erb │ ├── nginx.conf.erb │ ├── unicorn.rb.erb │ ├── upstart │ │ ├── rpush.conf.erb │ │ ├── phobos.conf.erb │ │ ├── puma.conf.erb │ │ └── sidekiq.conf.erb │ └── unicorn_init.erb ├── recipes │ ├── imagemagick.rb │ ├── inspeqtor.rb │ ├── bower.rb │ ├── node.rb │ ├── libs.rb │ ├── memcached.rb │ ├── rpush.rb │ ├── rails.rb │ ├── phobos.rb │ ├── unicorn.rb │ ├── redis.rb │ ├── puma.rb │ ├── sidekiq.rb │ ├── private_pub.rb │ ├── rbenv.rb │ ├── elastic_search.rb │ ├── nginx.rb │ ├── monit.rb │ └── postgresql.rb ├── mina-stack.rb └── generators │ └── mina │ ├── templates │ ├── production.rb │ └── deploy.rb │ └── stack │ └── install_generator.rb ├── Gemfile ├── .gitignore ├── mina-stack.rb ├── mina-stack.gemspec ├── LICENSE.txt └── README.md /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | -------------------------------------------------------------------------------- /lib/mina-stack/version.rb: -------------------------------------------------------------------------------- 1 | module Mina 2 | module Stack 3 | VERSION = "0.0.23" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in mina-stack.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /lib/templates/application.yml.erb: -------------------------------------------------------------------------------- 1 | <%= rails_env %>: 2 | S3_BUCKET: folify 3 | S3_KEY: KEY 4 | S3_SECRET: Secret -------------------------------------------------------------------------------- /lib/templates/private_pub.yml.erb: -------------------------------------------------------------------------------- 1 | production: 2 | server: "http://folify.com:9292/faye" 3 | secret_token: "secret" 4 | signature_expiration: 3600 # one hour 5 | -------------------------------------------------------------------------------- /lib/templates/monit/redis.erb: -------------------------------------------------------------------------------- 1 | check process redis 2 | with pidfile /var/run/redis/redis-server.pid 3 | if failed host 127.0.0.1 port 6379 then restart 4 | if 5 restarts within 5 cycles then timeout -------------------------------------------------------------------------------- /lib/templates/database.yml.erb: -------------------------------------------------------------------------------- 1 | <%= rails_env %>: 2 | adapter: postgresql 3 | database: <%= psql_database %> 4 | username: <%= psql_user %> 5 | password: <%= psql_password %> 6 | host: localhost 7 | encoding: utf8 8 | pool: 16 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | -------------------------------------------------------------------------------- /lib/templates/monit/nginx.erb: -------------------------------------------------------------------------------- 1 | check process nginx with pidfile <%= nginx_pid %> 2 | start program = "/etc/init.d/nginx start" 3 | stop program = "/etc/init.d/nginx stop" 4 | if children > 250 then restart 5 | if 5 restarts within 5 cycles then timeout -------------------------------------------------------------------------------- /mina-stack.rb: -------------------------------------------------------------------------------- 1 | require "mina-stack/version" 2 | require 'mina-stack/defaults' 3 | require 'mina-stack/base' 4 | require 'mina-stack/setup' 5 | 6 | Dir['config/servers/*.rb'].each { |f| load f } 7 | Dir[File.dirname(__FILE__) + '/recipes/*.rb'].each {|file| require file } -------------------------------------------------------------------------------- /lib/templates/sidekiq.yml.erb: -------------------------------------------------------------------------------- 1 | :verbose: false 2 | :namespace: sidekiq 3 | :concurrency: <%= sidekiq_concurrency %> 4 | :queues: 5 | - [high, 7] 6 | - [low, 5] 7 | - [default, 3] 8 | - [mailers, 5] 9 | :limits: 10 | low: <%= (sidekiq_concurrency*0.4).to_i %> 11 | -------------------------------------------------------------------------------- /lib/recipes/imagemagick.rb: -------------------------------------------------------------------------------- 1 | namespace :imagemagick do 2 | 3 | desc "Install the latest release of Imagemagick" 4 | task :install do 5 | invoke :sudo 6 | queue "sudo apt-get install imagemagick libmagickwand-dev -y" 7 | end 8 | 9 | task(:setup) { } 10 | 11 | end -------------------------------------------------------------------------------- /lib/templates/memcached.conf.erb: -------------------------------------------------------------------------------- 1 | # run as a daemon 2 | -d 3 | 4 | logfile /var/log/memcached.log 5 | 6 | # memory limit 7 | -m <%= memcached_memory_limit %> 8 | 9 | # port 10 | -p 11211 11 | 12 | # user 13 | -u memcache 14 | 15 | # listen only on localhost (for security) 16 | -l 127.0.0.1 -------------------------------------------------------------------------------- /lib/mina-stack.rb: -------------------------------------------------------------------------------- 1 | require 'rake' 2 | require 'mina' 3 | require "mina-stack/version" 4 | require 'mina-stack/defaults' 5 | require 'mina-stack/base' 6 | require 'mina-stack/setup' 7 | 8 | Dir['config/servers/*.rb'].each { |f| load f } 9 | Dir[File.dirname(__FILE__) + '/recipes/*.rb'].each {|file| require file } -------------------------------------------------------------------------------- /lib/templates/monit/postgresql.erb: -------------------------------------------------------------------------------- 1 | check process postgresql with pidfile <%= postgresql_pid! %> 2 | start program = "/etc/init.d/postgresql start" 3 | stop program = "/etc/init.d/postgresql stop" 4 | if failed host localhost port 5432 protocol pgsql then restart 5 | if 5 restarts within 5 cycles then timeout -------------------------------------------------------------------------------- /lib/templates/monit/sidekiq.erb: -------------------------------------------------------------------------------- 1 | check process <%= sidekiq_name %> 2 | with pidfile <%= sidekiq_pid %> 3 | start program = "service <%= sidekiq_name %> start" with timeout 90 seconds 4 | stop program = "service <%= sidekiq_name %> stop" with timeout 90 seconds 5 | if totalmem is greater than 200 MB for 2 cycles then restart # eating up memory? 6 | group sidekiq -------------------------------------------------------------------------------- /lib/recipes/inspeqtor.rb: -------------------------------------------------------------------------------- 1 | namespace :inspeqtor do 2 | 3 | task(:install) {} 4 | 5 | task(:setup) {} 6 | 7 | [:"start deploy", :"finish deploy", :status].each do |command| 8 | desc "Inspeqtor #{command}" 9 | task command do 10 | queue %[echo "-----> Inspeqtor #{command}."] 11 | queue "inspeqtorctl #{command}" 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/templates/monit/puma.erb: -------------------------------------------------------------------------------- 1 | check process <%= puma_name %> with pidfile <%= puma_pid %> 2 | start program = "/sbin/start <%= puma_name %>" 3 | stop program = "/sbin/stop <%= puma_name %>" 4 | if cpu > 60% for 2 cycles then alert 5 | if cpu > 98% for 5 cycles then restart 6 | if 2 restarts within 3 cycles then timeout 7 | if totalmem is greater than 300 MB for 10 cycles then restart -------------------------------------------------------------------------------- /lib/templates/monit/memcached.erb: -------------------------------------------------------------------------------- 1 | check process memcached with pidfile <%= memcached_pid! %> 2 | start program = "/etc/init.d/memcached start" 3 | stop program = "/etc/init.d/memcached stop" 4 | if failed host 127.0.0.1 port 11211 then restart 5 | if cpu > 60% for 2 cycles then alert 6 | if cpu > 98% for 5 cycles then restart 7 | if 2 restarts within 3 cycles then timeout 8 | group cache -------------------------------------------------------------------------------- /lib/templates/monit/private_pub.erb: -------------------------------------------------------------------------------- 1 | check process <%= private_pub_name %> 2 | with pidfile <%= private_pub_pid %> 3 | start program = "<%= private_pub_start %>" with timeout 90 seconds 4 | stop program = "kill -s TERM `cat <%= private_pub_config %>`" with timeout 90 seconds 5 | if totalmem is greater than 200 MB for 2 cycles then restart # eating up memory? 6 | group <%= private_pub_name %> -------------------------------------------------------------------------------- /lib/recipes/bower.rb: -------------------------------------------------------------------------------- 1 | namespace :bower do 2 | 3 | desc "Install bower with dependencies" 4 | task :install do 5 | invoke :sudo 6 | queue %{echo "-----> Installing Bower..."} 7 | queue "sudo npm install -g bower" 8 | end 9 | 10 | task(:setup) { } 11 | 12 | desc "Install assets" 13 | task :install_assets do 14 | queue %{echo "-----> Installing Assets with Bower..."} 15 | queue "bower install" 16 | end 17 | 18 | end -------------------------------------------------------------------------------- /lib/recipes/node.rb: -------------------------------------------------------------------------------- 1 | namespace :node do 2 | desc "Install the latest relase of Node.js" 3 | task :install do 4 | invoke :sudo 5 | queue "sudo apt-get -y update" 6 | queue "sudo apt-get -y install software-properties-common python-software-properties python g++ make" 7 | queue "curl -sL https://deb.nodesource.com/setup_0.12 | sudo bash -" 8 | queue "sudo apt-get -y install nodejs" 9 | end 10 | task(:setup) { } 11 | end 12 | -------------------------------------------------------------------------------- /lib/recipes/libs.rb: -------------------------------------------------------------------------------- 1 | namespace :libs do 2 | 3 | desc "Install some important libs" 4 | task :install do 5 | invoke :sudo 6 | queue "sudo apt-get -y install curl libcurl3 libcurl3-dev" 7 | queue "sudo apt-get -y install libxml2 libxml2-dev libxslt-dev" 8 | queue "sudo apt-get -y install build-essential libssl-dev libcurl4-openssl-dev libreadline-dev libyaml-dev libffi-dev" 9 | 10 | end 11 | 12 | task(:setup) { } 13 | 14 | end 15 | -------------------------------------------------------------------------------- /lib/recipes/memcached.rb: -------------------------------------------------------------------------------- 1 | namespace :memcached do 2 | desc "Install Memcached" 3 | task :install do 4 | invoke :sudo 5 | queue "sudo apt-get -y install memcached" 6 | end 7 | 8 | desc "Setup Memcached" 9 | task :setup do 10 | # template "memcached.erb", "/tmp/memcached.conf" 11 | # run "#{sudo} mv /tmp/memcached.conf /etc/memcached.conf" 12 | # restart 13 | end 14 | 15 | %w[start stop restart].each do |command| 16 | desc "#{command} Memcached" 17 | task command do 18 | queue "sudo service memcached #{command}" 19 | end 20 | end 21 | end -------------------------------------------------------------------------------- /lib/templates/monit/monitrc.erb: -------------------------------------------------------------------------------- 1 | set daemon 30 2 | 3 | set logfile /var/log/monit.log 4 | set idfile /var/lib/monit/id 5 | set statefile /var/lib/monit/state 6 | 7 | set eventqueue 8 | basedir /var/lib/monit/events 9 | slots 100 10 | 11 | # set mailserver smtp.gmail.com port 587 12 | # username "foo@example.com" password "secret" 13 | # using tlsv1 14 | # with timeout 30 seconds 15 | 16 | # set alert foo@example.com 17 | 18 | set httpd port <%= monit_http_port %> 19 | allow <%= monit_http_username %>:"<%= monit_http_password %>" 20 | 21 | include /etc/monit/conf.d/* -------------------------------------------------------------------------------- /lib/templates/puma.rb.erb: -------------------------------------------------------------------------------- 1 | # Bind to a UNIX socket 2 | bind "unix://<%= puma_socket %>" 3 | activate_control_app "unix://<%= sockets_path %>/pumactl.sock" 4 | 5 | # not deamonizing here - still can use -d flag 6 | # daemonize true 7 | environment "<%= rails_env %>" 8 | directory '<%= "#{deploy_to!}/#{current_path!}" %>' 9 | pidfile "<%= puma_pid %>" 10 | state_path "<%= sockets_path %>/puma.state" 11 | stdout_redirect '<%= puma_log %>', '<%= puma_error_log %>', true 12 | 13 | workers <%= puma_workers %> 14 | prune_bundler 15 | 16 | # 0-16 threads for production environment 17 | # threads 0, 16 -------------------------------------------------------------------------------- /lib/recipes/rpush.rb: -------------------------------------------------------------------------------- 1 | namespace :rpush do 2 | 3 | task(:install) { } 4 | 5 | desc "Setup Puma configuration" 6 | task :setup => [:upload] 7 | 8 | desc "Create configuration and other files" 9 | task :upload do 10 | invoke :sudo 11 | template "upstart/rpush.conf.erb", "/tmp/rpush_conf" 12 | queue "sudo mv /tmp/rpush_conf #{rpush_upstart}" 13 | end 14 | 15 | %w[start stop restart reload].each do |command| 16 | desc "#{command.capitalize} rpush" 17 | task command do 18 | queue "sudo #{command} #{rpush_name}" 19 | queue %[echo "-----> #{command.capitalize} rpush."] 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/recipes/rails.rb: -------------------------------------------------------------------------------- 1 | namespace :rails do 2 | 3 | task(:install) { } 4 | task(:setup) { } 5 | 6 | task :log do 7 | queue 'echo "Contents of the log file are as follows:"' 8 | queue "tail -f #{logs_path}/#{rails_env}.log" 9 | end 10 | end 11 | 12 | 13 | 14 | # desc "Open the rails console on one of the remote servers" 15 | # task :console, :roles => :app do 16 | # queue %{ssh #{domain} -t "#{default_shell} -c 'cd #{current_path} && bundle exec rails c #{rails_env}'"} 17 | # end 18 | 19 | # desc "remote rake task" 20 | # task :rake do 21 | # run "cd #{deploy_to}/current; RAILS_ENV=#{rails_env} rake #{ENV['TASK']}" 22 | # end -------------------------------------------------------------------------------- /lib/generators/mina/templates/production.rb: -------------------------------------------------------------------------------- 1 | namespace :env do 2 | task :production => [:environment] do 3 | set :domain, '127.0.0.1' 4 | set :user, 'deployer' 5 | set :deploy_to, "/home/#{user}/apps/#{app}" 6 | set :repository, "/home/#{user}/git/#{app}" 7 | set :nginx_path, '/etc/nginx' 8 | set :deploy_server, 'production' # just a handy name of the server 9 | set :rails_env, 'production' 10 | set :branch, 'master' 11 | invoke :defaults # load rest of the config 12 | end 13 | end -------------------------------------------------------------------------------- /lib/recipes/phobos.rb: -------------------------------------------------------------------------------- 1 | namespace :phobos do 2 | 3 | task(:install) { } 4 | 5 | desc "Setup Phobos configuration" 6 | task :setup => [:upload] 7 | 8 | desc "Create configuration and other files" 9 | task :upload do 10 | invoke :sudo 11 | template "upstart/phobos.conf.erb", "/tmp/phobos_conf" 12 | queue "sudo mv /tmp/phobos_conf #{phobos_upstart}" 13 | end 14 | 15 | %w[start stop restart reload].each do |command| 16 | desc "#{command.capitalize} phobos" 17 | task command do 18 | queue "sudo #{command} #{phobos_name}" 19 | queue %[echo "-----> #{command.capitalize} phobos."] 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/recipes/unicorn.rb: -------------------------------------------------------------------------------- 1 | namespace :unicorn do 2 | 3 | task(:install) { } 4 | 5 | desc "Setup Unicorn initializer and app configuration" 6 | task :setup do 7 | invoke :sudo 8 | template "unicorn.rb.erb", unicorn_config 9 | template "unicorn_init.erb", "/tmp/unicorn_init" 10 | queue "chmod +x /tmp/unicorn_init" 11 | queue "sudo mv /tmp/unicorn_init #{unicorn_script}" 12 | queue "sudo update-rc.d -f #{unicorn_name} defaults" 13 | end 14 | 15 | %w[start stop restart].each do |command| 16 | desc "#{command} unicorn" 17 | task command do 18 | queue "service #{unicorn_name} #{command}" 19 | end 20 | end 21 | end -------------------------------------------------------------------------------- /lib/recipes/redis.rb: -------------------------------------------------------------------------------- 1 | namespace :redis do 2 | 3 | desc "Install the latest release of Redis" 4 | task :install do 5 | invoke :sudo 6 | queue %{echo "-----> Installing Redis..."} 7 | queue "sudo add-apt-repository -y ppa:chris-lea/redis-server --yes" 8 | queue "sudo apt-get -y update" 9 | queue "sudo apt-get -y install redis-server" 10 | end 11 | 12 | task(:setup) { } 13 | 14 | %w[start stop restart].each do |command| 15 | desc "#{command} redis" 16 | task command do 17 | invoke :sudo 18 | queue %{echo "-----> Trying to #{command} Redis..."} 19 | queue "#{sudo} service redis #{command}" 20 | end 21 | end 22 | 23 | end -------------------------------------------------------------------------------- /lib/templates/monit/unicorn.erb: -------------------------------------------------------------------------------- 1 | check process <%= unicorn_name %> with pidfile <%= unicorn_pid %> 2 | start program = "/etc/init.d/<%= unicorn_name %> start" 3 | stop program = "/etc/init.d/<%= unicorn_name %> stop" 4 | 5 | <% unicorn_workers.times do |n| %> 6 | <% pid = unicorn_pid.sub(".pid", ".#{n}.pid") %> 7 | check process <%= unicorn_name %>_worker_<%= n %> with pidfile <%= pid %> 8 | start program = "/bin/true" 9 | stop program = "/usr/bin/test -s <%= pid %> && /bin/kill -QUIT `cat <%= pid %>`" 10 | if mem > 200.0 MB for 1 cycles then restart 11 | if cpu > 50% for 3 cycles then restart 12 | if 5 restarts within 5 cycles then timeout 13 | if changed pid 2 times within 60 cycles then alert 14 | <% end %> -------------------------------------------------------------------------------- /lib/mina-stack/base.rb: -------------------------------------------------------------------------------- 1 | require 'erb' 2 | require 'shellwords' 3 | 4 | def template(from, to=nil) 5 | queue %{echo "-----> Put #{from} file to #{to}"} 6 | to ||= "#{config_path}/#{from.chomp(".erb")}" 7 | erb = File.read(File.expand_path("../../templates/#{from}", __FILE__)) 8 | put ERB.new(erb).result(binding), to 9 | end 10 | 11 | def put(content, file) 12 | queue %[echo #{escape content} > "#{file}"] 13 | end 14 | 15 | def escape(str) 16 | Shellwords.escape(str) 17 | end 18 | 19 | def check_symlink(destination) 20 | %{if [[ -h "#{destination}" ]]; #{check_response}} 21 | end 22 | 23 | def check_response 24 | 'then echo "-----> SUCCESS"; else echo "-----> FAILED"; fi' 25 | end 26 | 27 | 28 | task :sudo do 29 | set :sudo, true 30 | set :term_mode, :system # :pretty doesn't seem to work with sudo well 31 | end 32 | -------------------------------------------------------------------------------- /lib/recipes/puma.rb: -------------------------------------------------------------------------------- 1 | namespace :puma do 2 | 3 | task(:install) { } 4 | 5 | desc "Setup Puma configuration" 6 | task :setup => [:upload] 7 | 8 | desc "Create configuration and other files" 9 | task :upload do 10 | invoke :sudo 11 | template "puma.rb.erb", puma_config 12 | queue %[echo "-----> Be sure to edit #{puma_config}."] 13 | template "upstart/puma.conf.erb", "/tmp/puma_conf" 14 | queue "sudo mv /tmp/puma_conf #{puma_upstart}" 15 | end 16 | 17 | %w[start stop restart].each do |command| 18 | desc "#{command.capitalize} puma" 19 | task command do 20 | queue %[echo "-----> #{command.capitalize} puma."] 21 | queue "sudo #{command} #{puma_name}" 22 | end 23 | end 24 | 25 | desc "Phased-restart puma" 26 | task :'phased-restart' do 27 | queue %[echo "-----> Phased-restart puma."] 28 | queue "sudo reload #{puma_name}" 29 | end 30 | 31 | end 32 | -------------------------------------------------------------------------------- /mina-stack.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'mina-stack/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "mina-stack" 8 | spec.version = Mina::Stack::VERSION 9 | spec.authors = ["Igor Davydov"] 10 | spec.email = ["iskiche@gmail.com"] 11 | spec.description = %q{Easy deploy of rails app stack with mina on ubuntu servers} 12 | spec.summary = %q{Mina + stack} 13 | spec.homepage = "" 14 | spec.license = "MIT" 15 | 16 | spec.files = `git ls-files`.split($/) 17 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 18 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 19 | spec.require_paths = ["lib"] 20 | 21 | spec.add_dependency "rake" 22 | spec.add_dependency "mina", '<= 0.3.1' 23 | spec.add_dependency "highline" 24 | spec.add_development_dependency "bundler", "~> 1.3" 25 | end 26 | -------------------------------------------------------------------------------- /lib/recipes/sidekiq.rb: -------------------------------------------------------------------------------- 1 | namespace :sidekiq do 2 | 3 | task(:install) { } 4 | 5 | desc "Setup sidekiq configuration" 6 | task :setup => [:upload] 7 | 8 | desc "Create configuration and other files" 9 | task :upload do 10 | invoke :sudo 11 | template "sidekiq.yml.erb", sidekiq_config 12 | queue %[echo "-----> Be sure to edit #{sidekiq_config}."] 13 | template "upstart/sidekiq.conf.erb", "/tmp/sidekiq_conf" 14 | queue "sudo mv /tmp/sidekiq_conf #{sidekiq_upstart}" 15 | end 16 | 17 | 18 | desc "Quiet sidekiq (stop accepting new work)" 19 | task :quiet => :environment do 20 | queue %[echo "-----> Quiet sidekiq (stop accepting new work)."] 21 | queue "sudo reload #{sidekiq_name}" 22 | end 23 | 24 | 25 | %w[start stop restart].each do |command| 26 | desc "#{command.capitalize} sidekiq" 27 | task command => :environment do 28 | queue %[echo "-----> #{command.capitalize} sidekiq."] 29 | queue "sudo #{command} #{sidekiq_name}" 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/recipes/private_pub.rb: -------------------------------------------------------------------------------- 1 | namespace :private_pub do 2 | 3 | task(:install) { } 4 | 5 | desc "Setup Private Pub configuration" 6 | task :setup => [:upload] 7 | 8 | desc "Create configuration and other files" 9 | task :upload do 10 | template "private_pub.yml.erb", private_pub_config 11 | queue %[echo "-----> Be sure to edit #{private_pub_config}."] 12 | end 13 | 14 | desc "Stop Private Pub" 15 | task :stop do 16 | queue %[ if [ -f #{private_pub_pid} ]; then 17 | echo "-----> Stop Private Pub" 18 | kill -s QUIT `cat #{private_pub_pid}` || true 19 | fi ] 20 | end 21 | 22 | desc "Start Private Pub" 23 | task :start do 24 | queue %{ 25 | echo "-----> Start Private Pub" 26 | #{echo_cmd %[(cd #{deploy_to}/#{current_path}; #{private_pub_cmd} -s #{private_pub_server} -E #{rails_env} -P #{private_pub_pid} >> #{private_pub_log} 2>&1 Installing Ruby"} 7 | queue "sudo apt-get -y install curl git-core" 8 | queue "curl -fsSL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-installer | bash" 9 | bashrc = <<-BASHRC 10 | if [ -d $HOME/.rbenv ]; then 11 | export PATH="$HOME/.rbenv/bin:$PATH" 12 | eval "$(rbenv init -)" 13 | fi 14 | BASHRC 15 | put bashrc, "/tmp/rbenvrc" 16 | queue "cat /tmp/rbenvrc ~/.bashrc > ~/.bashrc.tmp" 17 | queue "mv ~/.bashrc.tmp ~/.bashrc" 18 | queue %q{export PATH="$HOME/.rbenv/bin:$PATH"} 19 | queue %q{eval "$(rbenv init -)"} 20 | queue "sudo apt-get -y install build-essential zlib1g-dev libssl-dev libreadline-gplv2-dev" 21 | queue "rbenv install #{ruby_version}" 22 | queue "rbenv global #{ruby_version}" 23 | queue "gem install bundler --no-ri --no-rdoc" 24 | queue "rbenv rehash" 25 | end 26 | 27 | task(:setup) { } 28 | end 29 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Igor Davydov 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /lib/templates/nginx.conf.erb: -------------------------------------------------------------------------------- 1 | <% rails_socket = server_stack.include?("puma") ? puma_socket : unicorn_socket %> 2 | upstream <%= app %> { 3 | server unix://<%= rails_socket %> fail_timeout=0; 4 | } 5 | 6 | server { 7 | # listen 80 default deferred; 8 | server_name <%= server_name %>; 9 | keepalive_timeout 5; 10 | 11 | root <%= deploy_to %>/<%= current_path %>/public; 12 | 13 | client_max_body_size 4G; 14 | 15 | if (-f $document_root/system/maintenance.html) { 16 | return 503; 17 | } 18 | 19 | error_page 503 @maintenance; 20 | location @maintenance { 21 | rewrite ^(.*)$ /system/maintenance.html last; 22 | break; 23 | } 24 | 25 | location ~ ^/(assets)/ { 26 | gzip_static on; 27 | expires max; 28 | add_header Cache-Control public; 29 | add_header Last-Modified ""; 30 | add_header ETag ""; 31 | } 32 | 33 | location @rails { 34 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 35 | proxy_set_header Host $http_host; 36 | proxy_redirect off; 37 | proxy_pass http://<%= app %>; 38 | } 39 | 40 | try_files $uri/index.html $uri @rails; 41 | 42 | error_page 500 502 503 504 /500.html; 43 | } 44 | -------------------------------------------------------------------------------- /lib/templates/unicorn.rb.erb: -------------------------------------------------------------------------------- 1 | rails_root = "<%= "#{deploy_to!}/#{current_path!}" %>" 2 | rails_env = "<%= rails_env %>" 3 | pid_file = "<%= unicorn_pid %>" 4 | socket_file= "<%= unicorn_socket %>" 5 | log_file = "<%= unicorn_log %>" 6 | err_log = "<%= unicorn_error_log %>" 7 | old_pid = pid_file + '.oldbin' 8 | 9 | timeout 60 10 | worker_processes <%= unicorn_workers %> 11 | 12 | # Listen on a Unix data socket 13 | listen socket_file, :backlog => 2048 14 | pid pid_file 15 | 16 | stderr_path err_log 17 | stdout_path log_file 18 | 19 | preload_app true 20 | 21 | GC.copy_on_write_friendly = true if GC.respond_to?(:copy_on_write_friendly=) 22 | 23 | before_exec do |server| 24 | ENV["BUNDLE_GEMFILE"] = "#{rails_root}/Gemfile" 25 | end 26 | 27 | before_fork do |server, worker| 28 | # Using this method we get 0 downtime deploys. 29 | if File.exists?(old_pid) && server.pid != old_pid 30 | begin 31 | Process.kill("QUIT", File.read(old_pid).to_i) 32 | rescue Errno::ENOENT, Errno::ESRCH 33 | # someone else did our job for us 34 | end 35 | end 36 | end 37 | 38 | after_fork do |server, worker| 39 | child_pid = server.config[:pid].sub('.pid', ".#{worker.nr}.pid") 40 | system("echo #{Process.pid} > #{child_pid}") 41 | end -------------------------------------------------------------------------------- /lib/generators/mina/stack/install_generator.rb: -------------------------------------------------------------------------------- 1 | require 'rails/generators/base' 2 | 3 | module Mina 4 | module Stack 5 | module Generators 6 | class InstallGenerator < Rails::Generators::Base 7 | 8 | source_root File.expand_path("../../templates", __FILE__) 9 | desc "Creates an deploy script and server config for your application." 10 | 11 | def do_all 12 | create_servers_directory 13 | copy_server_example 14 | copy_deploy_script 15 | message = <<-RUBY 16 | 17 | Install complete! See the README on Github for instructions on getting your 18 | deploy running with mina-stack. 19 | 20 | RUBY 21 | puts message.strip_heredoc 22 | 23 | end 24 | 25 | private 26 | 27 | def create_servers_directory 28 | # Creates empty directory if none; doesn't empty the directory 29 | empty_directory "config/servers" 30 | end 31 | 32 | def copy_server_example 33 | template "production.rb", "config/servers/production.rb" 34 | end 35 | 36 | def copy_deploy_script 37 | template "deploy.rb", "config/deploy.rb" 38 | end 39 | 40 | end 41 | end 42 | end 43 | end -------------------------------------------------------------------------------- /lib/recipes/elastic_search.rb: -------------------------------------------------------------------------------- 1 | namespace :es do 2 | 3 | desc "Install the latest release of ElasticSearch" 4 | task :install do 5 | invoke :sudo 6 | queue %{echo "-----> Installing ElasticSearch..."} 7 | queue "sudo apt-get install openjdk-7-jre -y" 8 | queue "wget https://github.com/downloads/elasticsearch/elasticsearch/elasticsearch-0.19.1.tar.gz -O elasticsearch.tar.gz" 9 | queue "tar -xf elasticsearch.tar.gz" 10 | queue "rm elasticsearch.tar.gz" 11 | queue "sudo mv elasticsearch-* elasticsearch" 12 | queue "sudo mv elasticsearch /usr/local/share" 13 | 14 | queue "curl -L http://github.com/elasticsearch/elasticsearch-servicewrapper/tarball/master | tar -xz" 15 | queue "mv *servicewrapper*/service /usr/local/share/elasticsearch/bin/" 16 | queue "rm -Rf *servicewrapper*" 17 | queue "sudo /usr/local/share/elasticsearch/bin/service/elasticsearch install" 18 | queue "sudo ln -s `readlink -f /usr/local/share/elasticsearch/bin/service/elasticsearch` /usr/local/bin/rcelasticsearch" 19 | end 20 | 21 | task(:setup) { } 22 | 23 | %w[start stop restart].each do |command| 24 | desc "#{command} elasticsearch" 25 | task command do 26 | invoke :sudo 27 | queue "sudo service elasticsearch #{command}" 28 | end 29 | end 30 | 31 | end -------------------------------------------------------------------------------- /lib/templates/upstart/rpush.conf.erb: -------------------------------------------------------------------------------- 1 | description "Rpush Worker" 2 | 3 | start on runlevel [2345] and started networking 4 | stop on runlevel [!2345] or stopped networking 5 | 6 | setuid <%= user %> 7 | setgid <%= user %> 8 | 9 | respawn 10 | respawn limit 3 30 11 | 12 | script 13 | # this script runs in /bin/sh by default 14 | # respawn as bash so we can source in rbenv 15 | exec /bin/bash <<'EOT' 16 | # set HOME to the setuid user's home, there doesn't seem to be a better, portable way 17 | export HOME="$(eval echo ~$(id -un))" 18 | 19 | if [ -d "$HOME/.rbenv/bin" ]; then 20 | export PATH="$HOME/.rbenv/bin:$HOME/.rbenv/shims:$PATH" 21 | elif [ -f /etc/profile.d/rvm.sh ]; then 22 | source /etc/profile.d/rvm.sh 23 | elif [ -f /usr/local/rvm/scripts/rvm ]; then 24 | source /etc/profile.d/rvm.sh 25 | elif [ -f "$HOME/.rvm/scripts/rvm" ]; then 26 | source "$HOME/.rvm/scripts/rvm" 27 | elif [ -f /usr/local/share/chruby/chruby.sh ]; then 28 | source /usr/local/share/chruby/chruby.sh 29 | if [ -f /usr/local/share/chruby/auto.sh ]; then 30 | source /usr/local/share/chruby/auto.sh 31 | fi 32 | # if you aren't using auto, set your version here 33 | # chruby 2.0.0 34 | fi 35 | 36 | # Logs out to /var/log/upstart/<%= rpush_name %>.log by default 37 | 38 | cd <%= "#{deploy_to!}/#{current_path!}" %> 39 | exec <%= rpush_start %> 40 | EOT 41 | end script 42 | -------------------------------------------------------------------------------- /lib/templates/upstart/phobos.conf.erb: -------------------------------------------------------------------------------- 1 | description "Phobos Process" 2 | 3 | start on runlevel [2345] and started networking 4 | stop on runlevel [!2345] or stopped networking 5 | 6 | setuid <%= user %> 7 | setgid <%= user %> 8 | 9 | respawn 10 | respawn limit 3 30 11 | 12 | script 13 | # this script runs in /bin/sh by default 14 | # respawn as bash so we can source in rbenv 15 | exec /bin/bash <<'EOT' 16 | # set HOME to the setuid user's home, there doesn't seem to be a better, portable way 17 | export HOME="$(eval echo ~$(id -un))" 18 | 19 | if [ -d "$HOME/.rbenv/bin" ]; then 20 | export PATH="$HOME/.rbenv/bin:$HOME/.rbenv/shims:$PATH" 21 | elif [ -f /etc/profile.d/rvm.sh ]; then 22 | source /etc/profile.d/rvm.sh 23 | elif [ -f /usr/local/rvm/scripts/rvm ]; then 24 | source /etc/profile.d/rvm.sh 25 | elif [ -f "$HOME/.rvm/scripts/rvm" ]; then 26 | source "$HOME/.rvm/scripts/rvm" 27 | elif [ -f /usr/local/share/chruby/chruby.sh ]; then 28 | source /usr/local/share/chruby/chruby.sh 29 | if [ -f /usr/local/share/chruby/auto.sh ]; then 30 | source /usr/local/share/chruby/auto.sh 31 | fi 32 | # if you aren't using auto, set your version here 33 | # chruby 2.0.0 34 | fi 35 | 36 | # Logs out to /var/log/upstart/<%= phobos_name %>.log by default 37 | 38 | export RAILS_ENV=<%= rails_env %> 39 | cd <%= "#{deploy_to!}/#{current_path!}" %> 40 | exec <%= phobos_start %> 41 | EOT 42 | end script 43 | -------------------------------------------------------------------------------- /lib/templates/upstart/puma.conf.erb: -------------------------------------------------------------------------------- 1 | # /etc/init/puma.conf - Puma config 2 | 3 | # This example config should work with Ubuntu 12.04+. It 4 | # allows you to manage multiple Puma instances with 5 | # Upstart, Ubuntu's native service management tool. 6 | 7 | description "Puma Server" 8 | 9 | start on runlevel [2345] 10 | stop on runlevel [06] 11 | 12 | reload signal USR1 13 | normal exit 0 TERM 14 | 15 | setuid <%= user %> 16 | setgid <%= user %> 17 | 18 | respawn 19 | respawn limit 3 30 20 | 21 | script 22 | # this script runs in /bin/sh by default 23 | # respawn as bash so we can source in rbenv/rvm 24 | exec /bin/bash <<'EOT' 25 | # set HOME to the setuid user's home, there doesn't seem to be a better, portable way 26 | export HOME="$(eval echo ~$(id -un))" 27 | 28 | if [ -d "$HOME/.rbenv/bin" ]; then 29 | export PATH="$HOME/.rbenv/bin:$HOME/.rbenv/shims:$PATH" 30 | elif [ -f /etc/profile.d/rvm.sh ]; then 31 | source /etc/profile.d/rvm.sh 32 | elif [ -f /usr/local/rvm/scripts/rvm ]; then 33 | source /etc/profile.d/rvm.sh 34 | elif [ -f "$HOME/.rvm/scripts/rvm" ]; then 35 | source "$HOME/.rvm/scripts/rvm" 36 | elif [ -f /usr/local/share/chruby/chruby.sh ]; then 37 | source /usr/local/share/chruby/chruby.sh 38 | if [ -f /usr/local/share/chruby/auto.sh ]; then 39 | source /usr/local/share/chruby/auto.sh 40 | fi 41 | # if you aren't using auto, set your version here 42 | # chruby 2.0.0 43 | fi 44 | 45 | # Logs out to /var/log/upstart/<%= puma_name %>.log by default 46 | 47 | cd <%= "#{deploy_to!}/#{current_path!}" %> 48 | exec <%= puma_start %> 49 | EOT 50 | end script 51 | -------------------------------------------------------------------------------- /lib/recipes/nginx.rb: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # nginx Tasks 3 | ########################################################################### 4 | 5 | namespace :nginx do 6 | 7 | desc "Install latest stable release of nginx" 8 | task :install do 9 | invoke :sudo 10 | queue "sudo add-apt-repository ppa:nginx/stable --yes" 11 | queue "sudo apt-get -y update" 12 | queue "sudo apt-get -y install nginx" 13 | end 14 | 15 | desc "Upload and update (link) all nginx config file" 16 | task :setup => [:upload, :link, :reload] 17 | 18 | desc "Symlink config file" 19 | task :link do 20 | invoke :sudo 21 | queue %{echo "-----> Symlink nginx config file"} 22 | queue echo_cmd %{sudo ln -fs "#{config_path}/nginx.conf" "#{nginx_config}"} 23 | queue check_symlink nginx_config 24 | queue echo_cmd %{sudo ln -fs "#{config_path}/nginx.conf" "#{nginx_config_e}"} 25 | queue check_symlink nginx_config_e 26 | end 27 | 28 | desc "Parses nginx config file and uploads it to server" 29 | task :upload do 30 | template 'nginx.conf.erb', "#{config_path}/nginx.conf" 31 | end 32 | 33 | desc "Parses config file and outputs it to STDOUT (local task)" 34 | task :parse do 35 | puts "#"*80 36 | puts "# nginx.conf" 37 | puts "#"*80 38 | puts erb("#{config_templates_path}/nginx.conf.erb") 39 | end 40 | 41 | %w(stop start restart reload status).each do |action| 42 | desc "#{action.capitalize} Nginx" 43 | task action.to_sym do 44 | invoke :sudo 45 | queue %{echo "-----> #{action.capitalize} Nginx"} 46 | queue echo_cmd "sudo service nginx #{action}" 47 | end 48 | end 49 | end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | mina-stack 2 | =========== 3 | 4 | A compilation of several deploy scripts that I use for my rails apps. The stack I use is pretty standart, 5 | but it may not suit your needs, so its not for everybody. 6 | Current stack includes Nginx, Postgres, rbenv, Redis, Unicorn, Puma, 7 | Sidekiq, Memcached, Imagemagick, ElasticSearch, Bower and Monit. 8 | 9 | ## Installation 10 | 11 | ``` 12 | gem 'mina-stack', github: 'div/mina-stack', group: :development 13 | ``` 14 | 15 | ``` 16 | rails g mina:stack:install 17 | ``` 18 | to create default deploy.rb and servers/production.rb files 19 | 20 | ## Configuration 21 | 22 | In your config/deploy.rb you can configure your stack - you may want to exclude something you may not need e.g. Private Pub, 23 | and choose app server - unicorn and puma are supported. It is done by setting server_stack array, example config can be found in examples/deploy.rb. 24 | 25 | All the default settings can be fond in lib/mina-stack/defaults.rb and can be overriden in deploy.rb 26 | 27 | ## Servers 28 | 29 | Servers configs live in config/servers - example config is in examples/production.rb 30 | 31 | ## Monitoring 32 | 33 | You can also set with services of your stack will be monitored by Monit - just use monitored array. 34 | 35 | ## Deploy 36 | 37 | Create user on server 38 | ``` 39 | sudo adduser deploy 40 | sudo adduser deploy sudo 41 | su deploy 42 | ``` 43 | then copy your ssh keys 44 | ``` 45 | ssh-copy-id deploy@IPADDRESS 46 | ``` 47 | Install all the stack to the server 48 | ``` 49 | bundle exec mina install 50 | ``` 51 | Create folder structure and copy all configs 52 | ``` 53 | bundle exec mina setup 54 | ``` 55 | Create db and set password 56 | ``` 57 | bundle exec mina postgresql:create_db 58 | ``` 59 | Deploy 60 | ``` 61 | bundle exec mina deploy 62 | ``` 63 | -------------------------------------------------------------------------------- /lib/mina-stack/setup.rb: -------------------------------------------------------------------------------- 1 | 2 | %w(install setup).each do |action| 3 | desc "#{action.capitalize} Server Stack Services" 4 | task action.to_sym => :environment do 5 | if action.to_sym == :setup 6 | invoke :create_extra_paths 7 | # invoke :create_config_files 8 | else 9 | invoke :'libs:install' 10 | end 11 | server_stack.each do |service| 12 | invoke :"#{service}:#{action}" 13 | end 14 | end 15 | end 16 | 17 | desc 'Create extra paths for shared configs, pids, sockets, etc.' 18 | task :create_extra_paths do 19 | queue 'echo "-----> Create configs path"' 20 | queue echo_cmd "mkdir -p #{config_path}" 21 | 22 | queue 'echo "-----> Create shared paths"' 23 | shared_paths.each do |p| 24 | queue echo_cmd "mkdir -p #{deploy_to}/#{shared_path}/#{p}" unless p.include?(".") 25 | end 26 | 27 | shared_dirs = shared_paths.map { |file| File.dirname("#{deploy_to}/#{shared_path}/#{file}") }.uniq 28 | shared_dirs.map do |dir| 29 | queue echo_cmd %{mkdir -p "#{dir}"} 30 | end 31 | 32 | queue 'echo "-----> Create PID and Sockets paths"' 33 | queue echo_cmd "mkdir -p #{pids_path} && chown #{user}:#{group} #{pids_path} && chmod +rw #{pids_path}" 34 | queue echo_cmd "mkdir -p #{sockets_path} && chown #{user}:#{group} #{sockets_path} && chmod +rw #{sockets_path}" 35 | 36 | if monitored.any? 37 | queue 'echo "-----> Create Monit dir"' 38 | queue echo_cmd "mkdir -p #{config_path}/monit && chown #{user}:#{group} #{config_path}/monit && chmod +rw #{config_path}/monit" 39 | monitored.each do |p| 40 | path = "#{config_path}/monit/#{p}" 41 | queue echo_cmd "mkdir -p #{path} && chown #{user}:#{group} #{path} && chmod +rw #{path}" 42 | end 43 | end 44 | end 45 | 46 | desc 'Create config files' 47 | task :create_config_files do 48 | template "secrets.yml.erb" 49 | queue %[echo "-----> Be sure to edit 'shared/config/secrets.yml'."] 50 | end 51 | -------------------------------------------------------------------------------- /lib/recipes/monit.rb: -------------------------------------------------------------------------------- 1 | namespace :monit do 2 | 3 | desc "Install Monit" 4 | task :install do 5 | invoke :sudo 6 | queue %{echo "-----> Installing Monit..."} 7 | queue "sudo apt-get -y install monit" 8 | end 9 | 10 | desc "Setup all Monit configuration" 11 | task :setup do 12 | invoke :sudo 13 | if monitored.any? 14 | queue %{echo "-----> Setting up Monit..."} 15 | monitored.each do |daemon| 16 | invoke :"monit:#{daemon}" 17 | end 18 | invoke :'monit:syntax' 19 | invoke :'monit:restart' 20 | else 21 | queue %{echo "-----> Skiping monit - nothing is set for monitoring..."} 22 | end 23 | end 24 | 25 | task(:nginx) { monit_config "nginx" } 26 | task(:postgresql) { monit_config "postgresql" } 27 | task(:redis) { monit_config "redis" } 28 | task(:memcached) { monit_config "memcached" } 29 | task(:puma) { monit_config "puma", "#{puma_name}" } 30 | task(:unicorn) { monit_config "unicorn", "#{unicorn_name}" } 31 | task(:sidekiq) { monit_config "sidekiq", "#{sidekiq_name}" } 32 | task(:private_pub) { monit_config "private_pub", "#{private_pub_name}" } 33 | 34 | %w[start stop restart syntax reload].each do |command| 35 | desc "Run Monit #{command} script" 36 | task command do 37 | invoke :sudo 38 | queue %{echo "-----> Monit #{command}"} 39 | queue "sudo service monit #{command}" 40 | end 41 | end 42 | end 43 | 44 | def monit_config(original_name, destination_name = nil) 45 | destination_name ||= origin_name 46 | path ||= monit_config_path 47 | destination = "#{path}/#{destination_name}" 48 | template "monit/#{original_name}.erb", "#{config_path}/monit/#{original_name}" 49 | queue echo_cmd %{sudo ln -fs "#{config_path}/monit/#{original_name}" "#{destination}"} 50 | queue check_symlink destination 51 | # queue "sudo mv /tmp/monit_#{original_name} #{destination}" 52 | # queue "sudo chown root #{destination}" 53 | # queue "sudo chmod 600 #{destination}" 54 | end -------------------------------------------------------------------------------- /lib/recipes/postgresql.rb: -------------------------------------------------------------------------------- 1 | namespace :postgresql do 2 | 3 | require 'highline/import' 4 | 5 | desc "Install the latest stable release of PostgreSQL." 6 | task :install do 7 | invoke :sudo 8 | queue "sudo apt-get -y update" 9 | queue "sudo apt-get -y install postgresql-#{postgresql_version} postgresql-contrib libpq-dev" 10 | end 11 | 12 | task :setup => [:upload] 13 | 14 | desc "Create configuration and other files" 15 | task :upload do 16 | template "database.yml.erb" 17 | queue %[echo "-----> Be sure to edit 'shared/config/database.yml'."] 18 | end 19 | 20 | desc "Create database" 21 | task :create_db do 22 | queue %{echo "-----> Create database"} 23 | invoke :sudo 24 | ask "PostgreSQL password:" do |psql_password| 25 | psql_password.echo = "x" 26 | queue echo_cmd %{sudo -u postgres psql -c "create user #{psql_user} with password '#{psql_password}';"} 27 | queue echo_cmd %{sudo -u postgres psql -c "create database #{psql_database} owner #{psql_user};"} 28 | end 29 | end 30 | 31 | RYAML = <<-BASH 32 | function ryaml { 33 | ruby -ryaml -e 'puts ARGV[1..-1].inject(YAML.load(File.read(ARGV[0]))) {|acc, key| acc[key] }' "$@" 34 | }; 35 | BASH 36 | 37 | desc 'Pull remote db in development' 38 | task :pull do 39 | code = isolate do 40 | invoke :environment 41 | queue RYAML 42 | queue "USERNAME=$(ryaml #{config_path!}/database.yml #{rails_env!} username)" 43 | queue "PASSWORD=$(ryaml #{config_path!}/database.yml #{rails_env!} password)" 44 | queue "DATABASE=$(ryaml #{config_path!}/database.yml #{rails_env!} database)" 45 | queue %{echo "-----> Database $DATABASE will be dumped locally"} 46 | queue "PGPASSWORD=$PASSWORD pg_dump -w -U $USERNAME $DATABASE -f #{tmp_path}/dump.sql" 47 | queue "gzip -f #{tmp_path}/dump.sql" 48 | run! 49 | end 50 | 51 | %x[scp #{user}@#{domain}:#{tmp_path}/dump.sql.gz .] 52 | %x[gunzip -f dump.sql.gz] 53 | %x[#{RYAML} psql -d $(ryaml config/database.yml development database) -f dump.sql] 54 | %x[rm dump.sql] 55 | end 56 | 57 | end 58 | -------------------------------------------------------------------------------- /lib/templates/unicorn_init.erb: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: unicorn 4 | # Required-Start: $remote_fs $syslog 5 | # Required-Stop: $remote_fs $syslog 6 | # Default-Start: 2 3 4 5 7 | # Default-Stop: 0 1 6 8 | # Short-Description: Manage unicorn server 9 | # Description: Start, stop, restart unicorn server for a specific application. 10 | ### END INIT INFO 11 | set -e 12 | 13 | # Feel free to change any of the following variables for your app: 14 | TIMEOUT=60 15 | APP_ROOT="<%= "#{deploy_to!}/#{current_path!}" %>" 16 | PID="<%= unicorn_pid %>" 17 | CMD="<%= unicorn_cmd %>" 18 | AS_USER="<%= unicorn_user %>" 19 | ENVIRONMENT="<%= rails_env %>" 20 | CONFIG="<%= unicorn_config %>" 21 | set -u 22 | 23 | OLD_PIN="$PID.oldbin" 24 | 25 | sig () { 26 | test -s "$PID" && kill -$1 `cat $PID` 27 | } 28 | 29 | oldsig () { 30 | test -s $OLD_PIN && kill -$1 `cat $OLD_PIN` 31 | } 32 | 33 | run () { 34 | if [ "$(id -un)" = "$AS_USER" ]; then 35 | eval $1 36 | else 37 | su -c "$1" - $AS_USER 38 | fi 39 | } 40 | 41 | case "$1" in 42 | start) 43 | sig 0 && echo >&2 "Already running" && exit 0 44 | run "$CMD" 45 | ;; 46 | stop) 47 | sig QUIT && exit 0 48 | echo >&2 "Not running" 49 | ;; 50 | force-stop) 51 | sig TERM && exit 0 52 | echo >&2 "Not running" 53 | ;; 54 | restart|reload) 55 | sig USR2 && echo reloaded OK && exit 0 56 | echo >&2 "Couldn't reload, starting '$CMD' instead" 57 | run "$CMD" 58 | ;; 59 | upgrade) 60 | if sig USR2 && sleep 2 && sig 0 && oldsig QUIT 61 | then 62 | n=$TIMEOUT 63 | while test -s $OLD_PIN && test $n -ge 0 64 | do 65 | printf '.' && sleep 1 && n=$(( $n - 1 )) 66 | done 67 | echo 68 | 69 | if test $n -lt 0 && test -s $OLD_PIN 70 | then 71 | echo >&2 "$OLD_PIN still exists after $TIMEOUT seconds" 72 | exit 1 73 | fi 74 | exit 0 75 | fi 76 | echo >&2 "Couldn't upgrade, starting '$CMD' instead" 77 | run "$CMD" 78 | ;; 79 | reopen-logs) 80 | sig USR1 81 | ;; 82 | *) 83 | echo >&2 "Usage: $0 " 84 | exit 1 85 | ;; 86 | esac -------------------------------------------------------------------------------- /lib/templates/upstart/sidekiq.conf.erb: -------------------------------------------------------------------------------- 1 | # /etc/init/sidekiq.conf - Sidekiq config 2 | 3 | # This example config should work with Ubuntu 12.04+. It 4 | # allows you to manage multiple Sidekiq instances with 5 | # Upstart, Ubuntu's native service management tool. 6 | # 7 | # See workers.conf for how to manage all Sidekiq instances at once. 8 | # 9 | # Save this config as /etc/init/sidekiq.conf then manage sidekiq with: 10 | # sudo start sidekiq index=0 11 | # sudo stop sidekiq index=0 12 | # sudo status sidekiq index=0 13 | # 14 | # Hack Upstart's reload command to 'quiet' Sidekiq: 15 | # 16 | # sudo reload sidekiq index=0 17 | # 18 | # or use the service command: 19 | # sudo service sidekiq {start,stop,restart,status} 20 | # 21 | 22 | description "Sidekiq Background Worker" 23 | 24 | start on runlevel [2345] 25 | stop on runlevel [06] 26 | 27 | setuid <%= user %> 28 | setgid <%= user %> 29 | 30 | respawn 31 | respawn limit 3 30 32 | 33 | # TERM is sent by sidekiqctl when stopping sidekiq. Without declaring these as 34 | # normal exit codes, it just respawns. 35 | normal exit 0 TERM 36 | 37 | # Older versions of Upstart might not support the reload command and need 38 | # this commented out. 39 | reload signal USR1 40 | 41 | script 42 | # this script runs in /bin/sh by default 43 | # respawn as bash so we can source in rbenv 44 | exec /bin/bash <<'EOT' 45 | # set HOME to the setuid user's home, there doesn't seem to be a better, portable way 46 | export HOME="$(eval echo ~$(id -un))" 47 | 48 | if [ -d "$HOME/.rbenv/bin" ]; then 49 | export PATH="$HOME/.rbenv/bin:$HOME/.rbenv/shims:$PATH" 50 | elif [ -f /etc/profile.d/rvm.sh ]; then 51 | source /etc/profile.d/rvm.sh 52 | elif [ -f /usr/local/rvm/scripts/rvm ]; then 53 | source /etc/profile.d/rvm.sh 54 | elif [ -f "$HOME/.rvm/scripts/rvm" ]; then 55 | source "$HOME/.rvm/scripts/rvm" 56 | elif [ -f /usr/local/share/chruby/chruby.sh ]; then 57 | source /usr/local/share/chruby/chruby.sh 58 | if [ -f /usr/local/share/chruby/auto.sh ]; then 59 | source /usr/local/share/chruby/auto.sh 60 | fi 61 | # if you aren't using auto, set your version here 62 | # chruby 2.0.0 63 | fi 64 | 65 | # Logs out to /var/log/upstart/<%= sidekiq_name %>.log by default 66 | 67 | cd <%= "#{deploy_to!}/#{current_path!}" %> 68 | exec <%= sidekiq_start %> 69 | EOT 70 | end script 71 | -------------------------------------------------------------------------------- /lib/generators/mina/templates/deploy.rb: -------------------------------------------------------------------------------- 1 | require 'mina/bundler' 2 | require 'mina/rails' 3 | require 'mina/git' 4 | require 'mina/rbenv' 5 | require 'mina-stack' 6 | 7 | set :app, 'example' 8 | set :server_name, 'example.com' 9 | set :keep_releases, 9999 10 | set :default_server, :production 11 | set :server, ENV['to'] || default_server 12 | invoke :"env:#{server}" 13 | 14 | # Allow calling as `mina deploy at=master` 15 | set :branch, ENV['at'] if ENV['at'] 16 | 17 | set :server_stack, %w( 18 | nginx 19 | postgresql 20 | redis 21 | rbenv 22 | puma 23 | sidekiq 24 | private_pub 25 | elastic_search 26 | imagemagick 27 | memcached 28 | monit 29 | node 30 | bower 31 | ) 32 | 33 | set :shared_paths, %w( 34 | tmp 35 | log 36 | config/puma.rb 37 | config/database.yml 38 | config/application.yml 39 | config/sidekiq.yml 40 | public/uploads 41 | ) 42 | 43 | set :monitored, %w( 44 | nginx 45 | postgresql 46 | redis 47 | puma 48 | sidekiq 49 | private_pub 50 | memcached 51 | ) 52 | 53 | task :environment do 54 | invoke :'rbenv:load' 55 | end 56 | 57 | desc "Deploys the current version to the server." 58 | task :deploy do 59 | deploy do 60 | invoke :'sidekiq:quiet' 61 | invoke :'git:clone' 62 | invoke :'deploy:link_shared_paths' 63 | invoke :'bundle:install' 64 | invoke :'rails:db_migrate' 65 | invoke :'bower:install_assets' 66 | invoke :'rails:assets_precompile' 67 | 68 | to :launch do 69 | invoke :'puma:restart' 70 | invoke :'sidekiq:restart' 71 | invoke :'private_pub:restart' 72 | end 73 | end 74 | end -------------------------------------------------------------------------------- /lib/mina-stack/defaults.rb: -------------------------------------------------------------------------------- 1 | task :defaults do 2 | set_default :ruby_version, "2.2.3" 3 | set_default :services_path, "/etc/init.d" 4 | set_default :upstart_path, "/etc/init" 5 | set_default :tmp_path, "#{deploy_to}/#{shared_path}/tmp" 6 | set_default :sockets_path, "#{tmp_path}/sockets" 7 | set_default :pids_path, "#{tmp_path}/pids" 8 | set_default :logs_path, "#{deploy_to}/#{shared_path}/log" 9 | set_default :config_path, "#{deploy_to}/#{shared_path}/config" 10 | set_default :app_namespace, "#{app!}_#{rails_env!}" 11 | set_default :bundle, "cd #{deploy_to}/#{current_path} && #{bundle_bin}" 12 | 13 | set_default :term_mode, :pretty 14 | 15 | set_default :psql_user, "#{app!}" 16 | set_default :psql_database, "#{app_namespace}" 17 | set_default :postgresql_version, "9.4" 18 | set_default :postgresql_pid, "/var/run/postgresql/#{postgresql_version}-main.pid" 19 | 20 | set_default :memcached_pid, "/var/run/memcached.pid" 21 | 22 | set_default :puma_name, "puma_#{app_namespace!}" 23 | set_default :puma_cmd, lambda { "#{bundle_bin} exec puma" } 24 | set_default :pumactl_cmd, lambda { "#{bundle_bin} exec pumactl" } 25 | set_default :puma_config, "#{config_path}/puma.rb" 26 | set_default :puma_pid, "#{pids_path}/puma.pid" 27 | set_default :puma_log, "#{logs_path}/puma.log" 28 | set_default :puma_error_log, "#{logs_path}/puma.err.log" 29 | set_default :puma_socket, "#{sockets_path}/puma.sock" 30 | set_default :puma_state, "#{sockets_path}/puma.state" 31 | set_default :puma_upstart, "#{upstart_path!}/#{puma_name}.conf" 32 | set_default :puma_workers, 2 33 | set_default :puma_start, "#{puma_cmd} -C #{puma_config}" 34 | 35 | set_default :unicorn_name, "unicorn_#{app_namespace!}" 36 | set_default :unicorn_socket, "#{sockets_path}/unicorn.sock" 37 | set_default :unicorn_pid, "#{pids_path}/unicorn.pid" 38 | set_default :unicorn_config, "#{config_path}/unicorn.rb" 39 | set_default :unicorn_log, "#{logs_path}/unicorn.log" 40 | set_default :unicorn_error_log, "#{logs_path}/unicorn.error.log" 41 | set_default :unicorn_script, "#{services_path!}/#{unicorn_name}" 42 | set_default :unicorn_workers, 1 43 | set_default :unicorn_bin, lambda { "#{bundle_bin} exec unicorn" } 44 | set_default :unicorn_cmd, "cd #{deploy_to}/#{current_path} && #{unicorn_bin} -D -c #{unicorn_config} -E #{rails_env}" 45 | set_default :unicorn_user, user 46 | set_default :unicorn_group, user 47 | 48 | set_default :nginx_pid, "/var/run/nginx.pid" 49 | set_default :nginx_config, "#{nginx_path!}/sites-available/#{app_namespace!}.conf" 50 | set_default :nginx_config_e, "#{nginx_path!}/sites-enabled/#{app_namespace!}.conf" 51 | 52 | set_default :sidekiq_name, "sidekiq_#{app_namespace!}" 53 | set_default :sidekiq_cmd, lambda { "#{bundle_bin} exec sidekiq" } 54 | set_default :sidekiqctl_cmd, lambda { "#{bundle_prefix} sidekiqctl" } 55 | set_default :sidekiq_timeout, 10 56 | set_default :sidekiq_config, "#{config_path}/sidekiq.yml" 57 | set_default :sidekiq_log, "#{logs_path}/sidekiq.log" 58 | set_default :sidekiq_pid, "#{pids_path}/sidekiq.pid" 59 | set_default :sidekiq_concurrency, 25 60 | set_default :sidekiq_start, "#{sidekiq_cmd} -e #{rails_env} -C #{sidekiq_config}" 61 | set_default :sidekiq_upstart, "#{upstart_path!}/#{sidekiq_name}.conf" 62 | 63 | set_default :private_pub_name, "private_pub_#{app_namespace}" 64 | set_default :private_pub_cmd, lambda { "#{bundle_prefix} rackup private_pub.ru" } 65 | set_default :private_pub_pid, "#{pids_path}/private_pub.pid" 66 | set_default :private_pub_config, "#{config_path}/private_pub.yml" 67 | set_default :private_pub_log, "#{logs_path}/private_pub.log" 68 | 69 | set_default :rpush_name, "rpush_#{app_namespace!}" 70 | set_default :rpush_cmd, lambda { "#{bundle_bin} exec rpush" } 71 | set_default :rpush_upstart, "#{upstart_path!}/#{rpush_name}.conf" 72 | set_default :rpush_start, "#{rpush_cmd} start -f -e #{rails_env}" 73 | 74 | set_default :phobos_name, "phobos_#{app_namespace!}" 75 | set_default :phobos_cmd, lambda { "#{bundle_bin} exec phobos" } 76 | set_default :phobos_upstart, "#{upstart_path!}/#{phobos_name}.conf" 77 | set_default :phobos_boot_file, "config/phobos_boot.rb" 78 | set_default :phobos_config_file, "config/phobos.yml" 79 | set_default :phobos_start, "#{phobos_cmd} start -b #{phobos_boot_file} -c #{phobos_config_file}" 80 | 81 | set_default :monit_config_path, "/etc/monit/conf.d" 82 | set_default :monit_http_port, 2812 83 | set_default :monit_http_username, "PleaseChangeMe_monit" 84 | set_default :monit_http_password, "PleaseChangeMe" 85 | 86 | set_default :shared_paths, %w( 87 | tmp 88 | log 89 | public/uploads 90 | ) 91 | 92 | set_default :monitored, %w( 93 | nginx 94 | postgresql 95 | redis 96 | puma 97 | sidekiq 98 | private_pub 99 | memcached 100 | ) 101 | 102 | set_default :server_stack, %w( 103 | nginx 104 | postgresql 105 | redis 106 | rails 107 | rbenv 108 | puma 109 | sidekiq 110 | private_pub 111 | elastic_search 112 | imagemagick 113 | memcached 114 | monit 115 | bower 116 | node 117 | ) 118 | 119 | end 120 | --------------------------------------------------------------------------------