Skip to content

Instantly share code, notes, and snippets.

@marianposaceanu
Last active March 27, 2020 15:51
Show Gist options
  • Save marianposaceanu/5891863 to your computer and use it in GitHub Desktop.
Save marianposaceanu/5891863 to your computer and use it in GitHub Desktop.
Setting up Unicorn to run via init.d

Unicorn via init.d

You have your Rails Apps with specific Gemsets in RVM.

The following commands creates a wrapped unicorn_rails bin. Be sure to replace the variables and that you have unicorn in your bundle.

rvmsudo rvm wrapper [RUBY VERSION]@[GEMSET] [GEMSET] unicorn_rails

Now you have a /usr/local/rvm/bin/[GEMSET]_unicorn_rails I will refer to [GEMSET]_unicorn_rails as [WRAPPED_NAME]

Create the other files now, especially /etc/init.d/unicorn_init

sudo update-rc.d unicorn_init defaults

Mixed credits

#!/bin/bash
### BEGIN INIT INFO
# Provides: marianposaceanu.com
# Required-Start: $all
# Required-Stop: $network $local_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start the APPLICATION unicorns at boot
# Description: Enable marianposaceanu.com at boot time.
### END INIT INFO
set -u
set -e
# Change these to match your app:
APP_ROOT="/webapps/acn-docker"
PID="$APP_ROOT/tmp/pids/unicorn.pid"
ENV=production
GEM_HOME="/usr/local/rvm/gems/rbx-head@acn"
UNICORN_OPTS="-D -E $ENV -c $APP_ROOT/config/unicorn.rb"
SET_PATH="cd '/';"
CMD="$SET_PATH; $GEM_HOME/bin/unicorn_rails $UNICORN_OPTS"
old_pid="$PID.oldbin"
cd $APP_ROOT || exit 1
sig () {
test -s "$PID" && kill -$1 `cat $PID`
}
oldsig () {
test -s $old_pid && kill -$1 `cat $old_pid`
}
case ${1-help} in
start)
sig 0 && echo >&2 "Already running" && exit 0
# /bin/bash --login
bash -lc 'rvm use rbx@acn'
bash -lc 'unicorn_rails -p 3000 -E production -c /webapps/acn-docker/config/unicorn.rb -D'
echo "Starting"
;;
stop)
sig QUIT && exit 0
echo >&2 "Not running"
;;
force-stop)
sig TERM && exit 0
echo >&2 "Not running"
;;
restart|reload)
sig HUP && echo reloaded OK && exit 0
echo >&2 "Couldn't reload, starting '$CMD' instead"
$CMD
;;
upgrade)
sig USR2 && exit 0
echo >&2 "Couldn't upgrade, starting '$CMD' instead"
$CMD
;;
rotate)
sig USR1 && echo rotated logs OK && exit 0
echo >&2 "Couldn't rotate logs" && exit 1
;;
*)
echo >&2 "Usage: $0 <start|stop|restart|upgrade|rotate|force-stop>"
exit 1
;;
esac
# RAILS_ROOT/config/unicorn.rb
# Search for "# SET ME!" and replace these with your own settings!.
# Set environment to development unless something else is specified
env = ENV["RAILS_ENV"] || "development"
RAILS_ROOT = "/webapps/acn-docker" # SET ME!
if ENV['MY_RUBY_HOME'] && ENV['MY_RUBY_HOME'].include?('rvm')
begin
rvm_path = File.dirname(File.dirname(ENV['MY_RUBY_HOME']))
rvm_lib_path = File.join(rvm_path, 'lib')
# $LOAD_PATH.unshift rvm_lib_path
require 'rvm'
RVM.use_from_path! RAILS_ROOT
rescue LoadError
raise "RVM ruby lib is currently unavailable."
end
end
ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', File.dirname(__FILE__))
require 'bundler/setup'
pid "#{RAILS_ROOT}/tmp/pids/unicorn.pid"
# See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete
# documentation.
worker_processes 4 # SET ME!
# listen on both a Unix domain socket and a TCP port,
# we use a shorter backlog for quicker failover when busy
listen "/tmp/acn.sock", :backlog => 1024 # SET ME!
# Preload our app for more speed
preload_app true
GC.respond_to?(:copy_on_write_friendly=) and
GC.copy_on_write_friendly = true
# nuke workers after 30 seconds instead of 60 seconds (the default)
timeout 60
# Production specific settings
if env == "production"
# Help ensure your application will always spawn in the symlinked
# "current" directory that Capistrano sets up.
working_directory RAILS_ROOT
# feel free to point this anywhere accessible on the filesystem
user 'deployer', 'staff'
shared_path = RAILS_ROOT # SET ME!
stderr_path "#{shared_path}/log/unicorn.stderr.log"
stdout_path "#{shared_path}/log/unicorn.stdout.log"
end
before_fork do |server, worker|
# the following is highly recomended for Rails + "preload_app true"
# as there's no need for the master process to hold a connection
if defined?(ActiveRecord::Base)
ActiveRecord::Base.connection.disconnect!
end
# Before forking, kill the master process that belongs to the .oldbin PID.
# This enables 0 downtime deploys.
old_pid = "#{RAILS_ROOT}/tmp/pids/unicorn.pid.oldbin"
if File.exists?(old_pid) && server.pid != old_pid
begin
Process.kill("QUIT", File.read(old_pid).to_i)
rescue Errno::ENOENT, Errno::ESRCH
# someone else did our job for us
end
end
end
after_fork do |server, worker|
# the following is *required* for Rails + "preload_app true",
if defined?(ActiveRecord::Base)
ActiveRecord::Base.establish_connection
end
# if preload_app is true, then you may also want to check and
# restart any other shared sockets/descriptors such as Memcached,
# and Redis. TokyoCabinet file handles are safe to reuse
# between any number of forked children (assuming your kernel
# correctly implements pread()/pwrite() system calls)
end
#!/bin/sh
### BEGIN INIT INFO
# Provides: unicorn
# Required-Start: $all
# Required-Stop: $network $local_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start the unicorns at boot
# Description: Enable at boot time.
### END INIT INFO
# This is /etc/init.d/unicorn_init (without .sh)
# init.d script for single or multiple unicorn installations. Expects at least one .conf
# file in /etc/unicorn
#
# Modified by http://github.com/killercup
# based on modified version by jay@gooby.org http://github.com/jaygooby
# which is based on http://gist.github.com/308216 by http://github.com/mguterl
#
## A sample /etc/unicorn/my_app.conf
##
## RAILS_ENV=production
## RAILS_ROOT=/var/apps/www/my_app/current
## UNICORN="/usr/local/rvm/bin/<WRAPPED_NAME>" #see rvm wrapper above
#
# This configures a unicorn master for your app at /var/apps/www/my_app/current running in
# production mode. It will read config/unicorn.rb for further set up.
#
# You should ensure different ports or sockets are set in each config/unicorn.rb if
# you are running more than one master concurrently.
#
# If you call this script without any config parameters, it will attempt to run the
# init command for all your unicorn configurations listed in /etc/unicorn/*.conf
#
# /etc/init.d/unicorn start # starts all unicorns
#
# If you specify a particular config, it will only operate on that one
#
# /etc/init.d/unicorn start my_app
set -e
set -u
sig () {
test -s "$PID" && kill -$1 `cat "$PID"`
}
oldsig () {
test -s "$OLD_PID" && kill -$1 `cat "$OLD_PID"`
}
cmd () {
case $1 in
start)
sig 0 && echo >&2 "Already running" && exit 0
$CMD
echo "Starting"
;;
stop)
sig QUIT && echo "Stopping" && exit 0
echo >&2 "Not running"
;;
force-stop)
sig TERM && echo "Forcing a stop" && exit 0
echo >&2 "Not running"
;;
restart|reload)
sig USR2 && sleep 5 && oldsig QUIT && echo "Killing old master" `cat $OLD_PID` && exit 0
echo >&2 "Couldn't reload, starting '$CMD' instead"
$CMD
;;
upgrade)
sig USR2 && echo Upgraded && exit 0
echo >&2 "Couldn't upgrade, starting '$CMD' instead"
$CMD
;;
rotate)
sig USR1 && echo rotated logs OK && exit 0
echo >&2 "Couldn't rotate logs" && exit 1
;;
*)
echo >&2 "Usage: $0 <start|stop|restart|upgrade|rotate|force-stop>"
exit 1
;;
esac
}
setup () {
echo "$RAILS_ROOT: "
cd $RAILS_ROOT || exit 1
export PID=$RAILS_ROOT/tmp/pids/unicorn.pid
export OLD_PID="$PID.oldbin"
export RAILS_ENV=production
CMD="$UNICORN -c ${RAILS_ROOT}config/unicorn.rb -D"
}
start_stop () {
# either run the start/stop/reload/etc command for every config under /etc/unicorn
# or just do it for a specific one
# $1 contains the start/stop/etc command
# $2 if it exists, should be the specific config we want to act on
if [ $2 ]; then
. /etc/unicorn/$2.conf
setup
cmd $1
else
for CONFIG in /etc/unicorn/*.conf; do
# import the variables
. $CONFIG
setup
# run the start/stop/etc command
cmd $1
done
fi
}
ARGS="$1 $2"
start_stop $ARGS
@yudechen0820
Copy link

yudechen0820 commented Mar 27, 2020

If there is only 1 unicorn, we can use this.
sudo update-rc.d unicorn_myapp defaults

But if there are more than 2 unicorns, how can we enable them?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment