When I tried to run the chatops application anago written in Elixir with GKE, it became a fairly heavy Rails-like capacity, so I verified how far it can be removed.
FROM elixir:latest
WORKDIR /app
ENV MIX_ENV=prod
RUN mix local.hex --force && \
  mix local.rebar --force
COPY mix.exs mix.exs
COPY mix.lock mix.lock
COPY config config
RUN mix deps.get --only prod && \
  mix deps.compile
COPY . .
CMD ["mix", "run", "--no-halt"]
The Dockerfile at the beginning looks like this. The size of the application built with this Dockerfile is as follows ...
docker images
##
REPOSITORY                                TAG             IMAGE ID       CREATED          SIZE
anago                                     latest          aa7e0779d912   2 seconds ago    1.27GB
If the size of a simple application with no images, JSON, or DB comes out as 1.27GB, you will definitely decide to go on a diet ...
The base image size of Elixir is as follows.
docker pull elixir
## docker images
REPOSITORY                                TAG             IMAGE ID       CREATED         SIZE
elixir                                    latest          83478b936eba   2 days ago      1.24GB
When I get a Go language container for comparison ...
docker pull golang
### docker images
REPOSITORY                                TAG             IMAGE ID       CREATED          SIZE
golang                                    latest          5f9d35ce5cfe   3 weeks ago      839MB
After all, the file size is about 30MB including the code of the built library. But the base image is 1.24GB in the first place ... Elixir is nearly 300MB heavier than the image of Go for comparison: upside_down:
I think that the entrance to the image size diet is to make the base image alpine, so I will change the base image.
docker pull elixir:alpine
## docker images
REPOSITORY                                TAG             IMAGE ID       CREATED         SIZE
elixir                                    alpine          dd10458addd0   2 days ago       84.9MB
Overwhelming shape! 96% reduction! Even if you add 30MB of application to this, it will be 114MB!
REPOSITORY                                TAG             IMAGE ID       CREATED              SIZE
anago                                     alpine          c8b8c08b7aef   About a minute ago   114MB
Successful dieting to less than 10% compared to the original size! !! Isn't this all right? : thinking:
Erlang has a mechanism called escript that consolidates an application into a single executable file. The executable file may be executable in an environment with the Erlang runtime. Does that mean it works with the image of Erlang: alpine? : thinking: Get the base image of Erlang: alpine right away.
docker pull erlang:alpine
## docker images
REPOSITORY                                TAG             IMAGE ID       CREATED          SIZE
erlang                                    alpine          daa6bbdd7458   2 weeks ago      69.4MB
Since Elixir runs on Erlang, the base image of Erlang may be lighter. It's about 15MB, but it's lightweight. Let's go with this! !!
So I added mix escript build to Dockerfile.
By the way, you don't need the source code, so let's do a multi-stage build.
FROM elixir:alpine as build
WORKDIR /app
ENV MIX_ENV=prod
RUN mix local.hex --force && \
  mix local.rebar --force
COPY mix.exs mix.exs
COPY mix.lock mix.lock
COPY config config
RUN mix deps.get --only prod && \
  mix deps.compile
COPY . .
RUN mix escript.build
FROM erlang:alpine
WORKDIR /app
COPY --from=build /app/anago /app/anago
This is Yoshi! : thumbsup:
When I try docker build again and look at the size: eyes:
REPOSITORY                                TAG             IMAGE ID       CREATED          SIZE
anago                                     erlang_alpine   a01f810d11dc   2 seconds ago    71.4MB
Succeeded in reducing the weight to 71.4MB! !! !! We have finally broken through the 100MB wall! !!
I originally intended to run this application with mix run --no-halt, but when I use escript, it ends immediately.
In such a case, if you write timer.sleep (: infinity), it will work all the time.
defmodule Anago.CLI do
  def main(_args) do
    :timer.sleep(:infinity)
  end
end
erlang: I think that alpine will be included at least, so I'm wondering how much it will be reduced by apk add erlang to alpine.
The vanilla alpine is only 5MB in size.
Let's create a Dockerfile that installs only erlang in alpine.
FROM alpine:latest
RUN apk add --no-cache erlang
Building this Dockerfile will reduce the result to 63.6MB! (Erlang has a capacity of about 58MB, so no more diet is possible) If you reduce it to this point, you will be worried that it will work properly, but when you come to this point, the goal has shifted to how much you can reduce the size, so I will build it including the application.
REPOSITORY                                TAG             IMAGE ID       CREATED             SIZE
anago                                     custom_alpine   fb1de28697a1   9 minutes ago       65.6MB
I came up to 65.6MB: tada:
By the way, I was able to execute this image properly: tada: (Wow ...) It seems that the limit of weight reduction is 63.6MB + escript because I think that the size limit of Erlang probably cannot reduce the weight any more.
Recommended Posts