The way we build our WebSphere traditional Docker images is as a two-step process. First we install the products using Installation Manager and generate a tar file containing the installed product. Then we suck that tar file in to a clean image so that the resulting image does not contain all the cruft left lying around from the install process. (Not including Installation Manager in the final image also helps to reinforce that these images are intended to be immutable.)
The ADD
Dockerfile command is very convenient for copying in a tar file from the context and unpacking it, all in one atomic operation. Unfortunately the ADD command ignores the current user and always unpacks as root. (Aside: Docker recently re-opened the proposal created by IBMer Megan Kostick to address this problem.) You could run a chown
following the ADD
but this results in all the files being copied in to a new layer (not cool when the contents of your tar file weighs in at 1.5GB!). Our initial starting point was to make sure that all the files already had the right ownership when they are added to the tar file. This involved creating the same user/group in the initial image and relying on getting the same uid/guid in the eventual image, something I wasn’t entirely happy with.
A related problem that we had run in to elsewhere was that the copy and unpack magic of ADD
doesn’t extend to zip files, a format in which many of our install binaries are found. Where those binaries are already hosted somewhere, it’s simple enough to use wget
or curl
to pull the files, unpack, and perform any necessary cleanup as part of a RUN
command. The obvious solution to my local tar or zip file was to host the file somehow. I decided to spin up a python container to serve up the files as follows:
1 2 3 4 5 6 |
docker run -d --name server -v $(pwd):/host -w /host \ python:2-slim python -m SimpleHTTPServer ip=$(docker inspect \ --format '{{ .NetworkSettings.IPAddress }}' \ server) url="http://${ip}:8000/" |
That URL can then be consumed in a subsequent build. For example, if I had example.tar.gz
in the directory on the host, I could unpack as the user/group foo:bar
in my image with the following Dockerfile:
1 2 3 4 5 6 7 |
FROM ubuntu:16.04 RUN apt-get update && apt-get install -y wget \ && rm -rf /var/lib/apt/lists/* \ && groupadd bar && useradd foo -g bar -m ARG URL USER foo RUN wget -q -O - $URL/example.tar.gz | tar xz |
To build the image, we then just need to pass in the URL as a build argument and, when we’re done, we can clean up the python container:
1 2 |
docker build --build-arg URL=$url . docker rm -f server |
The result of all of this is that we then get the default non-root behavior of tar
which is to unpack as the current user.