Skip to content

Commit

Permalink
Merge pull request #1399 from mathbunnyru/asalikhov/arm_builds
Browse files Browse the repository at this point in the history
Support arm builds
  • Loading branch information
consideRatio authored Jul 16, 2021
2 parents 493a9ba + efb980a commit 514883d
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 10 deletions.
17 changes: 15 additions & 2 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ jobs:
!contains(github.event.pull_request.title, 'ci skip')
steps:
# Setup docker to build for multiple platforms, see:
# https://github.com/docker/build-push-action/tree/master#usage
# https://github.com/docker/build-push-action/blob/master/docs/advanced/multi-platform.md
- name: Set up QEMU (for docker buildx)
uses: docker/setup-qemu-action@27d0a4f181a40b142cce983c5393082c365d1480 # dependabot updates to latest release

- name: Set up Docker Buildx (for multi-arch builds)
uses: docker/setup-buildx-action@0d135e0c2fc0dba0729c1a47ecfcf5a3c7f8579e # dependabot updates to latest release

- name: Clone Main Repo
uses: actions/checkout@v2
with:
Expand All @@ -48,18 +57,22 @@ jobs:
make -C main dev-env
- name: Build Docker Images
run: make -C main build-test-all
run: make -C main build-all-multi
env:
# Full logs for CI build
BUILDKIT_PROGRESS: plain

- name: Test Docker Images
run: make -C main test-all

- name: Clone Wiki
uses: actions/checkout@v2
with:
repository: ${{github.repository}}.wiki
path: wiki

- name: Run Post-Build Hooks
id: hook-all
run: make -C main hook-all

- name: Push Wiki to GitHub
Expand All @@ -78,4 +91,4 @@ jobs:

- name: Push Images to DockerHub
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main'
run: make -C main push-all
run: make -C main push-all-multi
80 changes: 77 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,22 @@ SHELL:=bash
OWNER?=jupyter

# Need to list the images in build dependency order

# Images supporting the following architectures:
# - linux/amd64
# - linux/arm64
MULTI_IMAGES:= \
base-notebook \
minimal-notebook
# Images that can only be built on the amd64 architecture (aka. x86_64)
AMD64_ONLY_IMAGES:= \
r-notebook \
scipy-notebook \
tensorflow-notebook \
datascience-notebook \
pyspark-notebook \
all-spark-notebook
# All of the images
ALL_IMAGES:= \
base-notebook \
minimal-notebook \
Expand All @@ -26,7 +42,7 @@ export DOCKER_BUILDKIT:=1
help:
@echo "jupyter/docker-stacks"
@echo "====================="
@echo "Replace % with a stack directory name (e.g., make build/minimal-notebook)"
@echo "Replace % with a stack directory name (e.g., make build-multi/minimal-notebook)"
@echo
@grep -E '^[a-zA-Z0-9_%/-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

Expand All @@ -40,7 +56,59 @@ build/%: ## build the latest image for a stack using the system's architecture
@docker images $(OWNER)/$(notdir $@):latest --format "{{.Size}}"
@echo "::endgroup::"
build-all: $(foreach I, $(ALL_IMAGES), build/$(I)) ## build all stacks
build-test-all: $(foreach I, $(ALL_IMAGES), build/$(I) test/$(I)) ## build and test all stacks

# Limitations on docker buildx build (using docker/buildx 0.5.1):
#
# 1. Can't --load and --push at the same time
#
# 2. Can't --load multiple platforms
#
# What does it mean to --load?
#
# - It means that the built image can be referenced by `docker` CLI, for example
# when using the `docker tag` or `docker push` commands.
#
# Workarounds due to limitations:
#
# 1. We always build a dedicated image using the current system architecture
# named as OWNER/<stack>-notebook so we always can reference that image no
# matter what during tests etc.
#
# 2. We always also build a multi-platform image during build-multi that will be
# inaccessible with `docker tag` and `docker push` etc, but this will help us
# test the build on the different platform and provide cached layers for
# later.
#
# 3. We let push-multi refer to rebuilding a multi image with `--push`.
#
# We can rely on the cached layer from build-multi now even though we never
# tagged the multi image.
#
# Outcomes of the workaround:
#
# 1. We can keep using the previously defined Makefile commands that doesn't
# include `-multi` suffix as before.
#
# 2. Assuming we have setup docker/dockerx properly to build in arm64
# architectures as well, then we can build and publish such images via the
# `-multi` suffix without needing a local registry.
#
# 3. If we get dedicated arm64 runners, we can test everything separately
# without needing to update this Makefile, and if all tests succeeds we can
# do a publish job that creates a multi-platform image for us.
#
build-multi/%: DARGS?=
build-multi/%: ## build the latest image for a stack on both amd64 and arm64
@echo "::group::Build $(OWNER)/$(notdir $@) (system's architecture)"
docker buildx build $(DARGS) --rm --force-rm -t $(OWNER)/$(notdir $@):latest ./$(notdir $@) --build-arg OWNER=$(OWNER)
@echo -n "Built image size: "
@docker images $(OWNER)/$(notdir $@):latest --format "{{.Size}}"
@echo "::endgroup::"

@echo "::group::Build $(OWNER)/$(notdir $@) (amd64,arm64)"
docker buildx build $(DARGS) --rm --force-rm -t build-multi-tmp-cache/$(notdir $@):latest ./$(notdir $@) --build-arg OWNER=$(OWNER) --platform "linux/amd64,linux/arm64"
@echo "::endgroup::"
build-all-multi: $(foreach I, $(MULTI_IMAGES), build-multi/$(I)) $(foreach I, $(AMD64_ONLY_IMAGES), build/$(I)) ## build all stacks



Expand Down Expand Up @@ -117,6 +185,13 @@ push/%: ## push all tags for a jupyter image
@echo "::endgroup::"
push-all: $(foreach I, $(ALL_IMAGES), push/$(I)) ## push all tagged images

push-multi/%: DARGS?=
push-multi/%: ## push all tags for a jupyter image that support multiple architectures
@echo "::group::Push $(OWNER)/$(notdir $@) (amd64,arm64)"
docker buildx build $(DARGS) --rm --force-rm $($(subst -,_,$(notdir $@))_EXTRA_TAG_ARGS) -t $(OWNER)/$(notdir $@):latest ./$(notdir $@) --build-arg OWNER=$(OWNER) --platform "linux/amd64,linux/arm64"
@echo "::endgroup::"
push-all-multi: $(foreach I, $(MULTI_IMAGES), push-multi/$(I)) $(foreach I, $(AMD64_ONLY_IMAGES), push/$(I)) ## push all tagged images



run/%: DARGS?=
Expand All @@ -134,5 +209,4 @@ test/%: ## run tests against a stack (only common tests or common tests + specif
@if [ ! -d "$(notdir $@)/test" ]; then TEST_IMAGE="$(OWNER)/$(notdir $@)" pytest -m "not info" test; \
else TEST_IMAGE="$(OWNER)/$(notdir $@)" pytest -m "not info" test $(notdir $@)/test; fi
@echo "::endgroup::"

test-all: $(foreach I, $(ALL_IMAGES), test/$(I)) ## test all stacks
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,18 @@ This change is tracked in the issue [#1217](https://github.com/jupyter/docker-st
- [Jupyter Website](https://jupyter.org)
- [Images on DockerHub](https://hub.docker.com/u/jupyter)

## Architectures
## CPU Architectures

Currently published containers only support x86, some containers may support cross-building with docker buildx.
All published containers support amd64 (x86_64). The base-notebook and
minimal-notebook containers also support arm64. The ambition is to have all
containers support both amd64 and arm64.

### Caveats for arm64 images

- The manifests we publish in this projects wiki as well as the image tags for
the multi platform images that also support arm, are all based on the amd64
version even though details about the installed packages versions could differ
between architectures. For the status about this, see
[#1401](https://github.com/jupyter/docker-stacks/issues/1401).
- Only the amd64 images are actively tested currently. For the status about
this, see [#1402](https://github.com/jupyter/docker-stacks/issues/1402).
19 changes: 16 additions & 3 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,23 @@ Docker destroys the container after notebook server exit, but any files written

docker run --rm -p 10000:8888 -e JUPYTER_ENABLE_LAB=yes -v "${PWD}":/home/jovyan/work jupyter/datascience-notebook:33add21fab64

Architectures
-----------
Currently published containers only support x86, some containers may support cross-building with docker buildx.
CPU Architectures
-----------------

All published containers support amd64 (x86_64). The base-notebook and
minimal-notebook containers also support arm64. The ambition is to have all
containers support both amd64 and arm64.

Caveats for arm64 images
^^^^^^^^^^^^^^^^^^^^^^^^

- The manifests we publish in this projects wiki as well as the image tags for
the multi platform images that also support arm, are all based on the amd64
version even though details about the installed packages versions could differ
between architectures. For the status about this, see
[#1401](https://github.com/jupyter/docker-stacks/issues/1401).
- Only the amd64 images are actively tested currently. For the status about
this, see [#1402](https://github.com/jupyter/docker-stacks/issues/1402).

Table of Contents
-----------------
Expand Down
11 changes: 11 additions & 0 deletions tagging/github_set_env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
import os


def github_set_env(env_name, env_value):
if not os.environ.get("GITHUB_ACTIONS") or not os.environ.get("GITHUB_ENV"):
return

with open(os.environ["GITHUB_ENV"], "a") as f:
f.write(f"{env_name}={env_value}\n")
11 changes: 11 additions & 0 deletions tagging/tag_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from plumbum.cmd import docker
from .docker_runner import DockerRunner
from .get_taggers_and_manifests import get_taggers_and_manifests
from .github_set_env import github_set_env


logger = logging.getLogger(__name__)
Expand All @@ -15,21 +16,31 @@ def tag_image(short_image_name: str, owner: str) -> None:
"""
Tags <owner>/<short_image_name>:latest with the tags reported by all taggers
for the given image.
Tags are in a GitHub Actions environment also saved to environment variables
in a format making it easy to append them.
"""
logger.info(f"Tagging image: {short_image_name}")
taggers, _ = get_taggers_and_manifests(short_image_name)

image = f"{owner}/{short_image_name}:latest"

with DockerRunner(image) as container:
tags = []
for tagger in taggers:
tagger_name = tagger.__name__
tag_value = tagger.tag_value(container)
tags.append(tag_value)
logger.info(
f"Applying tag tagger_name: {tagger_name} tag_value: {tag_value}"
)
docker["tag", image, f"{owner}/{short_image_name}:{tag_value}"]()

if tags:
env_name = f'{short_image_name.replace("-", "_")}_EXTRA_TAG_ARGS'
docker_build_tag_args = "-t " + " -t ".join(tags)
github_set_env(env_name, docker_build_tag_args)


if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
Expand Down

0 comments on commit 514883d

Please sign in to comment.