Hello,
Im curious about what yall are liking these days for running your Elixir / Phoenix app with a PostgreSQL database. I found these three (gigalixir, fly.io and render.com) and am curious if anyone have any pros and cons about them.
Thanks!
Hello,
Im curious about what yall are liking these days for running your Elixir / Phoenix app with a PostgreSQL database. I found these three (gigalixir, fly.io and render.com) and am curious if anyone have any pros and cons about them.
Thanks!
I’ve only tried fly.io, and even that not for anything in production, but can attest to its ease of use (and it’s apparently even easier now mix phx.release
can create docker images for you: https://twitter.com/chris_mccord/status/1468998944009166849). They’re very responsive on their forum.
Digital Ocean’s App Platform:
I’m really happy with it. Switched from Render because of the graphs and more responsive remote console - but that was before Render introduced the free tier.
Once you package your app into a Docker image, switching a provider is not that hard.
I was looking to run on render.com for a little project. I was all excited about their free tier but then saw that the DB will stop after 90 days unless you upgrade it to a paid version.
The pricing for DO App is awesome. What is the cheapest DB you can add?
I’m using the cheapest one: $15/mo, 1GB mem, 10GB disk.
I am using AWS Lightsail. Managed DB, S3, containers, LB and CDN.
The nice part is that you can move to a more involved setup if you outgrow simple hosting.
I didnt choose DO because their S3(spaces) back then had some troubles.
Some things I remembered from trying those out.
Gigalixir
Render
Fly
Kubernetes on Linode for both the app and the db because nice to not have any vendor lock-in. I played with fly.io and wow its very nice and easy. Much more expensive than linode but I would def consider them for any projects that need low latency across the world.
A couple of quick clarifications on Render:
There was a discussion at the beginning of the year about this (over here), don’t know if you missed it, might find more information for what you’re looking for.
Personally, i still use Scalingo (5 years for any stack, 2 years with Phoenix). Never had any issue (nothing worth mentioning anyway). There not worldwide (well, not like the others, there getting there, you can make a request for access to US based datacenters), so that depends on what you’re looking for i guess. Deployment, managed databases, there close to what Heroku provides, but without a lot of their limitations (they provide a free small database instance to go along a container for testing).
Is that a fairly recent addition? Please correct me if I’m wrong, but it was not there when I was running my app on Render. Overall I was really happy with Render - it works great for Docker-based apps.
One area that I’d like to see an improvement in general is basic log handling: some limited set of features to work with simple logs produced on STDOUT.
We added CPU and memory metrics in 2020!
Re: basic log handling, we now have native integrations with any syslog-compatible log provider including LogDNA and Datadog: Log Streams - Integrate with Third-Party Logging Providers | Render
We’ll build more logging features into Render at some stage, but it’s lower on the priority list given these integrations.
I recently published an article covering the best cloud hosting platforms for Elixir Phoenix on StakNine. I think the best options are Gigalixir, Fly, Render, or Heroku. The criteria included ease of use, so these options provided the easiest path to deploying.
I also published a post for each with steps for deploying a Phoenix app with a Postgres database.
But that’s my actual gripe - for simple setups I don’t want to spend time setting up log forwarding - I just want to see them in the dashboard and have basic tools for working with them.
Agreed, and duly noted.
Do you use the managed DB option (the managed DB separate from the DO App experience) or did you add a DB when you were doing through the DO App creation process?
I think I’ve added it during the app setup.
cool - how did you go about telling your elixir / phoenix app about the DB you created?
I got a bit confused because i was following this Deploying with Releases — Phoenix v1.6.4 and saw that they export the db string pretty early in the release process.
mix phx.gen.secret
REALLY_LONG_SECRET
export SECRET_KEY_BASE=REALLY_LONG_SECRET
export DATABASE_URL=ecto://USER:PASS@HOST/database
but if that db string is not available until after the App Platform is created…is a redeploy needed?
My app uses Phoenix 1.6 with esbuild and TailwindCSS. I’m building it with Docker, relying on runtime.exs
to handle the config and I pass everything via ENV vars.
Dockerfile
:
FROM hexpm/elixir:1.12.2-erlang-23.3.4.5-alpine-3.13.5 AS builder
# Install build tools.
RUN apk add --no-cache build-base nodejs=14.18.1-r0 npm=14.18.1-r0 git=2.30.2-r0
# Prepare build directory.
WORKDIR /app
# Copy the sources.
COPY . ./
# Install Hex and Rebar.
RUN mix local.hex --force && \
mix local.rebar --force
# Build in prod env.
ENV MIX_ENV=prod
# Get and build dependencies.
RUN mix deps.get && \
mix deps.compile
# Build assets.
RUN npm --prefix assets install && \
mix assets.build
# Assemble the release.
RUN mix release
# Prepare the release image.
FROM alpine:3.13.5 AS release
# Install dependencies:
# - Erlang requires ncurses-libs
# - the :ssl module dynamically links to openssl
RUN apk add --no-cache openssl ncurses-libs
WORKDIR /app
COPY --from=builder --chown=nobody:nobody /app/_build/prod/rel/app ./
# Use the user with minimal permissions.
RUN chown -R nobody:nobody /app
USER nobody:nobody
ENV HOME=/app
CMD ["sh", "-c", "bin/app eval MyApp.Release.migrate && bin/app start"]
config/runtime.exs
:
if config_env() == :prod do
config :my_app, MyApp.Repo,
ssl: true,
url: System.fetch_env!("DATABASE_URL"),
pool_size: System.fetch_env!("DATABASE_POOL_SIZE") |> String.to_integer()
end
In the app’s config, the DATABASE_URL
environmental variable is set to ${db.DATABASE_URL}
. Not sure what the syntax is, but it somehow references the managed DB and it just works. The database page has a “Connection details” dialog where you can show the “Connection string” if you need to set it explicitly.
Generally speaking, when building the Docker image, I only set ENV variables that are strictly necessary (MIX_ENV
, stuff like GIT_SHA
) because they are baked into the image. Changing the values requires rebuilding the image. The rest is read at runtime, so that I can change the config by just restarting the app.
At least that’s the theory. Some platforms will export the ENV variables during both the build time and runtime. Some platforms won’t allow me to restart the app without redeploying. But I like to keep it clean and separated - it will definitely help if I want to move to a different IaaS.