Tuesday, July 14, 2015

A Look at Docker and Portability

Often enough, Docker is mentioned in one breath with portability. However, there are two dimensions of portability: first, running a container on any system of the same platform. Here, Docker really simplifies deploying applications on any system (of the same instruction set architecture). From a Linux on z Systems perspective, the second aspect of cross platform portability is more interesting: portability across platforms. Often enough, getting a container to run on z is not a big deal, but sometimes it is. Let's decompose this:

Start with the Docker interface: whether that refers to the CLI or REST API, it is identical on z. Same syntax, same semantics, no differences.

Docker images, as self-contained set of binaries, are specific to a CPU and ABI by nature. Mostly, Docker solutions are microservice architectures, consisting of many but per-se simple components. This facilitates scaling out, as well as simplifies getting the individual components ported.

An image is typically based on a distribution base image. This is not absolutely necessary, you can take a binary and all dependent shared libraries into a tarball and import that as a very slim container image; however typically a Dockerfile is used to build the image in an automatic and controlled fashion. The first line ("FROM") specifies the base image to be used, then often additional distribution packages are installed. If the same distribution is available on s390, e.g. a Fedora image, porting is typically simple -- yum is yum, and the package names are identical. A lot of images are based on Ubuntu on x86, however. We will have Ubuntu on s390x very soon. Until then, the closest thing on s390 is Debian, at least providing the same package tool chain ("apt-get") and mostly the same package names. This will make it much easier to get through the package installation steps. Sometimes, the base image includes a runtime, such as golang. In general, these images can be re-built 1:1 for s390, or they exist already (e.g. as described in this post for getting the recently published golang environment for z). Only if the base image is something non-existent on s390, the fun starts. Then, the art is to come up with an environment which is compatible with any succeeding steps. Yet in most cases, the base image does exist (or can be substituted) for s390.

Within Dockerfiles, additional components are often installed natively: source code archives are downloaded, extracted and built. This is usually platform independent, so should not add any impediment to building the container on z. There are a few exceptions: platform-specific behavior (e.g. if the application checks for CPU information in /proc), or non-portable code (endianness issues in the source code or written in assembler) will require additional care -- but for most packages that will not be necessary.

The last area of consideration is the main application itself. Should that be a binary blob from a third party, it will need to be substituted by an s390 build of the application. Otherwise, the same thoughts on code portability as just mentioned apply; this is also not specific to the use via Docker.

Eventually, work can be avoided in the future, if any necessary changes can be submitted to the originator (in an acceptable way for other platforms). When such changes get integrated "upstream", it will work out of the box next time.

Update 7/27: the next couple of posts will show how to overcome some of the specifics above.
Update 2/12: Ubuntu is very close. Golang is there. It continues to gets easier...
Update 3/29: the upcoming multi-arch support allows sticking binaries of several architectures into a single Docker image identifier on a registry (or Docker Hub). This can eliminate the need to adapt the FROM statement, once all the base images are "fat images" out there.

No comments:

Post a Comment