ams node meetup december presentation phusion passenger
TRANSCRIPT
Deploying with
Phusion Passenger
Our Node.js app is done. How do we deploy to production?
Can’t be that hard. Let’s ask Google.
Make sure your app keeps running(restart on crash)
Step 1
forever start app.js
Start your app on system boot
Step 2
systemd, SysV init,upstart, etc.
#!/bin/bash DIR=/var/www/YOUR_NODE_APP_GOES_HERE PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin NODE_PATH=/usr/local/lib/node_modules NODE=/usr/local/bin/node test -‐x $NODE || exit 0 function start_app { NODE_ENV=production nohup "$NODE" "$DIR/YOUR_APP_SERVER_FILE.js" 1>> "$DIR/logs/YOUR_APP_NAME.log" 2>&1 & echo $! > "$DIR/pids/YOUR_APP.pid" } function stop_app { kill `cat $DIR/pids/YOUR_APP.pid` } case $1 in start) start_app ;; stop) stop_app ;; restart) stop_app start_app ;; *) echo "usage: YOUR_APP_NAME {start|stop}" ;; esac exit 0
Reverse proxy from Nginx!
Step 3
• Serve files faster and better• Improves security: better
HTTP sanitizer!• Easier SSL configuration
server { listen 0.0.0.0:80; server_name yourdomain.com yourdomain; root /yourapp/public; }
server { listen 0.0.0.0:80; server_name yourdomain.com yourdomain; root /yourapp/public;
location ~* \.(css|js|gif|jpe?g|png)$ { add_header Pragma public; add_header Cache-‐Control "public, must-‐revalidate, proxy-‐revalidate"; } }
upstream app_yourdomain { server 127.0.0.1:3000; }
server { listen 0.0.0.0:80; server_name yourdomain.com yourdomain; root /yourapp/public;
location ~* \.(css|js|gif|jpe?g|png)$ { add_header Pragma public; add_header Cache-‐Control "public, must-‐revalidate, proxy-‐revalidate"; }
location / { proxy_set_header X-‐Real-‐IP $remote_addr; proxy_set_header X-‐Forwarded-‐For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-‐NginX-‐Proxy true;
proxy_pass http://app_yourdomain/; proxy_redirect off; } }
Multi-core!
Step 4
Cluster module
var cluster = require('cluster'); var http = require('http'); var numCPUs = require('os').cpus().length;
if (cluster.isMaster) { // Fork workers. for (var i = 0; i < numCPUs; i++) { cluster.fork(); }
cluster.on('exit', function(worker, code, signal) { console.log('worker ' + worker.process.pid + ' died'); }); } else { // Workers can share any TCP connection // In this case its a HTTP server http.createServer(function(req, res) { res.writeHead(200); res.end("hello world\n"); }).listen(8000); }
How can we see application statistics? Uhhh.... sign up with
proprietary monitoring services?
Configure forever
Configure init
Configure Nginx
Use Cluster module
Sign up for proprietary monitoring service
Node.js≠
boilerplate
Passenger: rethinking the workflow
server { listen 0.0.0.0:80; server_name yourdomain.com; root /yourapp/public; }
server { listen 0.0.0.0:80; server_name yourdomain.com; root /yourapp/public; deploy_my_damn_app on; }
server { listen 0.0.0.0:80; server_name yourdomain.com; root /yourapp/public; deploy_my_damn_app on; }
✓ Restarting on crash✓ Start during system
boot✓ Nginx reverse proxy✓ Multi-core
server { listen 0.0.0.0:80; server_name yourdomain.com; root /yourapp/public; deploy_my_damn_app on; }
✓ Restarting on crash✓ Start during system
boot✓ Nginx reverse proxy✓ Multi-core
bash$ show-‐my-‐app-‐status
server { listen 0.0.0.0:80; server_name yourdomain.com; root /yourapp/public; deploy_my_damn_app on;
}
✓ Restarting on crash✓ Start during system
boot✓ Nginx reverse proxy✓ Multi-core
bash$ show-‐my-‐app-‐status
passenger_enabled on;
bash$ passenger-‐status
# passenger-‐status -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ General information -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ Max pool size : 9 Processes : 3 Requests in top-‐level queue : 0
-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ Application groups -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ /u/apps/bubbleconf/current#default: App root: /u/apps/bubbleconf/current Requests in queue: 0 * PID: 25408 Sessions: 0 Processed: 4 Uptime: 4h 17m 2s CPU: 0% Memory : 95M Last used: 34m 30s a
/u/apps/passenger_website/current#default: App root: /u/apps/passenger_website/current Requests in queue: 0 * PID: 20696 Sessions: 0 Processed: 27291 Uptime: 6h 10m 0s CPU: 8% Memory : 155M Last used: 0s ago
# passenger-‐config system-‐metrics -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ General -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ Kernel version : 3.14.1-‐x86_64-‐linode39 Uptime : 225d 15h 52m 20s Load averages : 0.10%, 0.10%, 0.13% Fork rate : 0
-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ CPU -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ Number of CPUs : 4 Average CPU usage : 14% -‐-‐ 10% user, 0% nice, 4% system, 86% idle CPU 1 : 0% -‐-‐ 0% user, 0% nice, 0% system, 100% idle CPU 2 : 40% -‐-‐ 40% user, 0% nice, 0% system, 60% idle I/O pressure : 0% CPU 1 : 0% CPU 2 : 0% Interference from other VMs: 0% CPU 1 : 0% CPU 2 : 0%
-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ Memory -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ RAM total : 6008 MB RAM used : 1940 MB (32%) RAM free : 4068 MB Swap total : 1711 MB Swap used : 172 MB (10%) Swap free : 1539 MB
Nginx
Forever/PM2
Cluster
Init script
Monitoring software
Lets you focus on what is
really important
Keeps you
out of the dark
Identify and solve
problems
How it works
Easy to migrate to? Easy to setup?
$ brew install passenger $ brew install nginx —with-‐passenger …follow instructions…
OS X
…add our APT repo… $ sudo apt-‐get install passenger nginx-‐extras
Debian/Ubuntu
$ node app.js
$ passenger start \ —app-‐type node —startup-‐file app.js
Standalone mode
Nginx mode
server { listen 0.0.0.0:80; server_name yourdomain.com; root /yourapp/public; passenger_enabled on; }
Is it any good?
Is it stable?
Who uses it?
6 years
• Host multiple apps at once• Improve security with privilege separation• Dynamic worker management• etc…
Many more features not mentioned
• Zero-downtime rolling restarts• Error resistant deploys• Mass deployment• Resource control• Unstuck stuck apps• Memory limiting• Priority support
Paid offering
The future
Easily setup dev environmentwith one command
• Repeatable• Shareable
Easily setup and push to productionwith one command
• Repeatable• Shareable
Debugging
www.phusionpassenger.com