Skip to content

Commit

Permalink
Merge pull request #50: Support building multi-platform images and ad…
Browse files Browse the repository at this point in the history
…d linux/arm64
  • Loading branch information
victorlin authored Dec 16, 2022
2 parents 2de479f + 3b53f7a commit 960fb5b
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 20 deletions.
17 changes: 16 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ jobs:
# and hyphens.
run: echo "TAG=branch-${GITHUB_REF_NAME//[^A-Za-z0-9._-]/-}" | tee -a $GITHUB_ENV

- uses: docker/setup-qemu-action@v2

# GITHUB_TOKEN is unreliable¹ so use a token from nextstrain-bot.
# ¹ https://github.com/docker/build-push-action/issues/463#issuecomment-939394233
- uses: docker/login-action@v1
Expand All @@ -38,14 +40,20 @@ jobs:
username: nextstrain-bot
password: ${{ secrets.GH_TOKEN_NEXTSTRAIN_BOT_MANAGE_PACKAGES }}

- run: ./devel/build -r ghcr.io -t $TAG
- run: ./devel/build -p linux/amd64,linux/arm64 -r ghcr.io -t $TAG

outputs:
tag: ${{ env.TAG }}

test:
name: test (${{ matrix.platform }})
needs: build
runs-on: ubuntu-latest
strategy:
matrix:
platform:
- linux/amd64
- linux/arm64
steps:

- uses: docker/login-action@v1
Expand All @@ -58,11 +66,18 @@ jobs:
with:
python-version: ~3

# The ubuntu-latest runner is linux/amd64 so anything else will
# run with emulation, which is still better than nothing.
- if: matrix.platform != 'linux/amd64'
uses: docker/setup-qemu-action@v2

- name: Run zika-tutorial
run: |
git clone https://github.com/nextstrain/zika-tutorial
pip install nextstrain-cli
nextstrain build --image ghcr.io/nextstrain/base:${{ needs.build.outputs.tag }} zika-tutorial -F
env:
DOCKER_DEFAULT_PLATFORM: ${{ matrix.platform }}

push-branch:
if: startsWith(needs.build.outputs.tag, 'branch-') && github.event_name != 'pull_request'
Expand Down
82 changes: 70 additions & 12 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \

# Install a specific Node.js version
# https://github.com/nodesource/distributions/blob/0d81da75/README.md#installation-instructions
RUN curl -fsSL https://deb.nodesource.com/setup_16.x | bash - \
RUN curl -fsSL https://deb.nodesource.com/setup_14.x | bash - \
&& apt-get update && apt-get install -y nodejs

# Used for platform-specific instructions
ARG TARGETPLATFORM
ARG TARGETOS
ARG TARGETARCH

# Add dependencies. All should be pinned to specific versions, except
# Nextstrain-maintained software.
# This includes pathogen-specific workflow dependencies. Since we only maintain a
Expand All @@ -53,12 +58,14 @@ RUN mkdir -p /final/bin /final/share /final/libexec
# 1. Build programs from source

# Build RAxML
# AVX should be widely-supported enough
# linux/arm64 does not support -mavx and -msse3 compilation flags which are used in the official repository.
# Make these changes in a fork for now: https://github.com/nextstrain/standard-RAxML/tree/simde
# TODO: Use the official repository if this PR is ever merged: https://github.com/stamatak/standard-RAxML/pull/50
WORKDIR /build/RAxML
RUN curl -fsSL https://api.github.com/repos/stamatak/standard-RAxML/tarball/v8.2.12 \
RUN curl -fsSL https://api.github.com/repos/nextstrain/standard-RAxML/tarball/4621552064304a219ff03810f5f0d91e1063b68f \
| tar xzvpf - --no-same-owner --strip-components=1 \
&& make -f Makefile.AVX.PTHREADS.gcc \
&& cp -p raxmlHPC-PTHREADS-AVX /final/bin
&& make -f Makefile.AVX.PTHREADS.gcc \
&& cp -p raxmlHPC-PTHREADS-AVX /final/bin

# Build FastTree
WORKDIR /build/FastTree
Expand All @@ -80,46 +87,97 @@ RUN curl -fsSL https://github.com/vcftools/vcftools/releases/download/v0.1.16/vc
# 2. Download pre-built programs

# Download MAFFT
# NOTE: Running this program requires support for emulation on the Docker host
# if the processor architecture is not amd64.
# TODO: Build from source to avoid emulation. Instructions: https://mafft.cbrc.jp/alignment/software/installation_without_root.html
WORKDIR /download/mafft
RUN curl -fsSL https://mafft.cbrc.jp/alignment/software/mafft-7.475-linux.tgz \
| tar xzvpf - --no-same-owner --strip-components=2 mafft-linux64/mafftdir/ \
&& cp -p bin/* /final/bin \
&& cp -p libexec/* /final/libexec

# Download IQ-TREE
# NOTE: Running this program requires support for emulation on the Docker host
# if the processor architecture is not amd64.
# TODO: Build from source to avoid emulation. Instructions: http://www.iqtree.org/doc/Compilation-Guide
WORKDIR /download/IQ-TREE
RUN curl -fsSL https://github.com/iqtree/iqtree2/releases/download/v2.1.2/iqtree-2.1.2-Linux.tar.gz \
| tar xzvpf - --no-same-owner --strip-components=1 \
&& mv bin/iqtree2 /final/bin/iqtree

# Download Nextalign v1
# NOTE: Running this program requires support for emulation on the Docker host
# if the processor architecture is not amd64.
# TODO: Build from source to avoid emulation. Example: https://github.com/nextstrain/nextclade/blob/1.11.0/.circleci/config.yml#L183-L223
RUN curl -fsSL -o /final/bin/nextalign1 https://github.com/nextstrain/nextclade/releases/download/1.11.0/nextalign-Linux-x86_64

# Download Nextclade v1
# NOTE: Running this program requires support for emulation on the Docker host
# if the processor architecture is not amd64.
# TODO: Build from source to avoid emulation. Example: https://github.com/nextstrain/nextclade/blob/1.11.0/.circleci/config.yml#L183-L223
RUN curl -fsSL -o /final/bin/nextclade1 https://github.com/nextstrain/nextclade/releases/download/1.11.0/nextclade-Linux-x86_64

# Download tsv-utils
# NOTE: Running this program requires support for emulation on the Docker host
# if the processor architecture is not amd64.
# TODO: Build from source to avoid emulation. Instructions: https://github.com/eBay/tsv-utils/tree/v2.2.0#build-from-source-files
RUN curl -L -o tsv-utils.tar.gz https://github.com/eBay/tsv-utils/releases/download/v2.2.0/tsv-utils-v2.2.0_linux-x86_64_ldc2.tar.gz \
&& tar -x --no-same-owner -v -C /final/bin -z --strip-components 2 --wildcards -f tsv-utils.tar.gz "*/bin/*" \
&& rm -f tsv-utils.tar.gz

# Download csvtk
RUN curl -L https://github.com/shenwei356/csvtk/releases/download/v0.24.0/csvtk_linux_amd64.tar.gz | tar xz --no-same-owner -C /final/bin
RUN curl -L https://github.com/shenwei356/csvtk/releases/download/v0.24.0/csvtk_${TARGETOS}_${TARGETARCH}.tar.gz | tar xz --no-same-owner -C /final/bin

# Download seqkit
RUN curl -L https://github.com/shenwei356/seqkit/releases/download/v2.2.0/seqkit_linux_amd64.tar.gz | tar xz --no-same-owner -C /final/bin
RUN curl -L https://github.com/shenwei356/seqkit/releases/download/v2.2.0/seqkit_${TARGETOS}_${TARGETARCH}.tar.gz | tar xz --no-same-owner -C /final/bin

# Download gofasta (for ncov/Pangolin)
# NOTE: Running this program requires support for emulation on the Docker host
# if the processor architecture is not amd64.
# TODO: Build from source to avoid emulation. Instructions: https://github.com/virus-evolution/gofasta/tree/v0.0.6#installation
RUN curl -fsSL https://github.com/virus-evolution/gofasta/releases/download/v0.0.6/gofasta-linux-amd64 \
-o /final/bin/gofasta

# Download minimap2 (for ncov/Pangolin)
# NOTE: Running this program requires support for emulation on the Docker host
# if the processor architecture is not amd64.
# TODO: Build from source to avoid emulation. Instructions: https://github.com/lh3/minimap2/tree/v2.24#install
RUN curl -fsSL https://github.com/lh3/minimap2/releases/download/v2.24/minimap2-2.24_x64-linux.tar.bz2 \
| tar xjvpf - --no-same-owner --strip-components=1 -C /final/bin minimap2-2.24_x64-linux/minimap2


# 3. Install programs via pip

# Build cvxopt on linux/arm64
# cvxopt, an Augur dependency, does not have pre-built binaries for linux/arm64.
#
# First, add system deps for building¹:
# - libopenblas-dev: Contains optimized versions of BLAS and LAPACK.
# - libsuitesparse-dev: Contains SuiteSparse.
#
# Then, "install" (build) separately since the process requires a special
# environment variable².
#
# ¹ https://cvxopt.org/install/#building-and-installing-from-source
# ² https://github.com/cvxopt/cvxopt/issues/125#issuecomment-407396491
RUN if [[ "$TARGETPLATFORM" == linux/arm64 ]]; then \
apt-get update && apt-get install -y --no-install-recommends \
libopenblas-dev \
libsuitesparse-dev \
&& CVXOPT_SUITESPARSE_INC_DIR=/usr/include/suitesparse \
pip3 install cvxopt \
; \
fi

# Install jaxlib on linux/arm64
# jaxlib, an evofr dependency, does not have official pre-built binaries for
# linux/arm64. A GitHub user has provided them in a fork repo.
# https://github.com/google/jax/issues/7097#issuecomment-1110730040
RUN if [[ "$TARGETPLATFORM" == linux/arm64 ]]; then \
pip3 install https://github.com/yoziru/jax/releases/download/jaxlib-v0.3.25/jaxlib-0.3.25-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl \
; \
fi

# Install envdir, which is used by pathogen builds
RUN pip3 install envdir==1.0.1

Expand Down Expand Up @@ -162,12 +220,12 @@ COPY builder-scripts/ /builder-scripts/

# Download Nextalign v2
# Set default Nextalign version to 2
RUN curl -fsSL -o /final/bin/nextalign2 https://github.com/nextstrain/nextclade/releases/latest/download/nextalign-x86_64-unknown-linux-gnu \
RUN curl -fsSL -o /final/bin/nextalign2 https://github.com/nextstrain/nextclade/releases/latest/download/nextalign-$(/builder-scripts/target-triple) \
&& ln -sv nextalign2 /final/bin/nextalign

# Download Nextclade v2
# Set default Nextclade version to 2
RUN curl -fsSL -o /final/bin/nextclade2 https://github.com/nextstrain/nextclade/releases/latest/download/nextclade-x86_64-unknown-linux-gnu \
RUN curl -fsSL -o /final/bin/nextclade2 https://github.com/nextstrain/nextclade/releases/latest/download/nextclade-$(/builder-scripts/target-triple) \
&& ln -sv nextclade2 /final/bin/nextclade

# Fauna
Expand Down Expand Up @@ -198,8 +256,8 @@ RUN /builder-scripts/download-repo https://github.com/nextstrain/auspice release
RUN pip3 install evofr

# Add NCBI Datasets command line tools for access to NCBI Datsets Virus Data Packages
RUN curl -fsSL -o /final/bin/datasets https://ftp.ncbi.nlm.nih.gov/pub/datasets/command-line/v2/linux-amd64/datasets
RUN curl -fsSL -o /final/bin/dataformat https://ftp.ncbi.nlm.nih.gov/pub/datasets/command-line/v2/linux-amd64/dataformat
RUN curl -fsSL -o /final/bin/datasets https://ftp.ncbi.nlm.nih.gov/pub/datasets/command-line/v2/linux-${TARGETARCH}/datasets
RUN curl -fsSL -o /final/bin/dataformat https://ftp.ncbi.nlm.nih.gov/pub/datasets/command-line/v2/linux-${TARGETARCH}/dataformat

# ———————————————————————————————————————————————————————————————————— #

Expand Down Expand Up @@ -239,7 +297,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \

# Install a specific Node.js version
# https://github.com/nodesource/distributions/blob/0d81da75/README.md#installation-instructions
RUN curl -fsSL https://deb.nodesource.com/setup_16.x | bash - \
RUN curl -fsSL https://deb.nodesource.com/setup_14.x | bash - \
&& apt-get update && apt-get install -y nodejs

# Configure bash for interactive usage
Expand Down
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,16 @@ To build this image locally,
./devel/build
```
By default, this tags the image with `latest` and pushes to
By default, this builds for a single platform `linux/amd64`, tags the image with `latest`, and pushes to
`localhost:5000`. See instructions at the top of the script for additional
options.
If the target platform is different from the build platform, set up emulation before running `./devel/build`. This can be achieved using [`tonistiigi/binfmt`](https://github.com/tonistiigi/binfmt). For example, to set up emulation for `linux/arm64`, run:
```
docker run --privileged --rm tonistiigi/binfmt --install arm64
```
On each subsequent change during your development iterations, you can run just
the `./devel/build` command again.
Expand Down Expand Up @@ -93,12 +99,18 @@ To add a software program to `nextstrain/base`, follow steps in this order:
2. Check if it is available via PyPI. You can search on [PyPI's
website](https://pypi.org/search/). If available, add an install command to
the section labeled with `Install programs via pip`.
3. Check if a pre-built binary is available on the software's website (e.g.
3. Check if a pre-built binary for the `linux/amd64` platform (name contains
`linux` and `amd64`/`x86_64`) is available on the software's website (e.g.
GitHub release assets). If available, add a download command to the section
labeled with `Download pre-built programs`.
- If a pre-built binary supporting `linux/arm64` (name contains `linux` and
`arm64`/`aarch64`) is also available, that should be used conditionally on
`ARG`s `TARGETPLATFORM` or `TARGETOS`+`TARGETARCH` in the Dockerfile. See
existing usage of those arguments for examples.
4. The last resort is to build from source. Look for instructions on the
software's website. Add a build command to the section labeled with `Build
programs from source`.
programs from source`. Note that this can require platform-specific
instructions.
If possible, pin the software to a specific version. Otherwise, add the
download/install/build command to the section labeled with `Add unpinned
Expand Down
25 changes: 25 additions & 0 deletions builder-scripts/target-triple
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/bin/bash
#
# Get the target triple from a Docker target platform.
#
# The Docker target platform is provided by the TARGETPLATFORM variable¹.
# ¹ https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope
#
set -euo pipefail

if [[ $# -gt 0 ]]; then
TARGETPLATFORM="$1"
fi

case $TARGETPLATFORM in
"linux/amd64")
echo "x86_64-unknown-linux-gnu"
;;
"linux/arm64")
echo "aarch64-unknown-linux-gnu"
;;
*)
echo "No target triple mapping for $TARGETPLATFORM." 1>&2
exit 1
;;
esac
8 changes: 4 additions & 4 deletions devel/build
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,17 @@
set -euo pipefail

# Set default values.
platform=linux/amd64
registry=localhost:5000
tag=latest

# Read command-line arguments.
while getopts "r:t:" opt; do
while getopts "p:r:t:" opt; do
case "$opt" in
p) platform="$OPTARG";;
r) registry="$OPTARG";;
t) tag="$OPTARG";;
*) echo "Usage: $0 [-r <registry>] [-t <tag>]" 1>&2; exit 1;;
*) echo "Usage: $0 [-p <platform>] [-r <registry>] [-t <tag>]" 1>&2; exit 1;;
esac
done

Expand All @@ -36,8 +38,6 @@ export GIT_REVISION=$(git describe --tags --abbrev=40 --always --dirty || true)
# Calling `docker run nextstrain/base` will still only pull down the small base
# image rather than pulling down the larger nextstrain/base-builder image.

platform=linux/amd64

# `buildx create` is necessary to use a driver that supports multi-platform
# images.
builder=nextstrain-builder
Expand Down

0 comments on commit 960fb5b

Please sign in to comment.