DX Application Performance Management

 View Only

Creating Small Docker Images

By Guenter DI Grossberger posted Jun 21, 2018 12:48 PM

  

Docker images get big real fast. If you follow a few simple guidelines you can avoid bloated images and have image sizes in the megabytes not gigabytes.

 

I will use GitHub - CA-APM/docker-introscope as example - a project for running CA APM in Docker container forked from a customer and updated with every new release of CA APM. I need to update for version 10.7 SP 1 or - after reading this post - you should be able to do it yourself.

 

1. Use Minimal Base Images

You can start by using a full blown e.g. CentOS image or you can start with an Alpine linux image. The difference may nearly be a factor 10 in image size:

docker images
ca-standard-images/alpine-jre8    3.6        91ff24d2cd8a 5 months ago  82.5MB
ca-standard-images/centos72-java8 latest     f9de4f60691a 13 months ago 592MB
postgres                          9.6-alpine 6583932564f8 11 days ago   39.3MB
centos/postgresql-96-centos7      latest     33511160be06 3 weeks ago   337MB

So when you choose your (runtime) image, check the image size and look for "alpine" in the tag.

2. Use Multi-Stage Builds

I wrote "runtime image" above because the image that you build in need not be the image you run in:

Multi-stage builds are a new feature requiring Docker 17.05 or higher on the daemon and client. Multistage builds are useful to anyone who has struggled to optimize Dockerfiles while keeping them easy to read and maintain.

(Source: Use multi-stage builds | Docker Documentation)

You may need tools or packages (e.g. *-devel) in your build environment that you don't need in your runtime environment. For CA APM the installer binary (introscope${INTROSCOPE_VERSION}linuxAMD64.bin) alone has 1.6GB because it includes multiple components: the Enterprise Manager, WebView, the database installer, the ACC config server and AOP integration. As we want to build micro services we want to install just one of the components per image. And we don't need the installer once the installation is finished.

So we COPY the installer file to our build container, run the installer and then COPY just the INTROSCOPE_HOME directory to the runtime container.

So for the Enterprise Manager installation the Dockerfile looks like this (abbreviated, see GitHub - CA-APM/docker-introscope for full file):

FROM jeanblanchard/alpine-glibc as install
# install image

WORKDIR /opt/introscope-install
COPY ${INTROSCOPE_BIN} /opt/introscope-install/
COPY eula-introscope/ca-eula.txt SampleResponseFile.Introscope.txt /opt/introscope-install/

# run the installer and hotfix
RUN chmod +x ${INTROSCOPE_BIN} && \
./${INTROSCOPE_BIN} -f SampleResponseFile.Introscope.txt && \
cd ${INTROSCOPE_HOME} && \
jre/bin/java -jar /opt/introscope-install/APM${INTROSCOPE_HOTFIX}.jar


FROM jeanblanchard/alpine-glibc
# target image
LABEL version="10.7.0-HF3"
WORKDIR ${INTROSCOPE_HOME}
COPY --from=install ${INTROSCOPE_HOME}/ ./
COPY startup.sh /opt/introscope-install/

RUN chmod +x /opt/introscope-install/startup.sh
EXPOSE 5001 8081 8444
CMD /opt/introscope-install/startup.sh
  1. We start with out "install" image (line 1): jeanblanchard/alpine-glibc - this need not be the same as the target image below!
  2. Install any packages/tools you need for the build. - We don't need anything else.
  3. Next we copy the installer and other needed files into our container (lines 5-6).
  4. Then we run the installer (lines 9-12).
  5. Now we build our "target" image, again from jeanblanchard/alpine-glibc (line 15). This should be the smallest possible image that has all you need to run your application.
  6. Then we copy the installed application from our "install" image (line 19).
  7. Add everything else that we need: files, ports, volumes, CMD to run (lines 20-24).

The resulting "target" image has just 1.44 GB instead of 3.16 GB if we build in one stage. The difference is (mostly) the installer but could be even more if you need more tools to run your build (JDK, maven, ...).

3. Use Common Dockerfiles

In my example I build images for Enterprise Manager, WebView and ACC Config Server. The first 35 lines of the Dockerfiles of Enterprise Manager and WebView are exactly the same - only some of the copied files are different, e.g. the response file that contains the options for the silent installer.

If you put everything that is common between your images at the top of your Dockerfile and differences as far down as possible, not only the base images but also the resulting layers after the first few steps will be cached and re-used by Docker. 

Summary

Following these three guidelines has helped me reduce the size of the CA APM docker images significantly: more than half for the EM and for the Postgres DB to 40 MB vs 1.4 GB.

I'd be interested to hear how you put those rules to work or if you have other hints for building small Docker images.

3 comments
10 views