Total Pageviews

Saturday 16 June 2018

A Simple Way To Dockerize Applications


Dockerizing an application is the process of converting an application to run within a Docker container. While dockerizing most applications is straight-forward, there are a few problems that need to be worked around each time.
Two common problems that occur during dockerization are:
  1. Making an application use environment variables when it relies on configuration files
  2. Sending application logs to STDOUT/STDERR when it defaults to files in the container’s file system
This post introduces a new tool: dockerize that simplifies these two common dockerization issues.

The Problems

Configuration

Many applications use configuration files to control how they work. Different runtime environments have different values for various sections of a file. For example, database connection details for a development environment would be different than a production environment. Similarly, API keys and other sensitive details would be different across environments.
There are a few ways to handle these environmental differences with docker containers:
  1. Embed all environment details in the image and use a control environment variable to indicate which file to use at run time. (e.g. APP_CONFIG=/etc/dev.config)
  2. Use volumes to bind mount the configuration data at run time
  3. Use wrapper scripts that modify configuration data with tools like sed that environment variable
Embedding all environment details is not ideal because environmental changes should not require a rebuild of an image. It’s also less secure since sensitive data such as API keys, login credentials, etc.. for all environments are stored in the image. Comprimising a development environment could leak production details. Having these kinds of details in any image should really be avoided.
Using volumes keep these details out of the image but makes deployment more complicated since you can no longer just deploy the image. You must also coordinate configuration file changes along with the image.
Injecting environment variables into custom files is not always trivial as well. You can sometimes craft a sed command or write some custom scripts to it but it’s repetitive work. This does produce an image that works well in a docker ecosystem though.

Logging

Docker containers that log to STDOUT and STDERR are easier to troubleshoot, monitor and integrate into a centralized logging system. Logs can be acessed directly with the docker logs command and through the docker logs API calls. There are also many tools that can automatically pull docker logs and ship them off if they log to STDOUT and STDERR.
Unfortunately, many applications log to one or more files on the file system by default. While this can usually be worked around, it’s tedious to figure out the nuances of each applications logging configuration.

Using Dockerize

dockerize is a small Golang application that simplifies the dockerization process by:
  1. Generating configuration files using templates and the containers environment variables at startup
  2. Tailing arbitrary log files to STDOUT and STDERR
  3. Starting a process to run within the container

An Example

To demonstrate how it works, we’ll walk through dockerizing a generic nginx container with dockerize. We start with:
FROM ubuntu:14.04

# Install Nginx.
RUN echo "deb http://ppa.launchpad.net/nginx/stable/ubuntu trusty main" > /etc/apt/sources.list.d/nginx-stable-trusty.list
RUN echo "deb-src http://ppa.launchpad.net/nginx/stable/ubuntu trusty main" >> /etc/apt/sources.list.d/nginx-stable-trusty.list
RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C300EE8C
RUN apt-get update
RUN apt-get install -y nginx

RUN echo "daemon off;" >> /etc/nginx/nginx.conf

EXPOSE 80

CMD nginx
Next we’ll install dockerize and run nginx through it:
FROM ubuntu:14.04

# Install Nginx.
RUN echo "deb http://ppa.launchpad.net/nginx/stable/ubuntu trusty main" > /etc/apt/sources.list.d/nginx-stable-trusty.list
RUN echo "deb-src http://ppa.launchpad.net/nginx/stable/ubuntu trusty main" >> /etc/apt/sources.list.d/nginx-stable-trusty.list
RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C300EE8C
RUN apt-get update
RUN apt-get install -y wget nginx

RUN echo "daemon off;" >> /etc/nginx/nginx.conf

RUN wget https://github.com/jwilder/dockerize/releases/download/v0.0.1/dockerize-linux-amd64-v0.0.1.tar.gz
RUN tar -C /usr/local/bin -xvzf dockerize-linux-amd64-v0.0.1.tar.gz

ADD dockerize /usr/local/bin/dockerize

EXPOSE 80

CMD dockerize nginx
Nginx logs to two different log files under /var/log/nginx by default. It would be nice have the nginx access and error log streamed to the console if your run this container interactively or if you docker logs nginx so you can see what’s happening.
We can fix that by passing -stdout <file> and -stderr <file> as command-line options. These can also be passed multiple times if there are several files to tail.
CMD dockerize -stdout /var/log/nginx/access.log -stderr /var/log/nginx/error.log nginx
Now when you run the container, nginx logs are available via docker logs nginx.
To demonstrate the templating, we’ll make this a into a more generic proxy server than can be configured using environment variables. We’ll define the environment variable PROXY_URL to be a URL of a site to proxy.
PROXY_URL="http://jasonwilder.com"
When the container is started with this variable, dockerize will use it to generate an nginx server location path.
Here’s the template:
{% raw %}
server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    root /usr/share/nginx/html;
    index index.html index.htm;

    # Make site accessible from http://localhost/
    server_name localhost;

    location / {
      access_log off;
      proxy_pass {{ .Env.PROXY_URL }};
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

{% endraw %}
Then our final Dockerfile would look like:
FROM ubuntu:14.04

# Install Nginx.
RUN echo "deb http://ppa.launchpad.net/nginx/stable/ubuntu trusty main" > /etc/apt/sources.list.d/nginx-stable-trusty.list
RUN echo "deb-src http://ppa.launchpad.net/nginx/stable/ubuntu trusty main" >> /etc/apt/sources.list.d/nginx-stable-trusty.list
RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C300EE8C
RUN apt-get update
RUN apt-get install -y wget nginx

RUN echo "daemon off;" >> /etc/nginx/nginx.conf

RUN wget https://github.com/jwilder/dockerize/releases/download/v0.0.1/dockerize-linux-amd64-v0.0.1.tar.gz
RUN tar -C /usr/local/bin -xvzf dockerize-linux-amd64-v0.0.1.tar.gz

ADD default.tmpl /etc/nginx/sites-available/default.tmpl

EXPOSE 80

CMD dockerize -template /etc/nginx/sites-available/default.tmpl:/etc/nginx/sites-available/default 
-stdout /var/log/nginx/access.log -stderr /var/log/nginx/error.log nginx
The -template <src>:<dest> options indicates that the template at /etc/nginx/sites-available/default.tmpl should be generated and written to /etc/nginx/sites-available/default. Multiple templates can be specified as well.
Run this container with:
$ docker run -p 80:80 -e PROXY_URL="http://jasonwilder.com" --name nginx -d nginx
You can then access http://localhost and it will proxy to this site.
This is a simplistic example but it can easily be extended using the embedded split function and range statement to handle multiple proxy values or other options. There are also a few other template functions available.

Conclusion

While this example is somewhat simplistic, many applications need some shims to make them run well within docker. dockerize is a generic utility to help with this process.
You can find the code at jwilder/dockerize.

from  http://jasonwilder.com/blog/2014/10/13/a-simple-way-to-dockerize-applications/
https://github.com/jwilder/dockerize

另外一个办法:https://github.com/elifarley/container-entrypoint
--------------------


Squashing Docker Images

A common problem when building docker images is that they can get big quickly. A base image can be a tens to hundreds of MB in size. Installing a few packages and running a build can easily create a image that is a 1GB or larger. If you build an application in your container, build artifacts can stick around and end up getting deployed.
Large images are problematic when you start publishing images to a registry. More layers creates more requests and larger layers take longer to transfer. Unfortunately, deleting things in later layers does not actually remove them from the image due to the way AUFS layers work.
There are a few options to address this problem but this post will show you how you can squash your images to make them smaller without requiring big changes to your development and deployment workflow.

Other Solutions

Other people have written about this problem as well and have tried different solutions to the problem.

Using Small Base Images

A few strategies rely on starting with very small base images. For example, you could use buildroot and craft a barebones image. There is also the very small scratch base image that could be a starting point. Another strategy is to install a binary package into your container. If you’re using Go, building static binaries might be an option.
These options are pretty sophisticated and might work for you but they may not fit your development workflow easily. While deploying static binaries would work well for Go projects, it can be complicated if you have Python, Node or Ruby projects that may just wrap C libraries.

Publishing Tools

Another set of options out there are separate tools for modifying and creating new images from existing images. There is a python script, docker-flatten, docker-compile.pl and docker-rebase.rb as well as just runing docker export <id> | docker import -.
Unfortunately, I wasn’t able to get any of these tools to work and the docker export trick loses Dockerfile attributes such as PORT, VOLUMES, etc. which causes other problems.

Official Support

Fortunately, docker appears to be aware of the problem with large images so hopefully this problem won’t require custom tools to solve. There is already a docker squash pull request (4232), a Dockerfile syntax change proposal (7115), a squash build dependencies proposal (6906) as well as a flatten images proposal (332).
Hopefully one or more of these will address the problem in the future.

docker-squash

Since this is a problem that affects me currently, I created a tool to squash images before pushing them to a registry. docker-squashis a standalone Go application that works similarly to the idea described in 332. It’s intended to be used as a publishing tool in your workflow and would be run before pushing to a registry.
The way it works is that you save, squash and load an image with something like docker save <ID> | docker-squash -t <TAG> [-from <ID>] | docker load.
The resulting image has all of the layers beneath the initial FROM layer squashed into a single layer. The other layers defining PORT, etc.. are retained as well.
The default options retains the base image layer so that it does not need to be repeatedly transferred when pushing and pulling updates to the image.

Example

I have a simple Go test image called jwilder/whoami that I’ll use as an example. When you run it, it listens on a port 8080 and returns the hostname of the container over HTTP.

Starting Image

Viewing it’s history shows that it’s pretty big (423.7MB) for just simple 20 line Go app.
$ docker images jwilder/whoami
REPOSITORY          TAG                 IMAGE ID            CREATED              VIRTUAL SIZE
jwilder/whoami      latest              63e174c2ca3d        29 minutes ago       423.7 MB
Viewing the history shows how the size is broken down between the layers:
$ docker history jwilder/whoami:latest
IMAGE               CREATED             CREATED BY                                      SIZE
63e174c2ca3d        14 seconds ago      /bin/sh -c #(nop) CMD [/app/http]               0 B
e4eea4411c00        14 seconds ago      /bin/sh -c #(nop) EXPOSE map[8000/tcp:{}]       0 B
c50f2b65cab3        14 seconds ago      /bin/sh -c #(nop) ENV PORT=8000                 0 B
589338fba5eb        15 seconds ago      /bin/sh -c go build -o http                     7.031 MB
651626d6e364        15 seconds ago      /bin/sh -c #(nop) WORKDIR /app                  0 B
8dfc0bb00563        16 seconds ago      /bin/sh -c #(nop) ADD dir:78239d85b32dd28e4cb   21.8 kB
fc294d2b22cb        17 seconds ago      /bin/sh -c apt-get update && apt-get install    191.3 MB
c4ff7513909d        3 days ago          /bin/sh -c #(nop) CMD [/bin/bash]               0 B
cc58e55aa5a5        3 days ago          /bin/sh -c apt-get update && apt-get dist-upg   32.67 MB
0ea0d582fd90        3 days ago          /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/   1.895 kB
d92c3c92fa73        3 days ago          /bin/sh -c rm -rf /var/lib/apt/lists/*          0 B
9942dd43ff21        3 days ago          /bin/sh -c echo '#!/bin/sh' > /usr/sbin/polic   194.5 kB
1c9383292a8f        3 days ago          /bin/sh -c #(nop) ADD file:c1472c26527df28498   192.5 MB
511136ea3c5a        14 months ago
Breaking this down:
  • 225.4MB - 511136ea3c5a..c4ff7513909d is the ubuntu:14.04 base image.
  • 191.3MB - fc294d2b22cb is installing the Go SDK (golang-go)
  • 7MB - 589338fba5eb builds my app

Clean Up

I don’t want to ship the Go SDK with my image. There is also a bunch of left-over apt-get cache data, as well as some extra packages I don’t need. I’ll remove them in a new container.
$ docker run -it jwilder/whoami:latest /bin/bash
root@5fe8a50718c3:/app# apt-get purge -y man  perl-modules vim-common vim-tiny \
> libpython3.4-stdlib:amd64 python3.4-minimal xkb-data \
> libx11-data eject python3 locales golang-go
...
$ root@5fe8a50718c3:/app# apt-get clean autoclean
$ root@5fe8a50718c3:/app# apt-get autoremove -y
$ root@5fe8a50718c3:/app# rm -rf /var/lib/{apt,dpkg,cache,log}/
$ root@5fe8a50718c3:/app# exit

Squash The Image

Next I need to create a image from that container:
$ docker commit 5fe8a50718c3
49b5a7a88d5353fe77204ad5591a3ef100fc2807a9d6dce979fd1b17a73a68d6
Then I’ll save, squash and load it. I’m tagging the new image with -t jwilder/whoami:squash:
$ docker save 49b5a7a88d5 | sudo docker-squash -t jwilder/whoami:squash | docker load
If you run docker-squash with the -verbose option, you can see what it’s actually doing to the image.
$ docker save 49b5a7a88d5 | sudo docker-squash -t jwilder/whoami:squash -verbose | docker load
Loading export from STDIN using /tmp/docker-squash683466637 for tempdir
Loaded image w/ 15 layers
Extracting layers...
  -  /tmp/docker-squash683466637/49b5a7a88d5353fe77204ad5591a3ef100fc2807a9d6dce979fd1b17a73a68d6/layer.tar
  -  /tmp/docker-squash683466637/651626d6e364ccc22ac990ba95cd0aab9256c56055087cc9a5a1790cea5250b9/layer.tar
  -  /tmp/docker-squash683466637/c50f2b65cab3b74f9bdb6f616b36f132b9a182ed883d03f11173e32fa39ab599/layer.tar
  -  /tmp/docker-squash683466637/d92c3c92fa73ba974eb409217bb86d8317b0727f42b73ef5a05153b729aaf96b/layer.tar
  -  /tmp/docker-squash683466637/511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158/layer.tar
  -  /tmp/docker-squash683466637/1c9383292a8ff4c4196ff4ffa36e5ff24cb217606a8d1f471f4ad27c4690e290/layer.tar
  -  /tmp/docker-squash683466637/589338fba5eb5cc32a25a036975a5e0938f12eff0dc70b661363c13ef1a192a5/layer.tar
  -  /tmp/docker-squash683466637/63e174c2ca3d53e2b7639a440940e16e15c1970e6ad16f740ffdcc60e59e0324/layer.tar
  -  /tmp/docker-squash683466637/9942dd43ff211ba917d03637006a83934e847c003bef900e4808be8021dca7bd/layer.tar
  -  /tmp/docker-squash683466637/0ea0d582fd9027540c1f50c7f0149b237ed483d2b95ac8d107f9db5a912b4240/layer.tar
  -  /tmp/docker-squash683466637/8dfc0bb00563dab615dfcc28ab3e338089f5b1d71d82d731c18cbe9f7667435f/layer.tar
  -  /tmp/docker-squash683466637/c4ff7513909dedf4ddf3a450aea68cd817c42e698ebccf54755973576525c416/layer.tar
  -  /tmp/docker-squash683466637/cc58e55aa5a53b572f3b9009eb07e50989553b95a1545a27dcec830939892dba/layer.tar
  -  /tmp/docker-squash683466637/e4eea4411c0065f8b0c7cf6be31dd58daa5ac04d8c64d54537cbfce2eb8e3413/layer.tar
  -  /tmp/docker-squash683466637/fc294d2b22cb53cb2440ff6fece18813ee7363f5198f5e20346abfcf7cce54fe/layer.tar
Inserted new layer 27935276f797 after 1c9383292a8f
  -  511136ea3c5a
  -  1c9383292a8f /bin/sh -c #(nop) ADD file:c1472c26527df28498744f9e9e8a8304c
  -> 27935276f797 /bin/sh -c #(squash) from 1c9383292a8f
  -  9942dd43ff21 /bin/sh -c echo '#!/bin/sh' > /usr/sbin/policy-rc.d  && echo
  -  d92c3c92fa73 /bin/sh -c rm -rf /var/lib/apt/lists/*
  -  0ea0d582fd90 /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/\1/g' /etc/apt/
  -  cc58e55aa5a5 /bin/sh -c apt-get update && apt-get dist-upgrade -y && rm -
  -  c4ff7513909d /bin/sh -c #(nop) CMD [/bin/bash]
  -  fc294d2b22cb /bin/sh -c apt-get update && apt-get install -y golang-go
  -  8dfc0bb00563 /bin/sh -c #(nop) ADD dir:78239d85b32dd28e4cb1d81ace7ffd32b8
  -  651626d6e364 /bin/sh -c #(nop) WORKDIR /app
  -  589338fba5eb /bin/sh -c go build -o http
  -  c50f2b65cab3 /bin/sh -c #(nop) ENV PORT=8000
  -  e4eea4411c00 /bin/sh -c #(nop) EXPOSE map[8000/tcp:{}]
  -  63e174c2ca3d /bin/sh -c #(nop) CMD [/app/http]
  -  49b5a7a88d53 /bin/bash
Squashing from 27935276f797 into 27935276f797
  -  Deleting whiteouts
  -  Rewriting child history
  -  Removing 9942dd43ff21. Squashed. (/bin/sh -c echo '#!/bin/sh' > /usr/sbin/policy-...)
  -  Removing d92c3c92fa73. Squashed. (/bin/sh -c rm -rf /var/lib/apt/lists/*)
  -  Removing 0ea0d582fd90. Squashed. (/bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/\1...)
  -  Removing cc58e55aa5a5. Squashed. (/bin/sh -c apt-get update && apt-get dist-upgra...)
  -  Replacing c4ff7513909d w/ new layer 72391e640b52 (/bin/sh -c #(nop) CMD [/bin/bash])
  -  Removing fc294d2b22cb. Squashed. (/bin/sh -c apt-get update && apt-get install -y...)
  -  Removing 8dfc0bb00563. Squashed. (/bin/sh -c #(nop) ADD dir:78239d85b32dd28e4cb1d...)
  -  Replacing 651626d6e364 w/ new layer bd7b4b11874a (/bin/sh -c #(nop) WORKDIR /app)
  -  Removing 589338fba5eb. Squashed. (/bin/sh -c go build -o http)
  -  Replacing c50f2b65cab3 w/ new layer e4af8871b961 (/bin/sh -c #(nop) ENV PORT=8000)
  -  Replacing e4eea4411c00 w/ new layer 6803497b6a61 (/bin/sh -c #(nop) EXPOSE map[8000/tcp:{}])
  -  Replacing 63e174c2ca3d w/ new layer 40b8c7c33bba (/bin/sh -c #(nop) CMD [/app/http])
  -  Removing 49b5a7a88d53. Squashed. (/bin/bash)
Tarring up squashed layer 27935276f797
Removing extracted layers
Tagging 40b8c7c33bba as jwilder/whoami:squash
Tarring new image to STDOUT
Done. New image created.
  -  40b8c7c33bba Less than a second /bin/sh -c #(nop) CMD [/app/http] 3.072 kB
  -  6803497b6a61 Less than a second /bin/sh -c #(nop) EXPOSE map[8000/tcp:{}] 3.072 kB
  -  e4af8871b961 Less than a second /bin/sh -c #(nop) ENV PORT=8000 3.072 kB
  -  bd7b4b11874a Less than a second /bin/sh -c #(nop) WORKDIR /app 3.072 kB
  -  72391e640b52 Less than a second /bin/sh -c #(nop) CMD [/bin/bash] 3.072 kB
  -  27935276f797 1 seconds /bin/sh -c #(squash) from 1c9383292a8f 39.49 MB
  -  1c9383292a8f 3 days /bin/sh -c #(nop) ADD file:c1472c26527df28498744f9e9e8a83... 201.6 MB
  -  511136ea3c5a 14 months  1.536 kB
Removing tempdir /tmp/docker-squash683466637
My squashed layer is down from ~198MB to 39.5MB. Roughly 80% smaller. I should be able to get it down to ~7MB if I squash some of the apt-get updates my build pulled in with the upstream ubuntu:14.04 base image and use a custom base image.
If I was to create a custom base image, I would squash that entire image down to a single layer using -from root and update my Dockerfile to use it as the FROM image.
This is what -from root looks like with my example images:
$ docker save 49b5a7a88d5 | sudo docker-squash -t jwilder/whoami:squash -verbose -from root | docker load
Loading export from STDIN using /tmp/docker-squash627981871 for tempdir
Loaded image w/ 15 layers
Extracting layers...
  -  /tmp/docker-squash627981871/d92c3c92fa73ba974eb409217bb86d8317b0727f42b73ef5a05153b729aaf96b/layer.tar
  -  /tmp/docker-squash627981871/cc58e55aa5a53b572f3b9009eb07e50989553b95a1545a27dcec830939892dba/layer.tar
  -  /tmp/docker-squash627981871/1c9383292a8ff4c4196ff4ffa36e5ff24cb217606a8d1f471f4ad27c4690e290/layer.tar
  -  /tmp/docker-squash627981871/63e174c2ca3d53e2b7639a440940e16e15c1970e6ad16f740ffdcc60e59e0324/layer.tar
  -  /tmp/docker-squash627981871/8dfc0bb00563dab615dfcc28ab3e338089f5b1d71d82d731c18cbe9f7667435f/layer.tar
  -  /tmp/docker-squash627981871/c4ff7513909dedf4ddf3a450aea68cd817c42e698ebccf54755973576525c416/layer.tar
  -  /tmp/docker-squash627981871/0ea0d582fd9027540c1f50c7f0149b237ed483d2b95ac8d107f9db5a912b4240/layer.tar
  -  /tmp/docker-squash627981871/9942dd43ff211ba917d03637006a83934e847c003bef900e4808be8021dca7bd/layer.tar
  -  /tmp/docker-squash627981871/c50f2b65cab3b74f9bdb6f616b36f132b9a182ed883d03f11173e32fa39ab599/layer.tar
  -  /tmp/docker-squash627981871/49b5a7a88d5353fe77204ad5591a3ef100fc2807a9d6dce979fd1b17a73a68d6/layer.tar
  -  /tmp/docker-squash627981871/589338fba5eb5cc32a25a036975a5e0938f12eff0dc70b661363c13ef1a192a5/layer.tar
  -  /tmp/docker-squash627981871/651626d6e364ccc22ac990ba95cd0aab9256c56055087cc9a5a1790cea5250b9/layer.tar
  -  /tmp/docker-squash627981871/e4eea4411c0065f8b0c7cf6be31dd58daa5ac04d8c64d54537cbfce2eb8e3413/layer.tar
  -  /tmp/docker-squash627981871/fc294d2b22cb53cb2440ff6fece18813ee7363f5198f5e20346abfcf7cce54fe/layer.tar
  -  /tmp/docker-squash627981871/511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158/layer.tar
Inserted new layer 6996f41c1688 after 511136ea3c5a
  -  511136ea3c5a
  -> 6996f41c1688 /bin/sh -c #(squash) from 511136ea3c5a
  -  1c9383292a8f /bin/sh -c #(nop) ADD file:c1472c26527df28498744f9e9e8a8304c
  -  9942dd43ff21 /bin/sh -c echo '#!/bin/sh' > /usr/sbin/policy-rc.d  && echo
  -  d92c3c92fa73 /bin/sh -c rm -rf /var/lib/apt/lists/*
  -  0ea0d582fd90 /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/\1/g' /etc/apt/
  -  cc58e55aa5a5 /bin/sh -c apt-get update && apt-get dist-upgrade -y && rm -
  -  c4ff7513909d /bin/sh -c #(nop) CMD [/bin/bash]
  -  fc294d2b22cb /bin/sh -c apt-get update && apt-get install -y golang-go
  -  8dfc0bb00563 /bin/sh -c #(nop) ADD dir:78239d85b32dd28e4cb1d81ace7ffd32b8
  -  651626d6e364 /bin/sh -c #(nop) WORKDIR /app
  -  589338fba5eb /bin/sh -c go build -o http
  -  c50f2b65cab3 /bin/sh -c #(nop) ENV PORT=8000
  -  e4eea4411c00 /bin/sh -c #(nop) EXPOSE map[8000/tcp:{}]
  -  63e174c2ca3d /bin/sh -c #(nop) CMD [/app/http]
  -  49b5a7a88d53 /bin/bash
Squashing from 6996f41c1688 into 6996f41c1688
  -  Deleting whiteouts
  -  Rewriting child history
  -  Removing 1c9383292a8f. Squashed. (/bin/sh -c #(nop) ADD file:c1472c26527df2849874...)
  -  Removing 9942dd43ff21. Squashed. (/bin/sh -c echo '#!/bin/sh' > /usr/sbin/policy-...)
  -  Removing d92c3c92fa73. Squashed. (/bin/sh -c rm -rf /var/lib/apt/lists/*)
  -  Removing 0ea0d582fd90. Squashed. (/bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/\1...)
  -  Removing cc58e55aa5a5. Squashed. (/bin/sh -c apt-get update && apt-get dist-upgra...)
  -  Replacing c4ff7513909d w/ new layer 09a62007c3f3 (/bin/sh -c #(nop) CMD [/bin/bash])
  -  Removing fc294d2b22cb. Squashed. (/bin/sh -c apt-get update && apt-get install -y...)
  -  Removing 8dfc0bb00563. Squashed. (/bin/sh -c #(nop) ADD dir:78239d85b32dd28e4cb1d...)
  -  Replacing 651626d6e364 w/ new layer b4f0dec85412 (/bin/sh -c #(nop) WORKDIR /app)
  -  Removing 589338fba5eb. Squashed. (/bin/sh -c go build -o http)
  -  Replacing c50f2b65cab3 w/ new layer cd499c2d09ef (/bin/sh -c #(nop) ENV PORT=8000)
  -  Replacing e4eea4411c00 w/ new layer 653dfab45562 (/bin/sh -c #(nop) EXPOSE map[8000/tcp:{}])
  -  Replacing 63e174c2ca3d w/ new layer f7f7eb6aae54 (/bin/sh -c #(nop) CMD [/app/http])
  -  Removing 49b5a7a88d53. Squashed. (/bin/bash)
Tarring up squashed layer 6996f41c1688
Removing extracted layers
Tagging f7f7eb6aae54 as jwilder/whoami:squash
Tarring new image to STDOUT
Done. New image created.
  -  f7f7eb6aae54 Less than a second /bin/sh -c #(nop) CMD [/app/http] 3.072 kB
  -  653dfab45562 Less than a second /bin/sh -c #(nop) EXPOSE map[8000/tcp:{}] 3.072 kB
  -  cd499c2d09ef Less than a second /bin/sh -c #(nop) ENV PORT=8000 3.072 kB
  -  b4f0dec85412 Less than a second /bin/sh -c #(nop) WORKDIR /app 3.072 kB
  -  09a62007c3f3 Less than a second /bin/sh -c #(nop) CMD [/bin/bash] 3.072 kB
  -  6996f41c1688 2 seconds /bin/sh -c #(squash) from 511136ea3c5a 111.9 MB
  -  511136ea3c5a 14 months  1.536 kB
Removing tempdir /tmp/docker-squash627981871
That gets my full build down to a single layer of 106.2MB:
REPOSITORY          TAG                 IMAGE ID            CREATED              VIRTUAL SIZE
jwilder/whoami      squash              f7f7eb6aae54        About a minute ago   106.2 MB
jwilder/whoami      latest              63e174c2ca3d        29 minutes ago       423.7 MB
Since I typically have base images already loaded onto my docker hosts, I would continue to use the default squash settings and retain my parent base image so that I’m only tranferring the changes for each image.

Conclusion

Squashing images with docker-squash can reduce image sizes significantly. Since it only needs to be run before publishing to a registry, the regular docker build caching is not changed and you don’t lose any of the benefits of using Docker. Similarly, it does not require complex Dockerfile setups to get good results so you can start using it on existing projects with little effort.
If you want to try it out or learn more about it works, you can get it from github.

from http://jasonwilder.com/blog/2014/08/19/squashing-docker-images/
https://github.com/jwilder/docker-squash
 




No comments:

Post a Comment