You can be surprised how much disk space Docker images can consume. In this article we will look at several ways of how to minimize your Docker image. We will build an image with Dante socks server as an example. Dante will not be installed from binary packages, but will be compiled by ourselves inside Docker image.
Beginning. Naive solution. Image size: 328MB.
Let’s create simple Dante config file danted.conf.
internal: 0.0.0.0 port = 1080 internal: :: port = 1080 external: eth0 errorlog: stderr logoutput: stdout socksmethod: username user.privileged: root user.unprivileged: nobody client pass { from: 0/0 to: 0/0 session.max: 200 log: error connect disconnect } socks pass { from: 0/0 to: 0/0 log: error connect disconnect }
Next, create Dockerfile.
FROM debian:stable RUN apt-get update RUN apt-get upgrade -y RUN apt-get install -y wget gcc make WORKDIR /root/ RUN wget ftp://www.inet.no/dante/files/dante-1.4.2.tar.gz RUN tar zxvf dante-1.4.2.tar.gz WORKDIR /root/dante-1.4.2 RUN ./configure RUN make RUN make install COPY danted.conf /etc/ RUN useradd testuser RUN echo "testuser:pass123pass" | chpasswd RUN echo "precedence ::ffff:0:0/96 100" >> /etc/gai.conf EXPOSE 1080 CMD sockd -f /etc/danted.conf
Building image… God, it weights 328M.
sudo docker build -t localhost/debian-danted:testing . sudo docker save -o danted.tar localhost/debian-danted:testing du -h danted.tar #328M danted.tar
Let’s minify it.
Tip #1. Use a smaller base image. Image size: 260MB.
If your app not depends on OS, consider using alpine linux image. This is very compact and popular OS for Docker base image.
If your app depends on OS, for example Debian, try to use more compact debian:stable-slim image.
Let’s change our base image to debian:stable-slim.
FROM debian:stable-slim RUN apt-get update RUN apt-get upgrade -y RUN apt-get install -y wget gcc make WORKDIR /root/ RUN wget ftp://www.inet.no/dante/files/dante-1.4.2.tar.gz RUN tar zxvf dante-1.4.2.tar.gz WORKDIR /root/dante-1.4.2 RUN ./configure RUN make RUN make install COPY danted.conf /etc/ RUN useradd testuser RUN echo "testuser:pass123pass" | chpasswd RUN echo "precedence ::ffff:0:0/96 100" >> /etc/gai.conf EXPOSE 1080 CMD sockd -f /etc/danted.conf
sudo docker build -t localhost/debian-danted:testing . sudo docker save -o danted.tar localhost/debian-danted:testing du -h danted.tar #260M danted.tar
A way better.
Tip #2. Don’t install recommended packages. Image size: 253MB.
Use apt with –no-install-recommends option. Install missing packages manually.
FROM debian:stable-slim RUN apt-get update RUN apt-get upgrade -y RUN apt-get install -y --no-install-recommends wget gcc make libc-dev WORKDIR /root/ RUN wget ftp://ftp.inet.no/pub/socks/dante-1.4.2.tar.gz RUN tar zxvf dante-1.4.2.tar.gz WORKDIR /root/dante-1.4.2 RUN ./configure RUN make RUN make install COPY danted.conf /etc/ RUN useradd testuser RUN echo "testuser:pass123pass" | chpasswd RUN echo "precedence ::ffff:0:0/96 100" >> /etc/gai.conf EXPOSE 1080 CMD sockd -f /etc/danted.conf
sudo docker build -t localhost/debian-danted:testing . sudo docker save -o danted.tar localhost/debian-danted:testing du -h danted.tar #253M danted.tar
Tip #3. Remove unused files and packages, but do it in the same Docker layer. Image size: 121MB.
By default, Docker creating a layer for each Dockerfile line. Layer consists of relative to the previous line or relative to base image (for the first line) changes. Files, removed in current layer, will not lower Docker image size – previous layer containing removed files stays unchanged.
Docker will not rebuild image from beginning if you will change only the last line of your Dockerfile, but this feature can significantly increase the image size.
Let’s move compilation, installation and removing into the one layer.
FROM debian:stable-slim RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends wget gcc make libc-dev && \ wget ftp://ftp.inet.no/pub/socks/dante-1.4.2.tar.gz -P /root && cd /root && tar zxvf dante-1.4.2.tar.gz && \ cd /root/dante-1.4.2 && ./configure && make && make install && \ rm -r /root/dante* && apt-get -y remove wget gcc make libc-dev && apt-get -y autoremove --purge && apt-get -y clean COPY danted.conf /etc/ RUN useradd testuser && echo "testuser:pass123pass" | chpasswd RUN echo "precedence ::ffff:0:0/96 100" >> /etc/gai.conf EXPOSE 1080 CMD sockd -f /etc/danted.conf
sudo docker build -t localhost/debian-danted:testing . sudo docker save -o danted.tar localhost/debian-danted:testing du -h danted.tar #121M danted.tar
Tip #4. Experimental squash build option. Image size: 120MB.
After building, Docker will take all the layers and collapse them into a single new layer. All intermediate layers can be removed. This collapsing can save a little bit of disk space.
Let’s change Docker config /etc/docker/daemon.json to allow experimental options.
{ "experimental": true, }
Restart Docker.
sudo systemctl restart docker
Rebuild image with squash option.
sudo docker build --squash -t localhost/debian-danted:testing . sudo docker save -o danted.tar localhost/debian-danted:testing du -h danted.tar #120M danted.tar
Tip #5. Using btrfs filesystem level compression. Image size: 56MB.
OK. We did all to minimize image size to transfer it through network. But what if we want to store a lot of images locally? Let’s try to use btrfs compression. We will create btrfs volume over a file for this example.
sudo apt install btrfs-progs sudo fallocate -l 2G /root/btrfs.tmp sudo mkfs.btrfs /root/btrfs.tmp sudo mount /root/btrfs.tmp /var/lib/docker -o compress-force=zstd
Let’s change Docker config /etc/docker/daemon.json to allow btrfs storage-driver.
{ "experimental": true, "storage-driver": "btrfs" }
Restart Docker, build image, remove unused dependencies.
sudo systemctl restart docker sudo docker build --squash -t localhost/debian-danted:testing . sudo docker run --restart=always -it -d --name danted localhost/debian-danted:testing sudo docker image prune -a sudo docker image rm debian:stable-slim
sudo apt install btrfs-compsize sudo compsize /var/lib/docker/ Processed 7481 files, 2121 regular extents (3468 refs), 4906 inline. Type Perc Disk Usage Uncompressed Referenced TOTAL 46% 56M 121M 192M none 100% 643K 643K 879K zstd 46% 56M 120M 191M
56MB. Very nice.
Check.
#sudo docker run --restart=always -it -d --name danted localhost/debian-danted:testing curl --proxy socks5://testuser:pass123pass@172.17.0.2:1080 innerlife.io
Here you should see my site content, which means Dante container is running and working.
Thank you!!1