This guide provides some notes on how I used Dokku to deploy TeSS.
Dokku is a platform that allows easy deployment of apps via git (akin to Heroku) for applications that follow 12-factor principles.
My preferred setup:
- I like to use
docker-compose
in development. I follow the guide in the TeSS documentation to get this working. - I like to use Dokku in production. It makes zero-downtime upgrades a breeze. Steps below are intended to make this work.
- I prefer to use Rails credentials to minimize the number of secrets I need to communicate to my app through environment variables
- I have DNS setup so that I can have my Dokku apps as subdomains of my Dokku deployment host
(e.g.,
training.mydokkuhost.whatever
has same IP asmydokkuhost.whatever
)
My failings:
- Issues with the Solr setup documented
- I don't do anything for Sidekiq (I'm not sure all of the tasks it performs).
TeSS needs redis, PostGres and Solr. It uses Paperclip for uploads, so it also needs some persistent storage
mounted at public/system
(note: is there a better way?).
Here I assume that Dokku is installed on the host, and that the application we want to create is called training
.
I use similar names for the supporting services. Note that linking a service usually just
means Inject a very standard environment variable to find the service into the app
(e.g. DATABASE_URL
, REDIS_URL
, etc).
First we create the app:
dokku apps:create training
Next we create the Postgres database and link it to the training
app:
sudo dokku plugin:install https://github.com/dokku/dokku-postgres.git
dokku postgres:create training-db
dokku postgres:link training-db training
We now setup Redis and link it to the training
app:
sudo dokku plugin:install https://github.com/dokku/dokku-redis.git redis
dokku redis:create training-redis
dokku redis:link training-redis training
Now we setup Solr and connect it to the training
app (we'll need to modify the TeSS source a bit
to make this work, more on that elsewhere in this guide):
sudo dokku plugin:install https://github.com/dokku/dokku-solr.git solr
dokku solr:create training-solr
dokku solr:link training-solr training
Now we set up the persistent storage for assets:
dokku storage:ensure-directory training
dokku storage:mount training /var/lib/dokku/data/storage/training:/code/public/system
Now to setup some environment variables, one for the rails environment, another for the credentials master key, and one for serving static files (e.g., uploaded logos):
dokku config:set training RAILS_ENV=production
dokku config:set training RAILS_MASTER_KEY=[REDACTED]
dokku config:set training RAILS_SERVE_STATIC_FILES=Yes
I had some problem getting the Dokku Solr service reading the TeSS Solr config. See my comments on this issue. I'm not a Solr expert (and I didn't document this while doing it), but I may have had to do something nasty like uploading the conf to the Dokku host and doing a
sudo cp solr/conf/s* /var/lib/dokku/services/solr/training-solr/data/training_solr/conf
dokku solr:restart training-solr
There are more elegant ways of fixing this (move the xml files, fork the Dokku Solr plugin), but things at least work for me...
With things set up here, we would next want to set up our TeSS source code to have a Dokku git remote
(see docs),
and we push our code to this remote to deploy (while crossing fingers).
Here are some steps that I took while getting my app to work:
- Copy
config/tess.example.yml
toconfig/tess.yml
and alter.gitignore
so that it can be committed to your repository. This file is modified as indicated in the TeSS documentation. - Create your credentials file. See
bundle exec rails credentials:help
for guidance. You will want a master key for your credentials that you will use in production via the environment variableRAILS_MASTER_KEY
in production, but in development you can store this in the fileconfig/master.key
(.gitignore
is already set up mot to commit this file). - For the database configuration (
config/database.yml
), I replace most of settings for the production stanza (host
,database
, etc.) with the one line:url: <%= ENV['DATABASE_URL'] %>
(This variable gets set by linking the Dokku database with the Dokku app.) - I'll be honest, I'm not so sure how this works, but in
config/initializers/recaptcha.rb
I have:if Rails.application.credentials config.site_key = Rails.application.credentials.dig(:recaptcha, :sitekey) config.site_key = Rails.application.credentials.dig(:recaptcha, :secret) else config.site_key = Rails.application.secrets.recaptcha[:sitekey] config.secret_key = Rails.application.secrets.recaptcha[:secret] end
- For the seeds (
db/seeds.rb
) I have modified it to have:username = ENV["ADMIN_USERNAME"] || Rails.application.credentials.dig(:admin, :username) email = ENV["ADMIN_EMAIL"] || Rails.application.credentials.dig(:admin, :email) password = ENV["ADMIN_PASSWORD"] || Rails.application.credentials.dig(:admin, :password) if username && email && password puts "\nSeeding admin user" u = User.find_or_initialize_by(username: username, role: Role.find_by_name('admin')) u.update!(email: email, password: password, processing_consent: "1") unless u.persisted? end
- I use Sendgrid for sending emails, so in my credentials I have:
Insmtp: :address: smtp.sendgrid.net :user_name: [REDACTED] :password: [REDACTED] :port: 587 :authentication: plain :enable_starttls_auto: true
config/environments/production.rb
, I have in the section aboutsmtp
:
And inconfig.action_mailer.smtp_settings = Rails.application.credentials[:smtp] if Rails.application.credentials.key?(:smtp)
config/tess.yml
under theproduction
node I have:mailer: delivery_method: smtp
- Add a
app.json
file to configure the Dokku deployment:{ "name": "training", "description": "Deployment for training", "keywords": [], "scripts": { "dokku": { "predeploy": "bundle exec rake assets:precompile", "postdeploy": "bundle exec rake db:migrate" }, "postdeploy": "rake db:seed" } }