On data-only containers in Docker…

Sometime you just need a place to dump things…


What’s the problem?

You might read that using scratch is a bad idea for the data-only container pattern and maybe it’s true. Maybe you should use another copy of your base image to host the data. But doesn’t that break the concept of a data-only container? As a security-minded individual this strikes me as somewhat unusual to store applications with data if the point is to segregate the two. So I set out to prove that using a secure data container pattern is possible — in as few commands as possible.

Big warning

This method is a little unusual as it requires an “initialization phase” for the data container. Although¬†understandable, it’s not perfect and may not scale well without further work.

How it’s done

Suppose you start with a Dockerfile like so…

FROM alpine
RUN adduser -D test && mkdir /foo && touch /foo/bar && chown -R test:test /foo
USER test
CMD ls -lh /foo

And you build it thusly:

docker build -t test -< Dockerfile

Let’s run this container without a data container:

docker run --rm test

Which delivers this fully expected news:

total 0
-rw-r--r--    1 test     test           0 Apr  1 12:23 bar

And you create a dummy data container from scratch:

docker create -v /foo --name test-data scratch foo

Obviously since there are no applications foo would never run, but since this is a data container that’s not a problem as we will never start it.

Now let’s run the image with our shiny new data container.

docker run --rm --volumes-from test-data test


total 0

Drat. Right, there’s nothing in that folder now because the data container is empty. Let’s put something there.

docker run --rm --volumes-from test-data test sh -c "touch /foo/bar"

Which understandably results in:

touch: /foo/bar: Permission denied

Because the data container has mounted /foo with the permissions root:root

So how do we handle this? With initialization! Remember uncle Ben, with great power comes something something… let’s do it.

docker run --rm --volumes-from test-data test sh -c "su -c 'chown -R test:test /foo' && touch /foo/bar"

Now let’s re-run our previous command:

docker run --rm --volumes-from test-data test

Correctly resulting in:

-rw-r--r--    1 test     test           0 Apr  1 13:05 bar

Security is intact! Let’s double-check that:

docker run --rm --volumes-from test-data test sh -c "touch /foo/baz && ls -lh /foo"

And now we get no errors! Also this:

total 0
-rw-r--r--    1 test     test           0 Apr  1 13:05 bar
-rw-r--r--    1 test     test           0 Apr  1 13:08 baz

Today I learned…

  • Security can be properly handled using a from scratch data container.
  • Backups of a data container can be made easily via docker commands without all the extra distro cruft.
  • If someone does manage to get into your data container there are no commands available and it really can’t be started at all.
  • It can be done!

TIL – Dockerfiles are really sensitive to OOO

The Land of Ooo

TIL РOrder of operations are important!

Today I learned that order can have a profound effect on the size of the resulting images. For example my first Dockerfile contained a section something like this:

RUN curl http://www.bigfiles.com/bigfile.tgz > /opt/bigfile.tgz && \
    tar -C /opt -xzf /opt/bigfile.tgz

Which produced a ~300 MiB image.
But wait… the permissions are wrong! Let’s fix that:

RUN curl http://www.bigfiles.com/bigfile.tgz > /opt/bigfile.tgz && \
    tar -C /opt -xzf /opt/bigfile.tgz
RUN chown -R user:user /opt/bigfiledir

Wow! Suddenly we are over 500MiB! Why?

AuFS is actually storing the files twice. Resulting in an extra 200MiB just to store permissions. Yikes!

So what’s the solution?

RUN curl http://www.bigfiles.com/bigfile.tgz > /opt/bigfile.tgz && \
    tar -C /opt -xzf /opt/bigfile.tgz && \
    chown -R user:user /opt/bigfiledir

Since this all happens in one command the changes don’t get saved in an overlay layer.

My actual work was much more complicated so it took awhile to spot this, but it’s an important lesson nonetheless.

Keep your images small folks!