mirror of
https://github.com/jupyter/docker-stacks.git
synced 2025-10-18 15:32:56 +00:00
Merge pull request #1399 from mathbunnyru/asalikhov/arm_builds
Support arm builds
This commit is contained in:
17
.github/workflows/docker.yml
vendored
17
.github/workflows/docker.yml
vendored
@@ -32,6 +32,15 @@ jobs:
|
|||||||
!contains(github.event.pull_request.title, 'ci skip')
|
!contains(github.event.pull_request.title, 'ci skip')
|
||||||
|
|
||||||
steps:
|
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
|
- name: Clone Main Repo
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
@@ -48,11 +57,14 @@ jobs:
|
|||||||
make -C main dev-env
|
make -C main dev-env
|
||||||
|
|
||||||
- name: Build Docker Images
|
- name: Build Docker Images
|
||||||
run: make -C main build-test-all
|
run: make -C main build-all-multi
|
||||||
env:
|
env:
|
||||||
# Full logs for CI build
|
# Full logs for CI build
|
||||||
BUILDKIT_PROGRESS: plain
|
BUILDKIT_PROGRESS: plain
|
||||||
|
|
||||||
|
- name: Test Docker Images
|
||||||
|
run: make -C main test-all
|
||||||
|
|
||||||
- name: Clone Wiki
|
- name: Clone Wiki
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
@@ -60,6 +72,7 @@ jobs:
|
|||||||
path: wiki
|
path: wiki
|
||||||
|
|
||||||
- name: Run Post-Build Hooks
|
- name: Run Post-Build Hooks
|
||||||
|
id: hook-all
|
||||||
run: make -C main hook-all
|
run: make -C main hook-all
|
||||||
|
|
||||||
- name: Push Wiki to GitHub
|
- name: Push Wiki to GitHub
|
||||||
@@ -78,4 +91,4 @@ jobs:
|
|||||||
|
|
||||||
- name: Push Images to DockerHub
|
- name: Push Images to DockerHub
|
||||||
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main'
|
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
Makefile
80
Makefile
@@ -7,6 +7,22 @@ SHELL:=bash
|
|||||||
OWNER?=jupyter
|
OWNER?=jupyter
|
||||||
|
|
||||||
# Need to list the images in build dependency order
|
# 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:= \
|
ALL_IMAGES:= \
|
||||||
base-notebook \
|
base-notebook \
|
||||||
minimal-notebook \
|
minimal-notebook \
|
||||||
@@ -26,7 +42,7 @@ export DOCKER_BUILDKIT:=1
|
|||||||
help:
|
help:
|
||||||
@echo "jupyter/docker-stacks"
|
@echo "jupyter/docker-stacks"
|
||||||
@echo "====================="
|
@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
|
@echo
|
||||||
@grep -E '^[a-zA-Z0-9_%/-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
@grep -E '^[a-zA-Z0-9_%/-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||||
|
|
||||||
@@ -40,7 +56,59 @@ build/%: ## build the latest image for a stack using the system's architecture
|
|||||||
@docker images $(OWNER)/$(notdir $@):latest --format "{{.Size}}"
|
@docker images $(OWNER)/$(notdir $@):latest --format "{{.Size}}"
|
||||||
@echo "::endgroup::"
|
@echo "::endgroup::"
|
||||||
build-all: $(foreach I, $(ALL_IMAGES), build/$(I)) ## build all stacks
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -117,6 +185,13 @@ push/%: ## push all tags for a jupyter image
|
|||||||
@echo "::endgroup::"
|
@echo "::endgroup::"
|
||||||
push-all: $(foreach I, $(ALL_IMAGES), push/$(I)) ## push all tagged images
|
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?=
|
run/%: DARGS?=
|
||||||
@@ -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; \
|
@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
|
else TEST_IMAGE="$(OWNER)/$(notdir $@)" pytest -m "not info" test $(notdir $@)/test; fi
|
||||||
@echo "::endgroup::"
|
@echo "::endgroup::"
|
||||||
|
|
||||||
test-all: $(foreach I, $(ALL_IMAGES), test/$(I)) ## test all stacks
|
test-all: $(foreach I, $(ALL_IMAGES), test/$(I)) ## test all stacks
|
||||||
|
16
README.md
16
README.md
@@ -105,6 +105,18 @@ This change is tracked in the issue [#1217](https://github.com/jupyter/docker-st
|
|||||||
- [Jupyter Website](https://jupyter.org)
|
- [Jupyter Website](https://jupyter.org)
|
||||||
- [Images on DockerHub](https://hub.docker.com/u/jupyter)
|
- [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).
|
||||||
|
@@ -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
|
docker run --rm -p 10000:8888 -e JUPYTER_ENABLE_LAB=yes -v "${PWD}":/home/jovyan/work jupyter/datascience-notebook:33add21fab64
|
||||||
|
|
||||||
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).
|
||||||
|
|
||||||
Table of Contents
|
Table of Contents
|
||||||
-----------------
|
-----------------
|
||||||
|
11
tagging/github_set_env.py
Normal file
11
tagging/github_set_env.py
Normal file
@@ -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")
|
@@ -6,6 +6,7 @@ import logging
|
|||||||
from plumbum.cmd import docker
|
from plumbum.cmd import docker
|
||||||
from .docker_runner import DockerRunner
|
from .docker_runner import DockerRunner
|
||||||
from .get_taggers_and_manifests import get_taggers_and_manifests
|
from .get_taggers_and_manifests import get_taggers_and_manifests
|
||||||
|
from .github_set_env import github_set_env
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -15,6 +16,9 @@ def tag_image(short_image_name: str, owner: str) -> None:
|
|||||||
"""
|
"""
|
||||||
Tags <owner>/<short_image_name>:latest with the tags reported by all taggers
|
Tags <owner>/<short_image_name>:latest with the tags reported by all taggers
|
||||||
for the given image.
|
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}")
|
logger.info(f"Tagging image: {short_image_name}")
|
||||||
taggers, _ = get_taggers_and_manifests(short_image_name)
|
taggers, _ = get_taggers_and_manifests(short_image_name)
|
||||||
@@ -22,14 +26,21 @@ def tag_image(short_image_name: str, owner: str) -> None:
|
|||||||
image = f"{owner}/{short_image_name}:latest"
|
image = f"{owner}/{short_image_name}:latest"
|
||||||
|
|
||||||
with DockerRunner(image) as container:
|
with DockerRunner(image) as container:
|
||||||
|
tags = []
|
||||||
for tagger in taggers:
|
for tagger in taggers:
|
||||||
tagger_name = tagger.__name__
|
tagger_name = tagger.__name__
|
||||||
tag_value = tagger.tag_value(container)
|
tag_value = tagger.tag_value(container)
|
||||||
|
tags.append(tag_value)
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Applying tag tagger_name: {tagger_name} tag_value: {tag_value}"
|
f"Applying tag tagger_name: {tagger_name} tag_value: {tag_value}"
|
||||||
)
|
)
|
||||||
docker["tag", image, f"{owner}/{short_image_name}:{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__":
|
if __name__ == "__main__":
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
Reference in New Issue
Block a user