{"id":223,"date":"2018-10-16T03:58:55","date_gmt":"2018-10-16T03:58:55","guid":{"rendered":"https:\/\/www.appservgrid.com\/paw93\/?p=223"},"modified":"2018-10-16T04:20:03","modified_gmt":"2018-10-16T04:20:03","slug":"running-and-building-arm-docker-containers-in-x86-own-your-bits","status":"publish","type":"post","link":"https:\/\/www.appservgrid.com\/paw93\/index.php\/2018\/10\/16\/running-and-building-arm-docker-containers-in-x86-own-your-bits\/","title":{"rendered":"Running and building ARM Docker containers in x86 \u2013 Own your bits"},"content":{"rendered":"<p>We already covered <a href=\"https:\/\/ownyourbits.com\/2018\/05\/23\/the-real-power-of-linux-executables\/\">how Linux executes files<\/a> and <a href=\"https:\/\/ownyourbits.com\/2018\/06\/13\/transparently-running-binaries-from-any-architecture-in-linux-with-qemu-and-binfmt_misc\/\">how to run ARM binaries \u201cnatively\u201d<\/a> in Linux in the last two posts. We ended up running a whole ARM root filesystem transparently in a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Chroot\"><em>chroot jail<\/em><\/a> using QEMU user mode and <em>binfmt_misc<\/em> support.<br \/>\nNow that we have that covered, nothing prevents us from applying that to Docker containers. At the end of the day, containers are chroots in steroids, and they also share kernel with the host so all the basic mechanics remain the same.<br \/>\n<strong>Running ARM containers<\/strong><br \/>\nIf you haven\u2019t yet, install QEMU user mode, by default it will install also <em>binfmt_misc<\/em> support.<\/p>\n<table>\n<tbody>\n<tr>\n<td><\/td>\n<td># apt-get install qemu-user<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Now, we only need to place the <em>qemu-arm-static<\/em> interpreter inside the container. This is as easy as mount-binding it in the container invocation and voila! We are running an armhf container in our x86 machine.<\/p>\n<table>\n<tbody>\n<tr>\n<td><\/td>\n<td>$ docker run -v \/usr\/bin\/qemu-arm-static:\/usr\/bin\/qemu-arm-static &#8211;rm -ti arm32v7\/debian:stretch-slim<br \/>\nroot@49176286e89e:\/#<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h4>Building ARM containers<\/h4>\n<p>This is a bit of an uglier trick, because we need to copy the QEMU interpreter to the container. The problem is that it adds ~5MiB to the container, but the benefit of being able to build foreign containers natively is immense!<\/p>\n<p>Consider the following simplified Dockerfile to create an armhf nginx container<\/p>\n<table style=\"font-size: 1rem;\">\n<tbody>\n<tr>\n<td><\/td>\n<td>FROM arm32v7\/debian:stretch-slim<\/p>\n<p>COPY qemu-arm-static \/usr\/bin<\/p>\n<p>RUN apt-get update;<\/p>\n<p>apt-get install -y nginx;<\/p>\n<p>echo &#8220;ndaemon off;&#8221; &gt;&gt; \/etc\/nginx\/nginx.conf<\/p>\n<p>CMD [&#8220;nginx&#8221;]<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>We end up with a container that can be run both natively in an ARM device, and in an x86 system with a properly configured <em>binfmt_misc<\/em> support. Not bad!<\/p>\n<p>We can even test it locally<\/p>\n<table>\n<tbody>\n<tr>\n<td><\/td>\n<td>docker build . -t nginx-armhf:testing<\/p>\n<p>docker run &#8211;rm -ti -d -p 80:80 nginx-armhf:testing<\/p>\n<p>firefox localhost<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>We are now running the ARM nginx web server locally.<\/p>\n<p>This means that we can create a build pipeline with automated testing without requiring any ARM boards. After all automated tests are passing, we can create the production image.<\/p>\n<table>\n<tbody>\n<tr>\n<td><\/td>\n<td>FROM nginx-armhf:testing<\/p>\n<p>RUN rm \/usr\/bin\/qemu-arm-static<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<table>\n<tbody>\n<tr>\n<td><\/td>\n<td>docker build . -t nginx-armhf:production<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h6>Reclaiming the space in Docker API 1.25+<\/h6>\n<p>If we really want to reclaim those extra 5MiB from qemu-arm-static, we can use the new experimental<br \/>\n&#8211;squash flag.<\/p>\n<table>\n<tbody>\n<tr>\n<td><\/td>\n<td>docker build &#8211;squash . -t nginx-armhf:production<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Honestly, it was about time that they did something to help us keep the image size down. The piling up of layers and <a href=\"https:\/\/github.com\/moby\/moby\/issues\/6119\">their refusal<\/a> to add a simple<br \/>\n&#8211;chown argument to the COPY command made the creation of Dockerfiles a black art where you had to chain all the installation steps including the cleanup in a single RUN statement, therefore denying the benefits of caching for big blocks of code.<\/p>\n<p>Thankfully, they are beginning to react and we now have not only<br \/>\n&#8211;chown , but also the<br \/>\n&#8211;squash flag for the build command. In order to use it, we need to enable experimental features. Add the following to the <em>daemon.json<\/em> file, which might not exist<\/p>\n<p>Restart the Docker daemon, after this.<\/p>\n<h6>Reclaiming the space in Docker API &lt;1.25<\/h6>\n<p>We are left with the <a href=\"https:\/\/ownyourbits.com\/2017\/02\/19\/creating-a-minimal-debian-container-for-docker\/\">old hacky way<\/a> of flattening the images, by exporting the container<\/p>\n<table>\n<tbody>\n<tr>\n<td><\/td>\n<td>docker container create &#8211;name nginx-armhf-container nginx-armhf:production<\/p>\n<p>docker export nginx-armhf-container | docker import &#8211; nginx-armhf:raw<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>, and finally rebuild the metadata<\/p>\n<table>\n<tbody>\n<tr>\n<td><\/td>\n<td>FROM nginx-armhf:raw<\/p>\n<p>CMD [&#8220;nginx&#8221;]<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<table>\n<tbody>\n<tr>\n<td><\/td>\n<td>docker build . -t nginx-armhf:latest<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/ownyourbits.com\/2018\/06\/27\/running-and-building-arm-docker-containers-in-x86\/\" target=\"_blank\" rel=\"noopener\">Source<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>We already covered how Linux executes files and how to run ARM binaries \u201cnatively\u201d in Linux in the last two posts. We ended up running a whole ARM root filesystem transparently in a chroot jail using QEMU user mode and binfmt_misc support. Now that we have that covered, nothing prevents us from applying that to &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.appservgrid.com\/paw93\/index.php\/2018\/10\/16\/running-and-building-arm-docker-containers-in-x86-own-your-bits\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Running and building ARM Docker containers in x86 \u2013 Own your bits&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-223","post","type-post","status-publish","format-standard","hentry","category-docker"],"_links":{"self":[{"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts\/223","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/comments?post=223"}],"version-history":[{"count":2,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts\/223\/revisions"}],"predecessor-version":[{"id":232,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts\/223\/revisions\/232"}],"wp:attachment":[{"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/media?parent=223"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/categories?post=223"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/tags?post=223"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}