Easily run a console in a new machine with `fly console`

In flyctl v0.0.557, we introduced a new command, fly console, to make it easier to run interactive tools like the Rails console and the Django shell for your apps. If you’re familiar with Heroku, it’s designed to provide a user experience similar to the original heroku console.

The usual way to do run an interactive console has been to write out a fly ssh console command, e.g.:

fly ssh console --pty -C "/rails/bin/rails console"

Besides being a lot to type, this runs the console in an existing instance of your app. By doing so, it’s possible to cause an out-of-memory crash or to otherwise disrupt your app. Also, if you have auto_stop_machines enabled for your app, the instance might be shut down due to low load while you’re working.

With fly console, you can define a console_command in your fly.toml. (If undefined, it currently defaults to /bin/sh.) Then, running fly console will run your console_command (no need to type the whole thing out now!) in a new machine.

The new machine is configured with the image and environment from your app’s latest release, but your app isn’t started, and no traffic will be routed to it. It’s just for running your console, and it gets destroyed when you’re done.

Under the hood, it works by creating a new machine that runs /bin/sleep inf instead of your app, and then connecting to it through SSH.

Example: querying a Django app’s database

# In fly.toml:
console_command = "/code/manage.py shell"
# Then, in a shell:
$ fly console
Created an ephemeral machine 7aeee04007847d to run the console.
Waiting for 7aeee04007847d to start ... done.
Connecting to fdaa:X:2... complete
Python 3.10.11 (main, May 3 2023, 09L:31L23) [GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.contrib.auth.models import Users
>>> for user in User.objects.all():
... print("{}: is_staff={}, is_superuser={}".format(user.username, user.is_staff, user.is_superuser))
...
matthew: is_staff=True, is_superuser=True
>>> ^D
now exiting InteractiveConsole...
Waiting for ephemeral runner machine 7aeee04007847d to be destroyed ... done.
$

Setting console_command

Here are a few suggestions for setting console_command for various frameworks:

# Rails:
console_command = "/rails/bin/rails console"

# Django:
console_command = "/code/manage.py shell"

# Laravel:
console_command = "php /var/www/html/artisan tinker"

(In future versions of flyctl, we’d like for fly launch to autofill this field based on your framework when creating a new app!)

Options

By default, fly console creates a shared-cpu-1x machine (the smallest size) for you. If necessary, you can adjust the size with --cpus and --memory.

If you’d like to run your console in an existing machine, you can specify the machine ID with --machine or select from a list with --select.

The console runs as root by default; --user will let you change that.

Caveats

Here are few things to be aware of:

  • fly console works only for v2 apps.
  • The working directory for commands is currently /.
  • For now, the command /bin/sleep needs to be in your image, and /bin/sleep inf needs to work as expected. (I’m hoping to lift this restriction in the future.)
  • The machines that fly console creates are billed like any other machine, so you may want to be careful not to leave them running for a long time.
  • fly console will do its best to warn you if it can’t clean up your machine when you’re done and suggest how to destroy it manually. However, if it’s suddenly terminated (e.g. SIGKILL), it won’t be able to do so.

Please let me know what you think or if you run into any issues!

16 Likes

This was super helpful! I was running into issues trying to run some basic commands in my ephemeral machine instance after fly console due to memory issues (parsing large CSVs) and I was unable to find this helpful info in the official docs. I was uncomfortable consoling into production instances. But I stumbled upon this, and now knowing that I can control the ephemeral machine specs when I’m rails console-ing in, is great!

4 Likes