I was playing with AWS. I’m just wondering how can I easily deploy Elixir application with Elastic Beanstalk. Quickly I found exrm. It’s a great tool for generating elixir/erlang project releases. So I added to my deps in mix.exs something like this:

{:exrm, "~> x.x.x"}

next step was to generate a release:

$ mix deps.get

$ mix release

After a while, the new release was generated! So I want to deploy it! Elastic Beanstalk supports docker. So let’s generate one. Quickly find a proper Dockerfile:

Let’s try build docker locally:

$ docker build -t myapp .

Wow, It build! Let’s move on, and try to run it!

$ docker run -t myapp

Unfortunately, my app using hakey and need and ssl stuff. After a lot of searching, I noticed that my release was build on mac. It simply will not work if there are packages that include erlang erts etc. After a while found another solution, that doesn’t include these things in the release. Added rel/relx.config:

{include_erts, true}. {include_src, false}.

Yes. It’s erlang file, dots are necessary. But this solution also won’t work. Tried added packages like erlang-erts, erlang-asn1 into docker image, but without any luck. So it will not work. So I was thinking about creating a docker that will create release… Sounds interesting. But first, let just run my elixir application on Beanstalk.

So I started to build another docker with following Dockerfile:

Tried it locally! Works. And on Beanstalk ?

$ eb deploy

Wow! Works. So I want to cleanup things a little. We don’t need all these files in a docker image anyway. I used .dockerignore file:

.git/

_build/

dist/

cover/

deps/

doc/

tarballs/

rel/

erl_crash.dump

*.ez

.edip.log

.*

OK, but what about Beanstalk ? Beanstalk uses a .ebignore file that can look exactly the same:

.git/

_build/

dist/

cover/

deps/

doc/

tarballs/

rel/

erl_crash.dump

*.ez

.edip.log

.*

So right now we send to Beanstalk only files that we need to build our docker image. Beanstalk doesn’t ignore all files in deps folder. I don’t know why, and really don’t know why few files were send. I check it with:

$ eb deploy — staged -v

Now everything works just fine, but this is a very stupid thing. I don’t need to upload source code of compiled language to the server. I don’t want to.

After a while, edib comes to the rescue! This tool uses exrm and docker to generate a proper release. This is what I was thinking of. Docker for building docker.

Great. Let’s run it! Add another dependency to mix.exs:

and let magic begins…

$ mix edib

Cool. Release generated, docker created! Now I can run it:

$ docker run --rm -e "PORT=4000" -p 4000:4000 local/myapp:0.0.0

It works. But how can I put it into Beanstalk ? I have an image tar.gz file in tarballs directory. But there must be a Dockerfile so beanstalk can create a proper image. OK lets try to build one:

We have to start from scratch.

Interesting think is that Beanstalk doesn’t allow us to create empty docker with FROM scratch directive, do I use one empty one. If you want to your docker image stays empty forever, you can create your own.

Next we need to add files from release archive to docker. We can use ADD directive. It will unarchive it for us. Just wonderful isn’t it ?

And yes it works on Beanstalk. You can deploy it with eb deploy. But wait. I have to cleanup our .dockerignore and .ebignore files. We only need tarball and Dockerfile. We can use ! directive like this:

The first line will ignore all things, and just not ignore tarballs and Dockerfile

And that’s it. We have a proper docker image only with compiled code. Also, we have to remember that within release we don’t have a mix. So things like migration will not work. There is a lot of solutions for that. Just google exrm release migration, you’ll find a few.

Right now, deploying to AWS is easy as deploying to Heroku. You just need to type: