Elixir Getting Started Guide

Looking to deploy Elixir on Fly? Check out the Elixir Getting Started guide: Build, Deploy and Run an Elixir Application · Fly

I hope it helps you experience the goodness and power of a globally connected and distributed Elixir cluster! Even if you don’t need to cluster anything, it can help you get up and running quickly.

2 Likes

The guide was updated from the initial release version. Here’s a changelog of sorts. :slight_smile:

ELIXIR GUIDE CHANGELOG 2021-05-03

  • Updated project and docs to remove --live option. LiveView doesn’t add anything to this HelloWorld example.
  • Release section updated
    • moved Fly networking explanation to the top
    • added section about mix release.init and configuring rel/env.sh.eex
  • Updated Dockerfile
    • changed base to hexpm/elixir with explanation
    • changed to match more of the Phoenix deploy guide’s example
  • Adds extra bonus section covering SSH and getting an IEx shell into production
2 Likes

Nice! I was looking for the SSH/IEx bit earlier when I was following this guide, so great timing there! What’s the reason for moving those lines of code into rel/env.sh.eex from entrypoint.sh out of interest? Love your podcast BTW!

2 Likes

The reason for moving the ENV out of entrypoint.sh is the ENV was only getting set when the application launched (using the Dockerfile CMD command). This worked fine for launching the application.

When logging in via SSH and running app/bin/hello_elixir remote, the ENV values weren’t set and it would fail to connect to the local running node. The hello_elixir part of the command is a generated shell script. When moving the config to rel/env.sh.eex, it gets generated into a env.sh script that gets auto-executed when running any release command. So it’s really the right place for it to live. Hope that makes sense!

I’m glad you like the podcast! I’d love to figure out a way to get more regular interaction with interested listeners. Maybe a Discord server?

2 Likes

Thanks for the explanation, that definitely makes sense. I’ll make these tweaks you’ve mentioned, having SSH/IEx so easily will be really useful. And FWIW I’d definitely be interested in joining a Discord server for Thinking Elixir :slight_smile:

1 Like

Let me know if the SSH portion goes well or if there’s something that can be updated to help it be more clear.

I’ve just made the same updates to my app and it’s working great, SSH and IEx worked no problems. Really nice! ssh-agent and fly ssh issue --agent is really slick too.

My only question, might be a long shot! but is there any way to get an Erlang observer pointing at an Elixir app on Fly? Perhaps using Wireguard like how I connect to Postgres in Fly locally?

1 Like

That is a good question. I don’t know yet. That would be really cool to get working. In the short-term, check out observer_cli

Add it to your project, then you can :observer_cli.start and get a nice terminal view of most of the information. It even adds some recon scripts for things like “top 5 processes for memory”, etc.

1 Like

@mcintyre1994 I got a Wireguard tunnel setup and an Observer session open to remote node! So yes, it works. However, it’s not entirely straight forward. I think most of it can be wrapped up into a script to make it easier. I’ll keep playing with it.

1 Like

ELIXIR GUIDE CHANGELOG 2021-05-06

  • Changed the rel/env.sh.eex file to use $FLY_APP_NAME for the node name. Updated the hello_elixir project and the guide.
  • Added section “Special Note on Clustering” that covers the above change and why we do it.
  • Removed the entrypoint.sh file and section from the guide
    • This was only being used for running the migrations and that has moved out now.
    • File was removed from repo and the Dockerfile’s reference was removed.
  • Updated "Customizing fly.toml" section
    • Added example of [deploy] config and added text to the guide about that change. This is how we can run migrations once on a deploy!
4 Likes

Wauw! Just went through the entire guide, and much to my surprise, everything just worked! Thanks for a superb guide, with great explanations. It was fairly easy to follow and I really liked that you took the time to explain the different steps.

Would be great to see an example/tutoral of how to configure libcluster as well and deploy the app as a distributed elixir cluster.

3 Likes

Thanks @mscno! I’m glad to hear it worked for you! I love the idea of going in to clustering, but that felt like overwhelming the guide. I should write that up separately and link to it.

If you want to check out how to do the clustering, you can find an example specifically aimed at fly.io here: tictac - my globally distributed, clustered game

There is info in the readme on running it locally clustered and the this config file is all that’s needed for libcluster!

So easy! I love it!

ELIXIR GUIDE CHANGELOG 2021-05-07

  • Added section to the end of the guide that covers clustering
    • covers adding libcluster and configuring it
    • covers scaling the application in single or multiple regions and seeing that it is clustered

@mscno, thanks for the suggestion on covering clustering an Elixir application. I added that today. I hope it helps!

Thanks for fixing, super easy to follow as well! Amazing how easy it was to setup :rocket:

2 Likes

@brainlid Thank you for the guide, it worked super well! Also thanks for your podcast, really enjoying it :slight_smile:

I’ve modified the Dockerfile to use the latest Elixir/Erlang versions, the things I had to modify/add were:

###
### Fist Stage - Building the Release
###
- FROM hexpm/elixir:1.11.2-erlang-23.3.2-alpine-3.13.3 AS build
+ FROM hexpm/elixir:1.12.0-erlang-24.0.1-alpine-3.13.3 AS build

+ # prevent hex timeout
+ ENV HEX_HTTP_TIMEOUT=20

###
### Second Stage - Setup the Runtime Environment
###

# prepare release docker image
FROM alpine:3.13.3 AS app
- RUN apk add --no-cache openssl ncurses-libs
+ RUN apk add --no-cache libstdc++ openssl ncurses-libs
2 Likes

@zimt28 Thanks for the tip! :heart:

Got the Elixir guide and hello_elixir project updated. :+1:

ELIXIR GUIDE CHANGELOG 2021-06-21

  • Updated Dockerfile example for Elixir 1.12 and OTP 24
  • Added 2nd stage dockerfile dependency for libstdc++ which is needed for runtime ETS table support
  • Updated the hello_elixir example repo

@brainlid, thanks for the guide. Surprisingly easy to get clustering set up!

A couple of minor things:

  1. Although likely obvious to many, might it be helpful to state when the second fly deploy is required, after the libcluster config has been added?

  2. When deploying or re-deploying, though the nodes are connected (I checked by accessing the interactive shell as per the guide) I get warnings in the logs (datacentre name made bold here for ease of reading):

    2021-06-22T13:04:55.765712833Z app[47501f25] ams [info] 13:04:55.762 [warn] [libcluster:fly6pn] unable to connect to :"{app name}@{ip address}"

    2021-06-22T13:04:55.816219860Z app[47501f25] ams [info] 13:04:55.813 [warn] [libcluster:fly6pn] unable to connect to :"{app name}@{ip address}"

    2021-06-22T13:04:56.022270251Z app[b6ef7f8f] lhr [info] 13:04:56.018 [error] ** Connection attempt from node :"{app name}@{ip address}" rejected. Invalid challenge reply. **

    2021-06-22T13:05:00.877738238Z app[47501f25] ams [info] 13:05:00.874 [warn] [libcluster:fly6pn] unable to connect to :"{app name}@{ip address}"

    2021-06-22T13:05:01.135994372Z app[b6ef7f8f] lhr [info] 13:05:01.132 [error] ** Connection attempt from node :"{app name}@{ip address}" rejected. Invalid challenge reply. **

    Is this expected? If so, perhaps it’s worth mentioning them so that they don’t cause undue concern.

    It seems like the connection “failure” warnings and errors are all in regard to connection from one of the two nodes to the other, and not in the other direction, so I’m thinking these warnings may occur because a connection has already been made.

Edit: Erlang 24.0.2 is now available, in case you want to update the guide to use that.

Thanks @doliver for the feedback! Your #1 is an easy one to do and a good idea.

As for #2, there are a couple things that can be at play here. If the clustering cookie isn’t explicitly given, then it is re-generated during the build/deploy process. This means the new nodes can’t connect to the old nodes because the cookies don’t match. It might also be that a shutting down node is rejecting connections because it is shutting down. When deploying a new release, it is common to see some log churn about connections being broken and rejected.

Mentioning that may be a good idea. :thinking:

Thanks for the Erlang version tip!