Simple Rails 5.2 application to demonstrate using Docker for production deployment. The application is a very simple kind of CMS (content management system) allowing to manage posts. Beside the boring CRUD functionality it has some non-default features.
This project aims to build a lean Docker image for use in production. Therefore it's based on the official Alpine Ruby image, uses multi-stage building and some optimizations that I described in my blog. This results in an image size of ~ 135MB (including the large wkhtmltopdf binary).
- Auto refresh via ActionCable: If a displayed post gets changed by another user/instance, it refreshes automatically using the publish/subscribe pattern
- Full text search via Elasticsearch and the Searchkick gem to find post content (with suggestions)
- Autocompletion with corejs-typeahead
- PDF export with wkhtmltopdf and the WickedPDF gem
- Editing HTML content with the WYSIWYG JavaScript editor Trix
- Uploading images directly to S3 with the Shrine gem and jQuery-File-Upload
- Display images as Gallery with the React Grid Gallery
- Background jobs with ActiveJob and the Sidekiq gem (to handle full text indexing, image processing and ActionCable broadcasting)
- Cron scheduling with Sidekiq-Cron to handle daily data updates from Wikipedia
- Permalinks using the FriendlyId gem
- Infinitive scrolling (using the Kaminari gem and some JavaScript)
- User authentication with the Clearance gem
- Sending HTML e-mails with Premailer and the Really Simple Responsive HTML Email Template
- Admin dashboards with Blazer gem
- Page specific JavaScript with Punchbox
- Bundle JavaScript libraries with Yarn
This project demonstrates my way of building Rails applications. The techniques used to build the app should not be considered as "best practice", maybe there are better ways to build. Any feedback would be appreciated.
There is a separate docker-compose.yml for every environment: development, test and production. The whole stack is divided into multiple different containers:
- app: Main part. It contains the Rails code to handle web requests (by using the Puma gem). See the Dockerfile for details. The image is based on the Alpine variant of the official Ruby image and uses multi-stage building.
- worker: Background processing. It contains the same Rails code, but only runs Sidekiq
- db: PostgreSQL database
- elasticsearch: Full text search engine
- memcached: Memory caching system (used from within the app via the Dalli gem)
- redis: In-memory key/value store (used by Sidekiq and ActionCable)
- backup: Regularly backups the database as a dump via CRON to an Amazon S3 bucket
For running tests using RSpec, there is an additional container:
- selenium: Standalone Chrome for executing system tests containing JavaScript
To start up the application in your local Docker environment:
git clone https://github.com/ledermann/docker-rails.git
cd docker-rails
docker-compose build
docker-compose run app yarn install
docker-compose up
Wait some minutes while the database will be prepared by fetching articles from Wikipedia. Then,
navigate your browser to http://[DOCKER_HOST]:[DOCKER_PORT]
.
Sign in to the admin account:
- Username:
[email protected]
- Password:
secret
Enjoy!
On every push, the test suite (including RuboCop checks) is run in public on Travis CI and in private on Gitlab CI.
On every successful Travis build, a new Docker image is pushed to Docker Hub.
The Docker image build for production is different from development or test. It includes precompiled assets only (no node_modules and no sources). The spec folder is removed and the Alpine packages for Node and Yarn are not installed.
The stack is ready to host with nginx proxy and letsencrypt-nginx-proxy-companion. See docker-compose.production.yml for example setup.
A demo installation is set up on https://docker-rails.georg-ledermann.de.