Unicorn continues to use old code following deploy + restart - capistrano

task :restart_unicorn, :except => { :no_release => true } do
run "#{try_sudo} kill -s USR2 $(cat /var/www/app_name/shared/pids/unicorn.pid)"
end
When I do sudo kill -s USR2 $(cat /var/www/app_name/shared/pids/unicorn.pid) on the server, what happens is that a new unicorn master is created, and the old one has (old) appended to its name. The old one is never killed, but even if I kill it on my own, the new unicorn instance is still showing the old code from before my deployment. The new instance has the same creation time as the old -- its as if its just being duplicated. If I stop the instance, and the start it again, it works, but I would like to be able to do zero-downtime deploys.
Any help is appreciated.
EDIT
After following the sugest Ilya O., I created a capistrano task that does this:
old_pid = get_pid('/var/www/appname/shared/pids/unicorn.pid')
run "#{try_sudo} kill -s SIGUSR2 $(cat /var/www/appname/shared/pids/unicorn.pid)"
/var/www/app/current/tmp/pids/unicorn.pid)"
run "#{try_sudo} kill -s SIGWINCH #{old_pid}"
This runs SIGUSR2 on the pid, and kills the old unicorn process. The problem is that all my application server is never updated to my recently deployed code, this task just seems to copy my the old unicorn enviroment into a new process. It works fine if I simply kill the master process and then start unicorn fresh again, but then there is a minute or so of dropped requests.

Do you have preload_app set to true in your Unicorn config? If so, you need to send SIGUSR2 and then SIGQUIT to the original master process after the new process are up and running.
What may also be happening is that the original master process has died but the children are still serving requests. You can try sending SIGUSR2, and after the new master process has spawned, send SIGWINCH (to the old master) to kill the old unicorn child processes, and then SIGQUIT on the old master process. You should now have only the "new" unicorn processes serving requests.
EDIT: Try doing SIGQUIT instead of SIGWINCH. I think the old process might be spawning workers after SIGWINCH.

I'm not sure why are you putting all that work on capistrano, usually on capistrano something like this is enough:
set :unicorn_pid, "unicorn.my_website.pid"
desc "Zero-downtime restart of Unicorn"
task :restart, roles: :app do
if remote_file_exists?("/tmp/#{unicorn_pid}")
puts "Killing /tmp/#{unicorn_pid}"
run "kill -s USR2 `cat /tmp/#{unicorn_pid}`"
else
run "cd #{current_path} ; RAILS_ENV=#{rails_env} bundle exec unicorn_rails -c #{unicorn_config} -D"
end
end
and then the real code for killing the old unicorn process is actually on the unicorn configuration
# config/unicorn.rb
# Set environment to development unless something else is specified
env = ENV["RAILS_ENV"] || "production"
# See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete documentation.
worker_processes 2 # amount of unicorn workers to spin up
APP_PATH = "/u/apps/my_website/current"
listen "/tmp/my_website.socket"
preload_app true
timeout 30 # restarts workers that hang for 30 seconds
pid "/tmp/unicorn.my_website.pid"
# By default, the Unicorn logger will write to stderr.
# Additionally, ome applications/frameworks log to stderr or stdout,
# so prevent them from going to /dev/null when daemonized here:
stderr_path APP_PATH + "/log/unicorn.stderr.log"
stdout_path APP_PATH + "/log/unicorn.stdout.log"
if env == "production"
# Help ensure your application will always spawn in the symlinked
# "current" directory that Capistrano sets up.
working_directory APP_PATH
# feel free to point this anywhere accessible on the filesystem
user 'deploy', 'deploy' # 'user', 'group'
shared_path = "/u/apps/my_website/shared"
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
# When sent a USR2, Unicorn will suffix its pidfile with .oldbin and
# immediately start loading up a new version of itself (loaded with a new
# version of our app). When this new Unicorn is completely loaded
# it will begin spawning workers. The first worker spawned will check to
# see if an .oldbin pidfile exists. If so, this means we've just booted up
# a new Unicorn and need to tell the old one that it can now die. To do so
# we send it a QUIT.
#
# This enables 0 downtime deploys.
old_pid = "/tmp/unicorn.my_website.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|
# Unicorn master loads the app then forks off workers - because of the way
# Unix forking works, we need to make sure we aren't using any of the parent's
# sockets, e.g. db connection (since "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
I use that setup most of the time and my application is reload without any issue, you probably already have all of that since its mostly the default configuration, but if you are missing something, give it a try ;)

Unicorn guys have a public init.d script for this, you should probably add that in your system and use it.
You will find 2 different ways to restart unicorn : restart and upgrade.
I personnaly add this script in /etc/init.d/unicorn, set this executable then you can use sudo service unicorn upgrade in your capistrano recipe.
Init script : http://unicorn.bogomips.org/examples/init.sh

Related

Preventing the Docker container from exiting when the main process dies

I am using Postgres with repmgr, one of the small problems I am having is that sometimes repmgr will have to stop and start the Postgres service and that will just kill the container, I tried some of the solutions online in the Dokcerfile but none seems to work, is there something I can add in the docker-compose file to prevent docker from exiting immediately, I don't want to stay alive forever, but maybe couple minutes?
Remember that docker-composer is mostly development thing. For production there are other ways, like kubernetes.
The only solution i know is to run our own .sh script as main process, which would have infinite loop with necessary checks in it.
This way you can control how to check - like ps aux and grep what you need. and exit main process if you need to by doing logic.
sh scrip would look something like:
while sleep 180; do
ps aux |grep postgres_service_name |grep -v grep
POSTGRESS=$?
if [ $POSTGRESS -ne 0 ]; then
# do what you need before exiting whole container
exit 1
fi
done
make sure you replace postgres_service_name with real name of Postgres service on linux.
Use that script as a startup script in docker compose or whatever you would use in prod.
if you really need 2 minutes before it is off - i would implement logic which would measure time after first time process is not there
The way docker is designed it will start a new container by starting the command specified as entrypoint/command to it and when this process terminates docker will kill all remaining processes in that container and shut it down.
So to keep the container running while the Postgres process is restarted you need to have another command running as the root process in the container.
You can achieve this by writing a simple shell script as a wrapper which will only exit when no Postgres process is running anymore or by using a dedicated init tool such as supervisord.

Running Mongodb Ops manager in docker

I have the dockerfile which correctly installs Mongodb and Ops manager in the container. After that I use an entrypoint.sh to do the setups, at the end of the script I put:
echo "starting mongodb"
service mongod start
echo "starting opsmgr"
service mongodb-mms start
When I run the container, from the logs message, the line to start ops manager line is never executed.
How can I do something like: If mongodb is up then execute service mongodb-mms start?
Not sure if it is running multiple services in one container beacuse ops manager needs to wait for mongodb to start correctly first.
I found this Dockerfile for a very old version of Ops Manager, but the way it waits for the mongodb port to be open still works: https://github.com/deviantony/docker-opsmanager/blob/master/ops-manager/startup.sh
Basically the author uses nc to wait until the standard mongod port accepts a connection with:
echo "Waiting for MongoDB"
while true; do
nc -q 1 database 27017 >/dev/null && break
done
Now, make sure when calling Ops Manager that this remains in the foreground, as Docker needs one process to be running.
You can start it with service start mongodb-mms and inmediatelly run tail, for instance, like:
echo "starting mongodb"
service mongod start
# snippet to wait for mongod to be in running state
echo "starting opsmgr"
service mongodb-mms start
# Keep this startup script busy, if it ends, the Docker container dies.
tail -f /opt/mongodb/mms/logs/mms0.log

supervisord: How to stop supervisord on PROCESS_STATE_FATAL

I'm using supervisord to manage multiple processes in a docker container.
However, one process is always the 'master', and the others are monitoring and reporting processes.
What I want to do is kill supervisord if the master process fails to start after startretries.
What I tried to do is use eventlistener to kill the process:
[eventlistener:master]
events=PROCESS_STATE_FAIL
command=supervisorctl stop all
But I don't think the events subsystem is this sophisticated. I think I need to actually write an event listener to handle the events.
Is that correct? Is there a simpler way to kill the entire supervisord if one of the processes kicks?
Thanks
Another try:
[eventlistener:quit_on_failure]
events=PROCESS_STATE_FATAL
command=sh -c 'echo "READY"; while read -r line; do echo "$line"; supervisorctl shutdown; done'
Especially for docker containers, it would literaly be a killer to have a simple straightforward shutdown on errors. Container should go down when processes die.
Answered by:
supervisord event listener
The command parameter MUST be an event handler, can't be a random command.

Running PostgreSQL with Supervisord

I want to run PostgreSQL 9.1 using Supervisor on Ubuntu 10.04. At the moment, I manually start PostgreSQL using the init script:
/etc/init.d/postgresql start
According to this post: http://nicksergeant.com/using-postgresql-with-supervisor-on-ubuntu-1010/, I need to modify the PostgreSQL config to make it run on TCP port instead of Unix socket, in order to make PostgreSQL work with Supervisor.
I have two questions regarding this approach:
Considering this is more of hack, is there any implication (e.g. security/permissions, performance, etc) of doing this?
Why cannot we just run the same init script postgresql in Supervisor config? Instead, as shown in the link above, it runs postmaster?
UPDATE:
Thanks to the useful suggestions from both answers below, I have setup a script for Supervisor to invoke PostgreSQL directly:
#!/bin/sh
# This script is run by Supervisor to start PostgreSQL 9.1 in foreground mode
if [ -d /var/run/postgresql ]; then
chmod 2775 /var/run/postgresql
else
install -d -m 2775 -o postgres -g postgres /var/run/postgresql
fi
exec su postgres -c "/usr/lib/postgresql/9.1/bin/postgres -D /var/lib/postgresql/9.1/main -c config_file=/etc/postgresql/9.1/main/postgresql.conf"
I also set the config: /etc/postgresql/9.1/main/start.conf to manual so that PostgreSQL does not start automatically on boot (however, it's not clear to me whether this config is loaded). And then I setup the Supervisor config for postgres as:
[program:postgres]
user=root
group=root
command=/usr/local/bin/run_postgresql.sh
autostart=true
autorestart=true
stderr_logfile=/home/www-data/logs/postgres_err.log
stdout_logfile=/home/www-data/logs/postgres_out.log
redirect_stderr=true
stopsignal=QUIT
So now, I can start PostgreSQL in supervisorctl by doing start postgres, which runs fine. However, after I issue stop postgres, although supervisorctl declares postgres is stopped, the server apparently is still running as I can psql into it.
I wonder if this is a Supervisor config issue, or a PostgreSQL issue. Any suggestion welcome!
The blog post is rather badly written. There is no "TCP mode": the post's suggested method will still listen on a Unix socket, just in a different directory. Comments in the post such as "external pid file - not needed for TCP mode" are very misleading.
postmaster is the traditional name for the postgresql executable (to distinguish the master dispatching process from the backend slaves). For some time now there has been no separate executable, and now it is installed as simply "postgres".
Assuming that Supervisor is broadly simliar to the qmail/daemontools supervise scheme, it would be entirely possible (in fact, quite normal) to have it run a script that sets up the directories and environment, and then execs postgres with the requisite arguments (or propagates arguments given to the wrapper script, which would be unusual with supervise but makes more sense when you have a config file to put arguments into).
The way supervise worked (and I'm going to continue to assume "Supervisor" is the same) is to have the supervisor process run a subprocess as specified, and simply relaunch a new subprocess if it exits. This is based on the idea that the process being launched is a long-lived daemon process that only exits when something goes badly wrong, and that simply restarting it is a valid fix. By contrast, init scripts such as in /etc/init.d run the subprocess and detach it, and return control to their caller- if the subprocess exits, nothing special happens, and it must be restarted manually. If you tried to simply run /etc/init.d/postgresql start from supervise, it would continuously keep spawning postgresql daemons, as the return from the init script would be interpreted as the daemon process having exited, when in fact it had been started and detached.
To avoid auto-starting the service with the /etc/init.d scripts, the package for postgresql 9.1 provides a file /etc/postgresql/9.1/main/start.conf that contains:
# Automatic startup configuration
# auto: automatically start/stop the cluster in the init script
# manual: do not start/stop in init scripts, but allow manual startup with
# pg_ctlcluster
# disabled: do not allow manual startup with pg_ctlcluster (this can be easily
# circumvented and is only meant to be a small protection for
# accidents).
auto
This is the file to modify to avoid auto-start as opposed to moving away /etc/init.d/postgresql as the blog post suggests.
Also, changing unix sockets parameters for lack of /var/run/postgresql doesn't look like the best idea, because it's the default for any program linked with libpq, and because there's no difficulty in creating that directory with the proper permissions, just like it's done by the package's start sequence in /usr/share/postgresql-common/init.d-functions:
# create socket directory
if [ -d /var/run/postgresql ]; then
chmod 2775 /var/run/postgresql
else
install -d -m 2775 -o postgres -g postgres /var/run/postgresql
fi
And although the default value shouldn't cause a problem, note that whether postmaster ultimately stays in foreground or forks and runs in background is controlled by the silent_mode parameter in postgresql.conf. Make sure that it is off.
I am trying to make both tomcat and postgres run under supervisor, and found some hints here : https://serverfault.com/questions/425132/controlling-tomcat-with-supervisor
Here is my modified run_postgresql.sh, using bash :
#!/bin/bash
# This script is run by Supervisor to start PostgreSQL 9.1 in foreground mode
function shutdown()
{
echo "Shutting down PostgreSQL"
pkill postgres
}
if [ -d /var/run/postgresql ]; then
chmod 2775 /var/run/postgresql
else
install -d -m 2775 -o postgres -g postgres /var/run/postgresql
fi
# Allow any signal which would kill a process to stop PostgreSQL
trap shutdown HUP INT QUIT ABRT KILL ALRM TERM TSTP
exec sudo -u postgres /usr/lib/postgresql/9.1/bin/postgres -D /var/lib/postgresql/9.1/main --config-file=/etc/postgresql/9.1/main/postgresql.conf
With this script postgresql stops correctly after supervisorctl stop postgres.

How to start a play2 application on a remote machine using capistrano

I'm trying to deploy a play2 application with capistrano, but I can't figure out how to (re)start the play2 application after a successful deployment. Just triggering 'play start' will cause the process to be hanging waiting for me to press ctrl+D
I've created a start script in the play app root folder
#!/bin/bash
nohup bash -c "/var/lib/play2/play start &>> /tmp/myapp.log 2>&1" &> /dev/null &
It works great when I run this on the server. When I try to call this from my local machine over ssh it also works. But when I am using capistrano, it doesn't seem to do anything. My capistrano config looks like this:
namespace :deploy do
task :restart do
stop
sleep 1
start
end
task :start do
run "cd #{current_release}/trip-api && ./start.sh"
end
task :stop do
run "cd #{current_release}/trip-api && ./stop.sh"
end
end
What's the best way to start a play2 application on a remote machine? How to get it working with capistrano?
Have a look at play documentation on deploying your application on production
The recommended way is to package your app with
play clean compile stage
And then run it with
$ target/start
To stop it, have a look at the docs:
The server’s process id is displayed at bootstrap and written to the
RUNNING_PID file. To kill a running Play server, it is enough to send
a SIGTERM to the process to properly shutdown the application.
In this quickstart for Openshift, it shows another way to start play as a service and how to stop it.
basically you do something like this to start:
APP_COMMAND="${OPENSHIFT_REPO_DIR}target/start $PLAY_PARAMS "\
"-Dhttp.port=${OPENSHIFT_INTERNAL_PORT} "\
"-Dhttp.address=${OPENSHIFT_INTERNAL_IP} "\
"-Dconfig.resource=openshift.conf"
echo $APP_COMMAND &>> $LOG_FILE
nohup bash -c "${APP_COMMAND} &>> ${LOG_FILE} 2>&1" &> /dev/null &
and to stop it
pid=`cat RUNNING_PID`
echo "Stopping play application" >> $LOG_FILE
kill -SIGTERM $pid
There are few fresh topics about running application available at Google Groups:
Start an application as a background process
When deployed on Ubuntu 10.04 cant detach from console
It's good idea to follow or join them
I would suggest using runit. We are currently running a bunch of services in production and it works great.
It only involves creating a simple shell script named run, pointing runit to its containing directory and then start it. Services should not daemonize by themselves and runit controls pid files, etc.
There is a command ( sv ) to start, stop and query services. ( sv start|stop|status|restart yourapp ).
A cursory google search got me this http://rubygems.org/gems/capistrano-runit though I do not use capistrano at all so I can't vouch for it's usefulness.
http://smarden.org/runit/
The faq is the best place to start: http://smarden.org/runit/faq.html
In debian you just apt-get install runit and are good to go.
update-service --add /your/service/dir/ will register the service with runit.
On deployment we stop services, change binaries and start services; it is really simple.