Deploying Express

This page describes how to use Nex!™ to deploy an application based on Maestrano's Enterprise Framework (a.k.a "Express"). At the end of this process you will have a live, fully functional application running.








1 - Project Setup

1.1 - Process Management

Make sure your Procfile allows the port to be specified via the $PORT environment variable, eg:

.foreman
.foreman
port: 7000

Procfile

Procfile
web: bundle exec puma

config/puma.rb

Procfile
# Puma can serve each request in a thread from an internal thread pool.
# The `threads` method setting takes two numbers a minimum and maximum.
# Any libraries that use thread pools should be configured to match
# the maximum value specified for Puma. Default is set to 5 threads for minimum
# and maximum, this matches the default thread size of Active Record.
#
threads_count = ENV.fetch('RAILS_MAX_THREADS') { 5 }.to_i
threads threads_count, threads_count

# Specifies the `port` that Puma will listen on to receive requests, default is 7000.
#
port        ENV.fetch('PORT') { 3000 }

# Specifies the `environment` that Puma will run in.
#
environment ENV.fetch('RAILS_ENV') { 'development' }

# Specifies the number of `workers` to boot in clustered mode.
# Workers are forked webserver processes. If using threads and workers together
# the concurrency of the application would be max `threads` * `workers`.
# Workers do not work on JRuby or Windows (both of which do not support
# processes).
#
# workers ENV.fetch("WEB_CONCURRENCY") { 2 }

# Use the `preload_app!` method when specifying a `workers` number.
# This directive tells Puma to first boot the application and load code
# before forking the application. This takes advantage of Copy On Write
# process behavior so workers use less memory. If you use this option
# you need to make sure to reconnect any threads in the `on_worker_boot`
# block.
#
# preload_app!

# The code in the `on_worker_boot` will be called if you are using
# clustered mode by specifying a number of `workers`. After each worker
# process is booted this block will be run, if you are using `preload_app!`
# option you will want to use this block to reconnect to any threads
# or connections that may have been created at application boot, Ruby
# cannot share connections between processes.
#
# on_worker_boot do
#   ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
# end

# Allow puma to be restarted by `rails restart` command.
plugin :tmp_restart

1.2 - Gems

Make sure your gems are up to date, it will speed up the deployment. You can see the list of gems baked in the web-ruby image here.

1.3 - Logging

To be able to view the Rails logs via nex-cli apps:logs, you need to redirect logs to STDOUT

For Rails 5, this is working out of the box. For Rails 4, you need to add this to your config/application.rb:

    # STDOUT logging for Rails 4
    # For Rails 5 see https://github.com/heroku/rails_12factor#rails-5-and-beyond
    if ENV["RAILS_LOG_TO_STDOUT"].present?
      log_level = ([(ENV['LOG_LEVEL'] || ::Rails.application.config.log_level).to_s.upcase, "INFO"] & %w[DEBUG INFO WARN ERROR FATAL UNKNOWN]).compact.first
      logger       = ::ActiveSupport::Logger.new(STDOUT)
      logger.formatter = proc do |severity, datetime, progname, msg|
        "#{datetime} #{severity}: #{String === msg ? msg : msg.inspect}\n"
      end
      logger       = ActiveSupport::TaggedLogging.new(logger) if defined?(ActiveSupport::TaggedLogging)
      logger.level = ::ActiveSupport::Logger.const_get(log_level)
      config.logger = logger

      STDOUT.sync = true
    end


And then add the environment variable via nex-cli apps:vars my-app --add RAILS_LOG_TO_STDOUT=true. 

1.4 - Configuration

Create a YAML configuration file based of application.yml to set the environment variables, eg:

application.nex-uat.yml
# Nex!™ maestrano/web-ruby specific
NO_MIGRATE: true
PORT: 3000
RAILS_ENV: uat
RAILS_MAX_THREADS: 32

# Tenant API keys
tenant_id: secret
tenant_key: secret

# Public hostname
mailer_default_host: enhanced-tuna-1.app.uat.maestrano.io

# Extra variables
newrelic_license_key: secret
google_tag_container: GTM-TH3MLB
SPARKPOST_API_KEY: secret
SECRET_KEY_BASE: secret # Generated with `rake secret`

Do NOT check this file into version control!

2 - Nex!™ - Deploying the app

This assume the Nex!™ Client is installed and properly configured

2.1 - Create the app


Create the App
# Create the app, with the correct environment variable
nex-cli apps:create maestrano/web-ruby --env-file <path/to/application.nex-uat.yml>  --size 4 --tags "ruby,express,uat" --desc "ACME Enterprise [UAT]"
 
# Save the app name to a var to make your life easier
export app=clueless-turkey-1

# Transfer app ownership to your parent organization (e.g. maestrano)
nex-cli apps:transfer $app maestrano
# Link it to the repository
nex-cli apps:scm $app --link github:maestrano/mno-enterprise-demo:develop
 
# Start it
nex-cli apps:up $app
 
# Check the logs
nex-cli apps:logs $app

You can now go to the Nex!™ generated URL (e.g. https://clueless-turkey-1.app.uat.maestrano.io/) and check that everything is working properly.

2.2 - Setting up a custom domain

First create a CNAME to your app:

∫ host mnoe-demo-uat.maestrano.io
mnoe-demo-uat.maestrano.io is an alias (CNAME) for enhanced-tuna-1.app.uat.maestrano.io.
# Create a domain
nex-cli domains:create mnoe-demo-uat.maestrano.io $app
 
# Add the SSL certs
# No NEED to perform this step if a wildcard certificate has been uploaded.
# nex-cli certs:create mnoe-demo-uat.maestrano.io $app --cert ../SSL/maestrano.io-wildcard-2016/maestrano.io.wildcard.crt --bundle ../SSL/maestrano.io-wildcard-2016/gd_bundle-g2-g1.crt --privkey ../SSL/maestrano.io-wildcard-2016/maestrano.io.wildcard.key.pem