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
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 .
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/
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)
Great job! Are you using different base and build images in your Dockerfile? It should get you further down in the size.
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!