Erlang and Elixir in AWS Lambda using Container Images (part 1)

AWS recently announced container image support for AWS Lambda Functions, allowing you to run your Lambda functions in a custom Docker image that you supply. This opens up a wide variety of new possibilities for Lambda, including:

  • Runtime libraries pre-loaded in Lambda, reducing the need to package libraries with code
  • Test Lambda functions locally, in a near-identical containerized environment
  • Write Lambdas in any language you want

It is the third bullet point that I wish to explore in this series. Erlang and Elixir, two functional programming languages designed to support high-concurrency programming, based on technology that is well known for its ability to produce programs with a high degree of fault-tolerance and availability, are, to my mind, well-suited to the serverless model.

A picture of an elixir.

In this series I will go through the steps of building a containerized, highly concurrent application in Erlang and Elixir, containerizing the application for portability, making the container compatible with AWS Lambda, and finally, converting the code to be deployable to AWS Lambda, thus decoupling it from the container.

Creating the Docker Container

First things first — we will need a container to run all this stuff in. Containers make it very easy to distribute the runtime environment of your application, allowing other developers of your project to be up and running in minimal time.

This tutorial assumes that you have Docker installed.

To begin, we create our project directory:

mkdir erlambda
cd erlambda

Then we create a file named Dockerfile in the directory:

FROM public.ecr.aws/amazonlinux/amazonlinux:latest

RUN yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm -y
RUN yum install https://packages.erlang-solutions.com/erlang-solutions-2.0-1.noarch.rpm -y
RUN sed -i.bak "s/\$releasever/7/" /etc/yum.repos.d/erlang_solutions.repo
RUN yum install erlang elixir -y

CMD [ "/usr/bin/env", "bash" ]

Finally, we build and run our image:

docker build -t erlambda .
docker run -it erlambda

The first time you run docker build, it will take a few minutes to create the new image. Future runs are sped up considerably as it is not necessary to re-install the necessary packages. This will build the image and launch the container, and present you with a root-privileged command prompt inside the container:

bash-4.2#

You may use the commands erl and iex to verify that Erlang and Elixir are available to you. When you are done, type:

exit

and your container will be stopped; you will be returned to the command prompt. Hooray, your image is ready!

Erlang and Elixir Hello World

OK, now we have to write some code that actually uses this container. Time to write our obligatory `Hello, World` one-off that tests that we’re actually up and running.

Create a directory named src and add the file hello.erl to it, with the following contents:

-module(hello).
-export([hello_world/0]).

hello_world() -> io:fwrite("Hello, World, from Erlang!\n").

Next, edit Dockerfile and replace the last line with:

COPY src /src
WORKDIR /src

RUN erl -compile hello
CMD erl -noshell -s hello hello_world -s init stop

Finally, rebuild and rerun the container from the command line:

docker build -t erlambda .
docker run erlambda

If all goes well, you should see the output Hello, World, from Erlang! in your terminal.

Next, we want to test Elixir in the same container. Create a file hello_elixir.exs in your src directory with the following contents:

require :hello

IO.puts("Hello, World, from Elixir!")
:hello.hello_world()

Notice that this script imports the hello Erlang module defined above.

Next, update the last two lines of your Dockerfile (the RUN and CMD lines) to this:

RUN erl -compile hello
CMD elixir hello_elixir.exs

Repeatedly running the build and run docker commands is already becoming burdensome, so let’s extract that into run.sh :

#!/usr/bin/env bash

docker build -t erlambda .
docker run erlambda

Then run:

chmod +x run.sh
./run.sh

This should be your output:

Hello, World, from Elixir!
Hello, World, from Erlang!

In almost no time, we have created a Hello, World application utilizing Docker, Elixir, and Erlang. Pat yourself on the back, then spend some time playing with the Docker container, and the Erlang and Elixir code. Finally, buckle in for the sample application, which we will begin making in part 2.

Learn Docker: https://www.docker.com/101-tutorial

Learn Elixir: https://elixirschool.com/en/

Learn Erlang: https://learnyousomeerlang.com/

Devopsy guy with liberal tendencies.