Rails koos Unicorni ja Nginxiga
Toores. Ehk seda pala võib täiendada.
Sissejuhatus
RailStation (õigemini Rack Station, kuna ka teised raamistikud ja toores Rack on toetatud) on lihtne server, mis koosneb järgnevatest kihtidest:
- Nginx (http://nginx.org/)
- Blessing (http://github.com/borgand/blessing)
- Unicorn (http://unicorn.bogomips.org/)
- suvaline Racki rakendus
Lühidalt on aga lugu selline
Nginx server
- serveerib staatilisi faile railsi /public kaustast
- kõik muu suunab UNIXi socketile
Idee on selline, et kõige ees on Nginx, mis teeb dünaamilist mass-virtualhostimist ja kõikide RAKENDUS.zoo.tartu.ee domeenimede jaoks üritab leida sobivat UNIXi socketit, kuhu päring edasi anda.
God:
- tõmmatakse käima local.stardist: /usr/local/bin/god -c /srv/w/app/config/meedia.god
- jälgib, et Unicorn käiks (ja vajadusel stardib unicorn protsessid käima ka)
- jälgib, et Redis käiks
- jälgib, et 3 Resque protsessi käiks
Unicorni server:
- käib plain-useri õigustes
- käima tõmmatud Railsi kodukaustast: bundle exec unicorn -c unicorn.conf -D -E <environment>
- kill -USR2 teeb no-downtime restardi, st Unicorn tõmbab uue masteri käima ja see loadib koodi ja kui ta esimese lapse teeb, siis too saadab vanale masterile surmasõnumi. kasutajate jaoks downtime ei ole.
Godi pluss on see, et tema konf on Ruby script, mistõttu on ta ülipaindlik.
Teine võimalus on kasutada God asemel Blessingut.
Blessing hooliseb Socketite olemasolu eest (blessing on inglise keeles ükssarvikute kari), mis on käivitatud selliselt, et leiab üles kõik /srv/w/*/config/unicorn.conf failid ja igaühe kohta tõmbab üne Unicorni käima. Seejärel jääb 10s intervalliga jälgima, kas faili muutmisaeg on muutunud, et Unicorni restartida.
Blessing on võimalik, et nõdram. Eesmärk on see, et ta monitoorib shell-glob mustriga kaustapuud (nt /srv/w/*/unicorn.conf) ja kui avastab mõne uue unicorn.conf faili, siis tõmbab uue Unicorni käima. Kui mõni ära kaob, tapab protsessi maha jne.
nginxi ja Unicorni mass-virtual-hostingu konfinäite:
Seal see Unicorni conf on suht generic ja sobib praktiliselt üks-ühele iga Railsi jaoks, mis Unixi socketi kaudu ühendub front-end serveriga.
- Mass-virtualhosting configuration for Nginx
- Sets up virtualhosts automatically, in the following way:
- test1.laas.tjs.ee -> /srv/laas/test1
- app.tjs.ee -> /srv/prod/test1
nginx_mass_vhosts.conf
server {
# enable one of the following if you're on Linux or FreeBSD
listen 80 default deferred; # for Linux
# If you have IPv6, you'll likely want to have two separate listeners.
# One on IPv4 only (the default), and another on IPv6 only instead
# of a single dual-stack listener. A dual-stack listener will make
# for ugly IPv4 addresses in $remote_addr (e.g ":ffff:10.0.0.1"
# instead of just "10.0.0.1") and potentially trigger bugs in
# some software.
# listen [::]:80 ipv6only=on; # deferred or accept_filter recommended
client_max_body_size 4G;
# Change to your domain
server_name .tjs.ee;
# ~2 seconds is often enough for most folks to parse HTML/CSS and
# retrieve needed images/icons/frames, connections are cheap in
# nginx so increasing this is generally safe...
keepalive_timeout 5;
# Set vhost to default to host header
set $vhost $host;
# Split up the host header
# NB! Modify to your domain
if ($vhost ~ "^(w{3}\.)?(.*?)\.(.*?)?\.?tjs\.ee$") {
set $vhost $2;
set $dir $3;
}
# If dir is empty, set it to prod
if ($dir ~ "^$") {
set $dir prod;
}
root /srv/$dir/$vhost/public;
# Prefer to serve static files directly from nginx to avoid unnecessary
# data copies from the application server.
try_files $uri/index.html $uri.html $uri @app;
location @app {
# an HTTP header important enough to have its own Wikipedia entry:
# http://en.wikipedia.org/wiki/X-Forwarded-For
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# enable this if and only if you use HTTPS, this helps Rack
# set the proper protocol for doing redirects:
# proxy_set_header X-Forwarded-Proto https;
# pass the Host: header from the client right along so redirects
# can be set properly within the Rack application
proxy_set_header Host $http_host;
# we don't want nginx trying to do something clever with
# redirects, we set the Host: header above already.
proxy_redirect off;
proxy_pass http://unix:/srv/$dir/$vhost/tmp/sockets/unicorn.sock;
}
# Maintenance
if (-f $document_root/maintenance.html) {
return 503;
}
error_page 503 @maintenance;
location @maintenance {
rewrite ^(.*)$ /maintenance.html break;
}
# Rails error pages
error_page 500 504 /500.html;
}
unicorn.conf
# Per-app unicorn configuration
basedir = File.absolute_path(File.dirname(__FILE__))
working_directory basedir
worker_processes 4
pid "#{basedir}/tmp/pids/unicorn.pid"
stderr_path "#{basedir}/log/unicorn.log"
listen "#{basedir}/tmp/sockets/unicorn.sock", :backlog => 2048
timeout 30
preload_app true
##
# REE
# http://www.rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
if GC.respond_to?(:copy_on_write_friendly=)
GC.copy_on_write_friendly = true
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
defined?(ActiveRecord::Base) and
ActiveRecord::Base.connection.disconnect!
##
# 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.
#
# Using this method we get 0 downtime deploys.
old_pid = basedir + '/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|
##
# 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
ActiveRecord::Base.establish_connection
# Redis and Memcached would go here but their connections are established
# on demand, so the master never opens a socket
end
Kasutamine
RailStationi (RS) kasutamiseks on vaja kahte asja
- laadida rakenduse kood RS serveris kausta: /srv/w/NIMI
- Koostada unicorn.conf
Iga 10 sekundi järel kontrollib RS uute rakenduste tekkimist ja käivitab need automaatselt. Samuti taaskäivitatakse ja suletakse rakendusi vastavalt vajadusele.
Lingid
https://github.com/blog/517-unicorn
http://www.opensourcerails.com/ hunnik railsi tarkvara