Initial Dockerfile
Below is a minimal, multi-stage build, Dockerfiler that is capable of supporting both ActiveRecord and Action Cable:- For Active Record (or more precisely, sqlite3) to work, we need to add
pkg-configto the list of packages installed viaapt-get. - For Action Cable to work, we need to add
redisto the list of packages installed viaapt-get. --minimaland--skip-active-recordare removed from therails newline.- Since the example below uses Tailwindcss, we need to add
--css tailwindto therails newline. - We need to add
RUN bin/rails assets:precompileandRUN bin/rails db:prepareimmediately after theENV RAILS_ENV=productionline. - In order to see the log messages, add
ENV RAILS_LOG_TO_STDOUT=trueimmediately before theCMD bin/rails serverline. - We need to serve the assets. Chose one of the following two methods:
-
Set
ENV RAILS_SERVE_STATIC_FILES=true -
Add to the bottom of
fly.toml:
-
Set
Example application
In order to demonstrate Action Cable and Active Record functionality, we need a Rails application. Following is a simple visitors counter. Replace the three lines starting withCOPY <<-"EOF" config/routes.rb with the following:
- A
Vistormodel with a single counter column. - A
Counterchannel to send realtime updates. - A controller method that updates the model, broadcasts the results, and renders the initial page.
- HTML that connects to the channel, displays the fly.io logo, and renders a partial.
- A partial that shows the counter inside a turbo frame.
- A route that connects the root to the controller method we defined above.
Setting up Redis
Before we deploy this application, we need to create the redis database. We will be using Upstash for Redis, and creating the database and connecting it to the demo application is a matter of issuing two commands:redis create command.
And you don’t need to split the secrets set line, that was merely done to
fit in your browser window.
If you have deployed the minimal application previously,
at this point, your application has been redeployed, and you can visit the
page to see a counter. If you open multiple windows, each will be updated
simultaneously. If you haven’t launched and deployed the application previously
do it now.
Making a persistent sqlite3 database
The counter itself needs to be saved in a database, and by default that database is sqlite3 for Rails. For that database to be kept intact across deploys it needs to be placed on a volume. We can create a volume using the CLI:fly.toml:
db:prepare step needs to be run after
the volume is mounted, which means that it needs to run on the deployment
machine, not on the build machine. This means that in your Dockerfile
this needs to be done by the CMD statement not on a RUN statement.
Start by removing RUN bin/rails db:prepare, then replace the CMD
statement with:
flyctl volumes list to
find the volume id. Delete the volume using flyctl volumes delete.
Also remove the DATABASE_URL from the [env] section and
delete the [mounts] section.
Changing the database to Postgresql
Postgresql is an alternative to sqlite3. To use it, you will need to install a library and a gem:- Add
libpq-devto theapt-get installline. - Add
--database postgresqlto therails newline.
libpq.so that needs to be available at deploy time.
One approach is to add a copy line:
postgresql-client. Since this will be on the deploy image the multi-stage build
approach of install and copy only what you need needs to be reversed: install and remove
what you don’t need. That’s why you will often see lines like the following in Dockerfiles:
db:prepare exactly once per deploy rather than once
per vm. You can accomplish this by adding the following to your fly.toml:
Changing the database to MySQL
MySQL on Fly is more of a do it yourself kinda thing at the moment. Follow that guide to set up a MySQL application. Once you have it up and running, the instructions are roughly the same as with postgresql, with the following modifications:-
On the rails new line, specify
--database mysqlinstead of--database postgresql - default-libmysqlclient-dev is the package containing the mysql libraries.
- default-mysql-client is the package containing the mysql client.
-
Add the deploy release command to
fly.tomlfrom the postgresql instructions above. -
You need to run
fly secrets set DATABASE_URL=in your application. For postgresql this is taken care of for you by theflyctl postgres attachcommand. This will look something like the following:
Recap
- Adding databases require a lot of configuration:
- Much of the configuration involve actions outside your Dockerfile: i.e, setting up volumes, secrets, virtual machines, etc.
- While Dockerfiles don’t reduce the number of steps required, they do provide a place where these actions can be captured concisely and reproducible executed.
- Knowing what packages to add and where shared libraries are to be found is once again requires more knowledge of operating system conventions (in this case Debian) than Docker knowledge.