After attending a resume workshop I decided that I need to shorten some links. Instead of opting to use someone else’s link shortener I wanted something that felt more personal to me. Being Gleam curious I wanted to take it to the next level and ship something to production. After updating my Gleam version and reading more about their recent developer survey I saw that only 8% of respondents were using Gleam in production. In order to help encourage that number to go up I wanted to share my experience of shipping my URL shortener from Mac to Production. It is pretty cool to be using a language in the early days. Many of the best practices haven’t been invented yet. This really was the case with shipping to production, I saw almost no examples or instructions on how to ship this stuff.
I first discovered Gleam following the hype when it turned 1.0 and immediately fell in love with the strong use of pattern matching in the HTTP library, mist. In this blog post I’ll be shipping a modified sample hello world app from mist’s README (minus the file sending, that’s an exercise to the reader).
First off we’ll start a new Gleam project using gleam new <project_name>
.
Next we’ll add the dependencies using gleam add mist gleam_erlang gleam_http gleam_otp gleam_yielder
.
On to the shipping!
Unfortunately, the complexity of building extra C dependencies (like sqlite) for another architecture is extremely complicated. After spending way to long trying to bang my head against a rebar3 wall without documentation I just gave up and decided to eat the emulation performance.
TL;DR Cross compiling in rebar3 is hard so expect long compile times
Now to the juicy Gleam compile commands (and the full dockerfile)! I have never
shipped Gleam or Erlang or elixir code for that matter before so the concept of
building Erlang shipments are new to me. From what I can gather is that Gleam
generates our Erlang code and then bundles up all the dependencies with it into
a folder along with entrypoint.sh
which lets us start our app.
FROM ghcr.io/gleam-lang/gleam:v1.8.0-erlang-alpine
# add project code
COPY . /build/
# compile the project
RUN cd /build \
&& gleam export erlang-shipment \
&& mv build/erlang-shipment /app \
&& rm -r /build
# run the server
WORKDIR /app
EXPOSE 3000
ENTRYPOINT ["/app/entrypoint.sh"]
CMD ["run"]
Docker (or containerd) typically just assume that you are shipping on the same platform as your development environment. However, this is less and less the case with development boxes running Arm becoming increasingly common. Since we are targeting docker on an x86_64 chip we want to be sure that Docker builds for the right platform.
- Docker:
docker buildx --platform=linux/amd64 -t <registry-tag> .
- nerdctl:
n build --platform=amd64 -t <registry-tag> .
From here out it is just running a “standard” docker container. Push to a registry and then pull on your server. If you were running this on a VPS, and need to have a TLS/SSL reverse you could install Caddy and configure it to connect to the Gleam container via the following config:
your-domain-name.com {
reverse_proxy localhost:3000
}
And to run your container: docker run --restart=unless-stopped -d -p 3000:3000 <registry-tag>
Happy shipping!