DEV Community

Jan Peterka
Jan Peterka

Posted on • Edited on

Deploying Rails app with Kamal - why is my image so big?

I'm currently in process of rewriting app from Python/Flask to Ruby/Rails, and one of changes is in deployment process.

I decided to use containers and Kamal, as it's upcoming default for Rails.
Mind you, I have no prior experience with neither Docker nor deployment tools like Capistrano.

There are many things that I got stuck on (and I plan to write about them maybe later), but today I was trying to solve one problem - images Kamal generated were about 3GB.
Whoa, that's a lot! It takes a long time to build, to upload to registry, to download to server. It's huge waste of resources!

I had to dig into it, and here's what I learned:

To find out how big my images really are (and compare before/after some changes), there's docker images. It lists all my images and their sizes.

But whats inside?
I found out about this handy command to show me what's contained inside the image:
docker history registry.example/example-all:latest
which shows me something like this:

IMAGE          CREATED              CREATED BY                                      SIZE      COMMENT
211b6b39d381   About a minute ago   CMD ["./bin/rails" "server"]                    0B        buildkit.dockerfile.v0
<missing>      About a minute ago   EXPOSE map[3000/tcp:{}]                         0B        buildkit.dockerfile.v0
<missing>      About a minute ago   ENTRYPOINT ["/rails/bin/docker-entrypoint"]     0B        buildkit.dockerfile.v0
<missing>      About a minute ago   USER rails:rails                                0B        buildkit.dockerfile.v0
<missing>      About a minute ago   RUN /bin/sh -c useradd rails --create-home -…   74.9MB    buildkit.dockerfile.v0
<missing>      About a minute ago   COPY /rails /rails # buildkit                   2.7GB     buildkit.dockerfile.v0
<missing>      17 minutes ago       COPY /usr/local/bundle /usr/local/bundle # b…   148MB     buildkit.dockerfile.v0
<missing>      18 minutes ago       RUN /bin/sh -c apt-get update -qq &&     apt…   148MB     buildkit.dockerfile.v0
<missing>      18 minutes ago       ENV RAILS_ENV=production BUNDLE_DEPLOYMENT=1…   0B        buildkit.dockerfile.v0
<missing>      19 minutes ago       WORKDIR /rails                                  0B        buildkit.dockerfile.v0
<missing>      8 weeks ago          CMD ["irb"]                                     0B        buildkit.dockerfile.v0
<missing>      8 weeks ago          RUN /bin/sh -c mkdir -p "$GEM_HOME" && chmod…   0B        buildkit.dockerfile.v0
<missing>      8 weeks ago          ENV PATH=/usr/local/bundle/bin:/usr/local/sb…   0B        buildkit.dockerfile.v0
<missing>      8 weeks ago          ENV BUNDLE_SILENCE_ROOT_WARNING=1 BUNDLE_APP…   0B        buildkit.dockerfile.v0
<missing>      8 weeks ago          ENV GEM_HOME=/usr/local/bundle                  0B        buildkit.dockerfile.v0
<missing>      8 weeks ago          RUN /bin/sh -c set -eux;   savedAptMark="$(a…   58.1MB    buildkit.dockerfile.v0
<missing>      8 weeks ago          ENV RUBY_DOWNLOAD_SHA256=cfb231954b8c241043a…   0B        buildkit.dockerfile.v0
<missing>      8 weeks ago          ENV RUBY_DOWNLOAD_URL=https://cache.ruby-lan…   0B        buildkit.dockerfile.v0
<missing>      8 weeks ago          ENV RUBY_VERSION=3.2.3                          0B        buildkit.dockerfile.v0
<missing>      8 weeks ago          ENV LANG=C.UTF-8                                0B        buildkit.dockerfile.v0
<missing>      8 weeks ago          RUN /bin/sh -c set -eux;  mkdir -p /usr/loca…   45B       buildkit.dockerfile.v0
<missing>      8 weeks ago          RUN /bin/sh -c set -eux;  apt-get update;  a…   46.5MB    buildkit.dockerfile.v0
<missing>      8 weeks ago          /bin/sh -c #(nop)  CMD ["bash"]                 0B        
<missing>      8 weeks ago          /bin/sh -c #(nop) ADD file:b86ae1c7ca3586d8f…   74.8MB    
Enter fullscreen mode Exit fullscreen mode

Here I saw that my problem lies in COPY rails/ rails/, meaning my app directory is huge.

Why's that? Here's another handy command to see that:
du --max-depth 1

This shows me size of directories inside my project:

8   ./.bundle
108 ./test
824388  ./.ruby-lsp
176 ./config
554380  ./vendor
56  ./lib
108 ./db
125260  ./tmp
28  ./bin
3034272 ./old
24  ./.kamal
39508   ./.git
8   ./.vscode
2300452 ./storage
232 ./spec
8216    ./app
20  ./public
427176  ./log
4614096 .
Enter fullscreen mode Exit fullscreen mode

The thing is, I started deploying from my laptop, so I have all this files that are not present when deploying from CI/CD (as would be optimal way).

So, we have /storage (with all files), /.ruby-lsp (from editor), /old (thats just some migration data), and /vendor.

I don't want these in my image!
Let's not include them:

# .dockerignore

old/
*.log

vendor/
tmp/
.ruby-lsp/
Enter fullscreen mode Exit fullscreen mode

After another build, I check my image again, and I got to much nicer ~600MB image.

There might be still some room for improvement, but I'm quite happy with this - my build time is down significantly, my self-hosted registry is not full of useless data, and I learned something new.

Top comments (2)

Collapse
 
tannakartikey profile image
Kartikey Tanna

Great job! Are you using different base and build images in your Dockerfile? It should get you further down in the size.

Collapse
 
janmpeterka profile image
Jan Peterka

Not sure what you mean by that 😅 (I'm complete newbie in Docker).
I'm using default Rails 7.2-generated Dockerfile..
Will be grateful for any pointers how to improve this!