nginx & uwsgi(psgi) & perlbrew & mojolicious

mche edited this page Feb 13, 2013 · 22 revisions

!!! Warn !!! Incomplete still !!!

Доброго всем !

¡ ¡ ¡ ALL GLORY TO GLORIA ! ! !

Table of Contents

perlbrew + cpanm + cpan-outdated

perlbrew is a tool to manage multiple perl installations in your $HOME directory. They are completely isolated perl universes.

$ curl -kL http://install.perlbrew.pl | bash
$ echo 'source ~/perl5/perlbrew/etc/bashrc' >> .bash_profile
# choose mirror
$ perlbrew mirror
$ perlbrew available
# choose version
$ perlbrew install perl-5.16.2
$ perlbrew use perl-5.16.2 # or switch
$ perlbrew install-cpanm
$ cpanm App::cpanoutdated
$ cpanm <Your::Favorite::Modules>
$ cpanm ...

# регулярно обновляться (regulary run update installed modules)
$ cpan-outdated | cpanm

Nigthly update perlbrew and all modules

$ crontab -e

30 2 * * * perlbrew self-upgrade; perlbrew upgrade-perl
0 3 * * * perlbrew exec --with perl-5.16.2 cpan-outdated | cpanm
# or
0 3 * * * perlbrew exec --with perl-5.16.2 perlbrew list-modules | cpanm

Mojolicious app

Install Mojolicious

$ cpanm Mojo

Generate app

An usual procedure for new Mojolicious app

$ mojo generate app Service1
$ service1/script/service1 test
$ service1/script/service1 daemon
# or 
$ morbo service1/script/service1
# or
$ hypnotoad service1/script/service1 start
# all glory to ...

Go in favorite browser http://127.0.0.1:3000 or http://localhost:8080/

And work, work, work on new app...


Below will install production bundle nginx+uwsgi(psgi) for our Mojolicious application.

uWSGI

Uwsgi daemon will load Mojolicious app in PSGI. No changes in the structure of the our application will not need. Mojolicious will autodetect PSGI mode.

You can compile and install uwsgi with psgi support using the "network installer". Make sure perlbrew set right Perl version (perl-5.16.2)

$ perlbrew info
$ curl http://uwsgi.it/install | bash -s psgi ~/uwsgi-perl-5.16.2
The new uwsgi server binary file name indicate linked with appropriate version of perl

Init script for uwsgi daemon

#!/bin/bash

# Use uwsgi to run psgi web apps.
# !!! Запускать от простого пользователя
# для которого установлен perlbrew
# su - <user> -c "/home/<user>/service1/<this bash script>.sh start"

# http://perlbrew.pl/Perlbrew-In-Shell-Scripts.html
# $ perlbrew info
export PERLBREW_ROOT=~/perl5/perlbrew
export PERLBREW_HOME=~/.perlbrew
source ${PERLBREW_ROOT}/etc/bashrc
perlbrew use perl-5.16.2

# $ mojo generate app Service1
SERVICE_ROOT=~/service1
SERVICE_SCRIPT="$SERVICE_ROOT/script/service1"
NAME=uwsgi
DESC=uwsgi

# uWSGI собирать при соответсвующем Перле!!!
# $ perlbrew use perl-5.16.2
# $ curl http://uwsgi.it/install | bash -s psgi ~/uwsgi-perl-5.16.2
DAEMON=~/uwsgi-perl-5.16.2
LOG="$SERVICE_ROOT/log/$NAME.log"
PID_FILE="$SERVICE_ROOT/$NAME.pid"
SOCK="/tmp/uwsgi.sock"
NUM_SOCK=1 # сверь с uwsgi_pass/upstream nginx.conf, циферка в названии файла сокета в конце
THIS=$0
ACTION=$1
shift
DAEMON_OPTS="--psgi $SERVICE_SCRIPT --enable-threads --processes=10 --master  --daemonize=$LOG --pidfile=$PID_FILE --uwsgi-socket=$SOCK.$NUM_SOCK"
#--declare-option '$@' --uid=$OWNER --gid=$GROUP --uwsgi-socket=$SOCK.{1..$NUM_SOCK}
echo "CHECK COMMAND: " $DAEMON $DAEMON_OPTS

test -x $DAEMON || exit 0

# Include uwsgi defaults if available
if [ -f /etc/default/uwsgi ] ; then
	. /etc/default/uwsgi
fi

set -e

get_pid() {
    if [ -f $PID_FILE ]; then
        echo `cat $PID_FILE`
    fi
}   


case $ACTION in # был shift!!!
  start)
	echo -n "Starting $DESC... "
        PID=$(get_pid)
        if [ -z "$PID" ]; then
            [ -f $PID_FILE ] && rm -f $PID_FILE
            touch $PID_FILE
	    touch $LOG
 	    $DAEMON $DAEMON_OPTS
	    echo "OK."
        else 
        echo "Its running? Found PID_FILE=[$PID_FILE].
        echo "Check (ps ax | grep \"$DAEMON\" | grep $PID) and then (rm '$PID_FILE')"
	    ps=$(ps ax | grep "$DAEMON" | grep $PID)
	    if [ -z "$ps" ]; then
		# ???
		exit
	    else
		echo "Found process:"
		echo "$ps"
	    fi
        fi

	;;
  stop)
	echo -n "Stopping $DESC... "
        PID=$(get_pid)
        [ ! -z "$PID" ] && kill -s 3 $PID &> /dev/null
        if [ $? -gt 0 ]; then
            echo "was not running" 
            exit 1
        else 
	    echo "OK."
            rm -f $PID_FILE &> /dev/null
	    rm -f "$SOCK.$NUM_SOCK" &> /dev/null
	    
        fi
	;;
  reload)
        echo "Reloading $DESC..." 
        PID=$(get_pid)
        [ ! -z "$PID" ] && kill -s 1 $PID &> /dev/null
        if [ $? -gt 0 ]; then
            echo "was not running" 
            exit 1
        else 
	    echo "OK."
        fi
	;;
  force-reload)
        echo "Reloading $DESC..." 
        PID=$(get_pid)
        [ ! -z "$PID" ] && kill -s 15 $PID &> /dev/null
        if [ $? -gt 0 ]; then
            echo "was not running" 
            exit 1
        else 
	    echo "OK."
        fi
        ;;
  restart)
        $0 stop
        sleep 2
        $0 start
	;;
  status) 
	# инфа кидается в лог $LOG
	killall -10 $DAEMON
	tail -n 100 $LOG
	;;
      *)  
	    echo "Usage: $THIS {start|stop|restart|reload|force-reload|status} [options pass to app -- not work :(]" >&2
	    exit 1
	    ;;
    esac
    exit 0

Note. Uwsgi have --declare-option which would be usefull for pass args to the Mojolicious app, but it didnt work on my tests. Configure your app with Mojolicious::Plugin::Config

Nightly reload app

Crontab for reload uwsgi Mojolicious app with every night updated perl modules (see above)

0 4 * * * ~/service1/<above bash script>.sh reload

NGINX

The nginx config /etc/nginx/conf.d/uwsgi-service1.conf that included by /etc/nginx/conf.d/*.conf; in main nginx.conf

server {
	listen 80;
	server_name <your domain>;

	access_log /var/log/nginx/<your domain>.access_log main;
	error_log /var/log/nginx/<your domain>.error_log info;

	rewrite ^/(favicon.ico)$ /images/$1 permanent;
	rewrite ^/(robots.txt)$ /files/$1 permanent;


	location / {
		include uwsgi_params;
		uwsgi_pass unix:/tmp/uwsgi.sock.1;
		uwsgi_modifier1 5;
	}

	location ~* /(images|css|js|files)/ { # static files in public/<folders>
		root /home/<user>/service1/public; # A request for "/images/foo.png" will return the file "/home/<user>/service1/public/images/foo.png"
		access_log off;
		expires 30d; # max
	}

	location /service1/ { # show your project :-)
		root /home/<user>;
		access_log off;
		expires 1d;
		autoindex  on;
		charset utf-8;
		charset_types *;
		index  index.html index.htm;
	}


}

The nginx interacts with uwsgi daemon through unix socket /tmp/uwsgi.sock.1

Go to http://your.domain/

Looks awesome!

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.