Flight Deck on ARM
ARM is not a new processor architecture. Virtually every smartphone today has one inside and has since the earliest days of iOS and Android. In fact, ARM goes all the way back to 1983, when transgender woman Sophie Wilson began designing the instruction set for the Acorn RISC Machine. Despite its long history, however, it’s never been considered a serious contender for workstations or desktop machines where x86 reigns supreme. Even in the data center, ARM is a comparative newcomer, with few cloud providers supporting it.
The Raspberry Pi did a lot to popularize the notion of ARM as a desktop replacement. For years, the Pi and other Single Board Computers have been slowly normalizing the ARM architecture on Linux. Now, it’s common for many popular distributions to offer both x86 and ARM versions. A key advantage of ARM is its low power consumption compared to the performance it provides. While Intel has made great strides there in the last decade, ARM still easily beats them in MHz per Watt.
That advantage was what led Microsoft (you thought I’d say Apple, didn’t you?) to release one of the first well-advertised “desktop” systems running ARM, the SurfaceRT, in 2012. Unfortunately, the launch was compromised by slow performance, lack of compatible applications and the entire Windows 8 mess. It was simply too early. It wouldn’t be until 2016, when the Pi 3 was released, that ARM on Desktop was reconsidered.
And Then the M1 Was Announced
After years of speculation and multiple iterations of their own custom ARM processor, Apple confirmed that the next MacBook would run ARM. MacOS developers and open source maintainers have been working to port their software ever since. A brief scandal erupted when it was discovered the dev kit lacked any support for hardware virtualization, meaning Docker, VMWare, Virtualbox, Parallels, and any hardware-accelerated virtualization system was non-functional. This was a potential disaster, as many developers rely on VMs or containers to run their software locally while retaining the user environment of MacOS. To Apple’s credit, they worked closely with developers and rectified the situation.
It was around this point that developers at TEN7 started asking me, “If I got an M1, would all our stuff work?” I had to break some hearts.
Not only did I live through the ugly PowerPC to Intel transition for OS X, I also lived through the nearly forgotten 68k to PowerPC transition.
“Likely not for two years,” was my reply, “and besides, none of our containers work on ARM.” Our developers rely on Flight Deck, a series of Linux containers we use both for development, and in our open source production hosting running on Kubernetes.
“So how hard would it be to get Flight Deck running on ARM?” they asked. I flatly didn’t know. I knew that Alpine Linux -- on which Flight Deck is based -- supports multiple architectures including ARM. In theory, we’d only need an ARM system on which to compile the images and push them up to Docker Hub. There was no way we’d be able to get an M1 or Apple’s Dev Kit just to compile Flight Deck.
Fortunately, Apple isn’t the only option here.
Getting Docker Installed
The most powerful ARM based system I have capable of running Docker is a Raspberry Pi 4 4GB. Presently, it’s been shoehorned into the modified case of an eMate 300, a laptop-shaped Newton intended for use in the education market. My “piMate 300” also features a mechanical keyboard and a 7” color touchscreen. A bit of a step up from the eMate.
Installing Docker was a little more complicated on Raspbian than most Linux distributions. Instead of simply
apt-get install docker-io, you need to add a special repository to the Raspbian package manager and then install Docker. Fortunately, Docker made this simple by providing a script which performs most of the necessary setup.
First, run updates on your system to ensure you have the newest packages installed:
sudo apt-get update
sudo apt-get upgrade
Then download and run the script:
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
When that completes, you’ll have Docker installed, but there’s a bit more set up yet to do. Docker runs as the root user. To have access to Docker commands while running as non-root, you need to add your user to the
Use the following command to get your username
Then, add yourself
sudo usermod -aG docker yourUserName
I also decided to configure Docker to start when the system starts up:
sudo systemctl enable docker
And then manually started Docker. You can choose to simply reboot the Pi at this point if you prefer:
sudo systemctl start docker
Finally, we can validate everything is working with:
Compiling Flight Deck
With Docker installed and running, the next step is to try to compile Flight Deck. Fortunately, all of Flight Deck’s code is free and open source on Github. You can choose to either use git to clone the repositories, or simply download a zip of the latest release of the source. Either works.
After getting the code, building Flight Deck is straightforward. There are no additional tools, scripts, or build systems necessary other than the
Change to the directory containing the Dockerfile. In my case, I created a
flight-deck directory in my home directory, then downloaded and extracted the 7.3.x zip of
Then, build the container:
To my astonishment, it compiled successfully the first time with no modifications. In retrospect, this made perfect sense. The base Docker image we’re using is in fact a “multi-arch” container. That is, it supports multiple processor architectures using the same name. The Docker engine is aware which CPU I’m using, so it downloaded and built the container for ARM without further prompting. Alpine Linux itself has been supporting ARM for years at this point, and Flight Deck is largely built on packages provided by Alpine. The minimalist approach in Flight Deck also helps us here.
The docker build command returns a hexadecimal image ID. We can run that using the
docker run command:
docker run -it 1234567890abcdef /bin/bash
And after a short start up script, we’re greeted by “Muffy”:
With that working, we could use Composer to download Drupal core:
composer create-project drupal/recommended-project path/to/target/dir
That too, worked perfectly, validating that PHP was alive and functioning on ARM.
One Down, Several to Go
The flight-deck-web container is only one of several containers necessary to run a Drupal site. We also need flight-deck-db to provide a database. For a production environment, we also need flight-deck-varnish, the official memcache image, and, optionally, flight-deck-solr. I downloaded all of these, and each one compiled and ran as expected on ARM with one exception.
Our Solr 6 image worked perfectly well, but Solr 8 failed to compile on ARM. When I dug into the build logs, I found that the problem was a missing dependency. Our Solr 6 image relies on OpenJDK 8, as per Solr’s own recommended system requirements. Solr 8, however, relies on the newer OpenJDK 11, which is not available on Alpine ARM at this time.
Getting a Site Running
With all the critical containers working, the next task was to stand up a site. Flight Deck relies on Docker Compose -- not to be confused with Composer -- which is a separate project from Docker itself. Compose relies on Python, so we can install it using the Python package manager, Pip:
sudo apt-get install libffi-dev libssl-dev
sudo apt install python3-dev
sudo apt-get install -y python3 python3-pip
sudo pip3 install docker-compose
Future versions of Flight Deck may supply a docker stack file instead of a Compose file. The format and features are similar, and it would remove the need to install Docker Compose at all.
Next, I can clone the ten7.com git repository from our internal Gitlab instance. I also needed a database dump. This last part was a bit hilarious. To get one, I needed to log in to various internal systems. To do that, I needed to log in to my password manager. To do that, I needed to use my hardware security key, which required half-tearing apart the piMate to awkwardly insert it into a free USB port. I’m sure the experience would be markedly more mundane on Apple’s consumer hardware.
Before starting up the containers, I needed to modify the docker-compose.yml to point to my local Flight Deck build files, rather than those on Docker Hub. This involved changing the
image directives to
build directives and supplying a local file path.
After that, two commands was all that was necessary:
docker-compose up -d
That’s when the problems started
The first sign of trouble was that all of the containers downloaded, but some mysteriously failed to start. A quick check with
docker-compose logs showed why:
The “exec format error” message was Linux’s way of telling me that those containers were not multi-arch, and thus couldn’t run on ARM. The loss of the official phpMyAdmin and Mailhog images was unfortunate for local development, but not a show-stopper.
Loading the database went perfectly well. After running
composer install and
drush cr, the site was up!
Kinda! Like many sites, ten7.com relies on SASS to preprocess CSS. I had failed to do that step. Fortunately, npm and node-sass (should) be installed inside of flight-deck-web, so it should only be a matter of running:
npm run build
And there’s where things really went off the rails.
It’s not all bad, however. There is a general tracking issue to finally, officially support ARM, due to Apple announcing the M1. Supporting only Apple’s version of ARM, unfortunately, would leave containerized development tools lacking, as the vast majority continue to run Linux. MacOS is little used for web development automated build systems or production web servers, where Linux is nearly universal. We could go back to the bad old days of committing compiled CSS code to git repositories, and bring back all the git conflicts that brings with it. I can only hope that the Node Sass team will broadly support ARM and not just Apple’s interpretation of it.
Where to Go From Here
While Flight Deck largely runs on ARM, it’s not quite ready yet for regular development. The lack of Node Sass is a major sticking point, and it would require some effort to compile all the needed utilities locally and apply whatever patches are necessary in order to support the architecture.
Furthermore, it would be best for Flight Deck to support multi-arch images itself. This can be done on an x86 based system through the use of QEMU and the
docker buildx command. This would allow Flight Deck to support different architectures transparently, as does the Alpine base image and the official Memcache image.
ARM on desktop is, in many ways, already here. It simply wasn’t taken seriously until Cupertino gave its blessing. Fortunately, the open source community has long since been here, working to keep our tools running as technology changes. We at TEN7 hope Flight Deck will be a part of that.