Start With a Single Machine Application
If you don’t have one, the following will do:Configure Your Routes
Modifyconfig/routes.rb. Wrap your routes with:
get "up" line outside of this block.
Uncomment the root line.
Your final result will look something like this:
FLY_MACHINE_ID environment variable is not set, no prefix is required.
You can get a list of Machine ids using:
Starting a Second Machine
In order to prepare for a multiple Machine deployment, we are going to need to ensure that each request is routed to the correct Machine. We can accomplish this via middleware that makes use of the fly-replay response header. Place the following intoconfig/initializers/fly_router.rb:
fly deploy, then use the following command to create
a second Machine:
Optimizing your routes
This section is optional, and depends on a unique feature of Rails’ Hotwire implementation. At this point, many requests will end up making two hops: first to a nearby Machine then to the desired Machine. This increases latency of responses, particularly when it is necessary to wake two Machines to process the first request. Not much can be done to avoid this for the first request, but subsequent requests can route to the correct Machine using thefly-force-instance-id
request header.
Place the following into app/javascript/controllers/fly_router_controller.js:
<body> line in app/views/layouts/application.html.erb:
fly deploy.
Next steps
The above merely amounts to a proof of concept. A production application will likely make use of one or more of the following:- While putting the Machine id into the URL path is effective, it isn’t very ergonomic. A better solution would be have a registry of paths and their associated Machines.
- Implementing routing in middleware gets the job done, but
separating this out to a separate process using an application like
nginxcan have a number of advantages:fly-replayis limited to request payloads of one megabyte or less, which would affect features like file uploads. A reverse proxy might be a better solution.- support for custom subdomains as an alternative to path namespaces and scopes.
- authentication and serving static assets can be performed outside of your application.
- Add-ons like Phusion Passenger can enable you to run multiple instances of your application in one Machine.
- Monitoring becomes more crucial when you have hundreds or even dozens of independent Machines. Fly.io will combine your logs and while this addresses many problems, it doesn’t help deal with logs that are missing due to application or network problems. Consider having applications emit a heartbeat, and write monitoring software that looks for missing heartbeats and reports them as issues.
- While applying updates when all of the services for a single Machine are self contained is an easier problem then upgrading potentially interdependent services running live in production, it does come at a cost: a blue/green deployment is not possible so a focus on reducing startup times is necessary.
- Consider building an administrative web based interface for your application. User registration and Machine assignments are likely coupled in your workflow. While Fly.io provides a Machines API, you can go a long way with old-fashioned scripting using the flyctl command.
Backups
As mentioned above, backups are crucial. Items to explore:- LiteFS - Distributed SQLite. By itself, it supports failover situations naturally. Additional disaster recovery options are available.
- Sqlite3 databases are just files. Build a separate application to host backups and have your application periodically POST copies there.
- Rsync is a utility available with Linux distributions that can be used to efficiently copy changes between Machines.
- Run multiple Machines per cell so that you get the full benefits of traditional high availability configurations. If you have implemented an admin web UI, you can automate the deployment of new clusters easily.