In modern B/S architecture applications, we do front-end and back-end separation, and some front-end web services put the compiled static files to a web server for deployment. For example, my blog is also based on static files compiled by Hugo for deployment.

Then in containerized deployment mode, we need to build static files into a container image of a site or web service for deployment based on a base container (image) of the web service. In Docker development best practices, we should try to keep the image small enough (Size). Therefore, we should try to choose a web service base image that is small enough to meet our needs.

Docker image size

In most cases, we choose Nginx as our web server, and that’s what I chose at first, because the community provides us with out-of-the-box containers on Docker Hub image, here’s a look at the process I used to build the static web service.

NGINX ON ALPINE

We know that in container build practice, we can choose an image based on AlpineLinux as the distribution system, which is much smaller than other (e.g. ubuntu, centos, etc.) images. So at first we also chose an Alpine based nginx image, e.g. nginx:1.22-alpine.

1
2
3
4
$ docker image pull nginx:1.22-alpine

$ docker image ls | grep nginx
nginx    1.22-alpine    23.5MB

You can see that its size is 23.5MB.

Build the release image of my blog based on this image

1
2
3
4
5
6
FROM mengzyou/hugo:0.106 AS builder
COPY --chown=hugo:hugo . /home/hugo/app
RUN hugo

FROM nginx:1.22-alpine
COPY --from=builder /home/hugo/app/public/ /usr/share/nginx/html
1
2
3
4
$ docker build -t myblog:nginx .

$ docker image ls --format "{{.Repository}}\t{{.Tag}}\t{{.Size}}" | grep myblog
myblog  nginx   29MB

The size of the built and delivered image is 29MB.

Then I found a lightweight web server written in GoLang - easyhttpd, so I forked the project and wrote a Dockerfile to build an image of the web server, see the contents of that file for details.

I’ve published the image at mengzyou/easyhttpd.

1
2
$ docker image ls --format "{{.Repository}}\t{{.Tag}}\t{{.Size}}" | grep easyhttpd
mengzyou/easyhttpd      v0.0.1  13.7MB

The image size is 13.7MB, which is a dozen MB smaller than the nginx:alpine image, which I used to build my blog site.

1
2
3
...
FROM mengzyou/easyhttpd:v0.0.1
COPY --from=builder --chown=http:www /home/hugo/app/public/ /srv/www
1
2
3
$ docker image ls --format "{{.Repository}}\t{{.Tag}}\t{{.Size}}" | grep myblog
myblog  nginx   29MB
myblog  ehttpd  19.1MB

The resulting application image size is 19.1MB , which further reduces the application image size.

BUSYBOX HTTPD

I recently came across a blog post that allows building a web server image that is only ~155KB in size, and I was very curious to see if I could further reduce the size of my static site’s image size.

It is the built-in httpd of BusyBox that is used to serve web services with static files. So I also learned from that author and created a web server image based on busybox - httpd, naming it bbhttpd, please refer to the Github repository for the build details - docker- bbhttpd.

The image I built I also published to Docker Hub - mengzyou/bbhttpd

1
2
$ docker image ls --format "{{.Repository}}\t{{.Tag}}\t{{.Size}}" | grep bbhttpd
mengzyou/bbhttpd        1.35    155kB

The image size is really only 155KB, isn’t that amazing? Using this image to build my site.

1
2
3
...
FROM mengzyou/bbhttpd:1.35
COPY --from=builder --chown=www:www /home/hugo/app/public/ /home/www/html
1
2
3
4
docker image ls --format "{{.Repository}}\t{{.Tag}}\t{{.Size}}" | grep myblog
myblog  nginx   29MB
myblog  ehttpd  19.1MB
myblog  bbhttpd 5.64MB

The final delivered image size is only 1.64MB, which is almost the size of the web service static file.

Summary

According to the best practice of Docker container image building, we should try to keep the image size as small as possible, and one way to reduce the image size is to choose a small enough base image. So when we build static web services, we can greatly reduce the final image size by building the base image ourselves.

Base image nginx:1.22-alpne mengzyou/easyhttpd:v0.0.1 mengzyou/bbhttpd:1.35
Size 23.5MB 13.7MB 155KB