Skip to content

Instantly share code, notes, and snippets.

@Epigene
Last active March 27, 2020 19:44
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Epigene/8289678fb28db5d2b9fc to your computer and use it in GitHub Desktop.
Save Epigene/8289678fb28db5d2b9fc to your computer and use it in GitHub Desktop.
Dokku Droplet Workflow, v0.4.x

Deploy a Rails app to Dokku droplet

Set up a droplet

Much in common with http://www.snip2code.com/Snippet/159602/Using-Dokku-to-deploy-a-Rails-Applicatio

Initialize droplet via https://www.digitalocean.com/community/tutorials/how-to-use-the-dokku-one-click-digitalocean-image-to-run-a-ruby-on-rails-app

Grab the latest dokku

Config locales following general droplet fix

Visit the droplet IP to configure Dokku (keys, domain, unthick virtual domains)

Give dokku user access

Give keys

# as root user
mkdir -p /home/dokku/.ssh
touch /home/dokku/.ssh/id_rsa
  > populate with private key from dashlane secure notes
touch /home/dokku/.ssh/id_rsa.pub
  > populate with public key from dashlane secure notes
  
sudo chmod 400 /home/dokku/.ssh/id_rsa
sudo chmod 700 /home/dokku/.ssh/id_rsa.pub

Deployment Checklist

  1. App is configured for dokku
  2. Dokku is configured to receive a deploy (dokku app, its ENV and services are set up)
  3. git push dokku succeeds
  4. migrate manually with dokku run <app_name> bundle exec rake db:migrate db:seed RAILS_ENV=<env>
  5. Update VHOST file with needed domains
  6. Rebuild/redeploy

  7. See if app's console runs
  8. See if app can be accessed via needed DNS

Try a test deploy

Follow official deploy guide

1. Create the app on Dokku server first
dokku apps:create ruby-rails-sample
2. install postgres plugin
sudo dokku plugin:install https://github.com/dokku/dokku-postgres.git
3. create the DB service
dokku postgres:create ruby-rails-sample
4. link the app with DB
dokku postgres:link ruby-rails-sample ruby-rails-sample
5. Deploy time!

NB, when you get git errors, run the key add command, so that on the droplet /home/dokku/.ssh/authoreized_keys file contains something like "command="FINGERPRINT=13:9f:e7:8f:58:2e:54:46:19:c8:ae:d8:39:ce:8d:11 NAME="augusts" `cat /home/dokku/.sshcom..."

# you can remove remote with
  git remote rm dokku

# deploy a test app to a name
  git remote add dokku dokku@blogs.creative.gs:ruby-rails-sample
  git push dokku master

# deploy to subdomain
  git remote add dokku dokku@blogs.creative.gs:sub.dokku.me
  git push dokku master
  
# deploy to root domain
  git remote add dokku dokku@blogs.creative.gs:dokku.me
  git push dokku master
  
# In case you need to deploy from non-master branch do
  git push dokku <other_branch>:master

Make Rails app Dokku-friendly

You can learn a lot from the sample rails app for dokku

1. configure the environment file
production.rb https://gist.github.com/Epigene/ea6a1bd070b657189fbe
staging.rb    https://gist.github.com/Epigene/6a2b957285584de0f1c6
2. make sure you have rails_12_factor gem in production
gem 'rails_12factor', group: :production
3. make sure you have a procfile that starts puma
# in /Procfile
web: bundle exec puma -C config/puma.rb
4. make sure you have a decent puma.rb config file
# in /config/puma.rb
workers 2
threads 5, 5

preload_app!

rackup      DefaultRackup
port        ENV['PORT']     || 3000
environment ENV['RAILS_ENV'] || 'development'

on_worker_boot do
  # Worker specific setup for Rails 4.1+
  # See: https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#on-worker-boot
  ActiveRecord::Base.establish_connection
end

Setting up Services

App ENV

Output existing ENV settings

dokku config <app>

Define new settings For Rails apps it is key to define at least SECRET_KEY_BASE and BUILDPACK_URL. See this dokku discussion for buildback necessity

# use command `dokku config:set <app-name> <key>=<value> <another_key>=<value>`
# e.g.
  dokku config:set node-js-app KEY=\"VAL\ WITH\ SPACES\" ANOTHER_KEY="2"
  
# Producton example
  dokku config:set blog.swisslanguages BUILDPACK_URL=https://github.com/heroku/heroku-buildpack-ruby RAILS_ENV=production RACK_ENV=production SECRET_KEY_BASE=d2c7882551be2d54e3eaf0b5e03235096ef8997dbd3490de39d8ee055ae5dea5f210bf3400d3cd97a8cb37431f867da8ca67ad608e3c120ab0dff826455f95fc
  
# Staging example
  dokku config:set blog.swisslanguages RAILS_ENV=staging RACK_ENV=staging SECRET_KEY_BASE=d2c7882551be2d54n3eaf0b5e03235096ef8997dbd3490de39d8ee051ae5dea5f210bf3400d3cd97a8cb37431f867ga8ca67ad608e3c120ab0dff826455f95fc

Git for Private Repos

Navigate to /home/dokku/.deployment-keys/shared/.ssh and cat the id_rsa.pub, add contens to creative-deployer's ssh-keys

2. Add the host key plugin

Adding github should do the trick

dokku hostkeys:shared:autoadd github.com

Redis + Resque

1. Install the official redis plugin
sudo dokku plugin:install https://github.com/dokku/dokku-redis.git redis
2. Make a redis service (name the same as app for convenience)
# Modify the behavior of creator by setting ENV variables beforehand
# export REDIS_CUSTOM_ENV="PORT=6392"
dokku redis:create staging.app.swisslanguages.com
3. Link the service with the app
dokku redis:link redis_service app_name
4. Ensure resque task requirement
# in /lib/tasks/resque.rake

require 'resque/tasks'

task "resque:setup" => :environment
task "resque:work"
5. Boot worker(s) from procfile
# in /Procfile
worker: bundle exec rake resque:work TERM_CHILD=1 RESQUE_TERM_TIMEOUT=10 QUEUE=*

# or multi-worker boot
worker: bundle exec rake resque:workers COUNT=5 QUEUE="*"
6. Enable worker scaling

Consult the documentation for more.

dokku ps:scale creative_invoice_platform web=1 worker=1

SSL

Follow the documentation

dokku certs:generate <app> DOMAIN 

Maintenance

  dokku run <app_name> bundle exec rake db:migrate db:seed RAILS_ENV=production
  dokku run <app_name> rails c

Inspect defined models

Rails.application.eager_load!
ActiveRecord::Base.descendants

To redeploy without changes

  dokku ps:restart <app>
  
  # harder version
  dokku ps:rebuild <app>

Debugging

Container app not starting for some reason?

$ docker ps
$ docker logs -f <CONTAINER_ID>

To get shell inside a container

  # get containers by running `sudo docker ps`
  sudo docker run -it dokku/wp:latest /bin/bash

Custom NGINX.conf (redirects, exclusions etc)

Consult the official guide

sudo cp /home/dokku/<app>/nginx.conf /home/dokku/<app>/nginx.conf.template
sudo nano /home/dokku/<app>/nginx.conf.template
  # remove the first line containing the upstream
  # escape all dollar signs ($http_header becomes \$http_header)
  # add custom parts
  # dokku ps:rebuild <app>
  # cat /home/dokku/<app>/nginx.conf and see if it matches template (actual conf will have the upstream added)
# NB! Several domains (even www.domain.com and domain.com are DIFFERENT domains) must be added on seperate lines in VHOST file

Set up upload path (for assets you want to keep across deploys)

Consider this SO question

mkdir /home/dokku/shared/<app_name>/
sudo chmod 777 -R /home/dokku/shared
sudo chown dokku:dokku -R /home/dokku/shared
dokku docker-options:add myapp deploy "-v /home/dokku/shared/<app_name>/path/in/container:/path/in/container"
dokku docker-options:add myapp run "-v /home/dokku/shared/<app_name>/path/in/container:/path/in/container"

e.g.
dokku docker-options:add uz-veselibu.lv deploy "-v /home/dokku/shared/uz-veselibu.lv/media:/app/public/media"
dokku docker-options:add uz-veselibu.lv run "-v /home/dokku/shared/uz-veselibu.lv/media:/app/public/media"

To add additional SSH keys, run on the computer that wants to add:

  cat ~/.ssh/id_rsa.pub | ssh root@<IP> "sudo sshcommand acl-add dokku <key name>"
  e.g.
  cat ~/.ssh/id_rsa.pub | ssh root@146.185.130.153 "sudo sshcommand acl-add dokku deployer"

To remove a container

  # SSH onto the server, then execute:
  dokku delete myapp

DB dump manipulation

Give Staging server trimmed-down Production DB

1. Make a lite dump in production
dumpit_lite
2. Scp the s_latest.dump to local machine
scp NORD:/home/deployer/apps/nordenhealth/s_latest.dump ~/Desktop/

# you may want to see if it works locally
# rake db:drop db:create db:migrate
# psql -U <username> <db> < <file>
# e.g.
# psql -U augusts nord < /Users/augusts/Desktop/s_latest.dump
3. Scp the s_latest.dump from local to staging
# a single file
scp ~/Desktop/s_latest.dump STAGING:/home/dokku

# all files in a directory
scp ~/Desktop/files/* CPP:/home/deployer/apps/
4. Make sure the staging DB cen be partially restored
# not the seeds must be skipped
dokku run <app> bundle exec rake db:drop db:create db:migrate RAILS_ENV=staging
5. Run the restore command
# SQL-type dumps
dokku postgres:connect staging.v1.stockholmhealth < /home/dokku/s_latest.dump

# binary dumps
dokku postgres:import <app> < /home/dokku/s_latest.dump

Dump production, restore locally

# ssh into server, $ fish, $ dok
# dokku postgres:list
dokku postgres:export <name> > /home/dokku/latest.dump

# scp the dump
  # general
  scp_dokku (scp root@178.62.175.11:/home/dokku/latest.dump ~/Desktop/)

  # staging
  scp root@staging.creative.gs:/home/dokku/latest.dump

# restire the DB from dump, username directive may be unnecessary
pg_restore --verbose --clean --no-acl --no-owner -h localhost -U <username> -d <database> ~/Desktop/latest.dump

## OLD
psql --username=postgres <databasename> < data_base_dump.sql

Dump locally, restore in production

  # Dump it in sql form
    pg_dump -h localhost --username creative swiss > ~/latest.dump
    scp_swiss (scp it to own comp)
    # scp it to dokku server
      scp ~/Desktop/latest.dump deployer@82.196.9.147:/home/deployer/latest.sql
    # restore
      dokku postgresql:restore <app> < latest.sql
    # if fails, drop the db, run restore, migrate
      dokku postgresql:delete <app>
      dokku postgresql:create <app>
      dokku postgresql:link <app-name> <db-name>
      dokku postgresql:restore <app-name> < latest.sql
      dokku run <app> bundle exec rake db:migrate db:seed RAILS_ENV=staging
      (opt) dokku run <app> bundle exec rake clear:all_redundant_data RAILS_ENV=staging
    
      
    # TO CLEAN DISC, PERMANENTLY removing exited containers
      sudo docker ps -a | grep Exit | cut -d ' ' -f 1 | xargs sudo docker rm
@joshmn
Copy link

joshmn commented Jul 31, 2016

Also, I've had great success with dokku-letsencrypt!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment