Skip to content

Commit

Permalink
Support multi-arch builds (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
tyranron committed Mar 23, 2021
1 parent 3344d58 commit b6c09cb
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 67 deletions.
28 changes: 15 additions & 13 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,27 @@ env:
&& startsWith(github.ref, 'refs/tags/alpine') }}

jobs:
docker:
buildx:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: docker/setup-qemu-action@v1
- uses: docker/setup-buildx-action@v1

- uses: satackey/[email protected]
continue-on-error: true
if: ${{ env.PUBLISH != 'true' && github.ref != 'refs/heads/master' }}
- run: make docker.image no-cache=no tag=build-${{ github.run_number }}
if: ${{ env.PUBLISH != 'true' && github.ref != 'refs/heads/master' }}
- name: Pre-build fresh Docker images cache
run: make docker.build.cache no-cache=yes

- run: make docker.image no-cache=yes tag=build-${{ github.run_number }}
if: ${{ env.PUBLISH == 'true' || github.ref == 'refs/heads/master' }}
- name: Test Docker images
run: |
# Enable experimental features of Docker Daemon to run multi-arch
# images.
echo "$(cat /etc/docker/daemon.json)" '{"experimental": true}' \
| jq --slurp 'reduce .[] as $item ({}; . * $item)' \
| sudo tee /etc/docker/daemon.json
sudo systemctl restart docker
- run: make npm.install
- run: make test.docker tag=build-${{ github.run_number }}
make npm.install
make test.docker platforms=@all build=yes
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
Expand All @@ -50,8 +54,6 @@ jobs:
password: ${{ secrets.DOCKERHUB_BOT_PASS }}
if: ${{ env.PUBLISH == 'true' }}

- run: make docker.tags of=build-${{ github.run_number }}
if: ${{ env.PUBLISH == 'true' }}
- run: make docker.push
if: ${{ env.PUBLISH == 'true' }}

Expand All @@ -74,7 +76,7 @@ jobs:
provider: dockerhub
destination_container_repo: instrumentisto/rsync-ssh
readme_file: README.md
if: ${{ env.PUBLISH == 'true' }}K
if: ${{ env.PUBLISH == 'true' }}

- name: Parse release version from Git tag
id: release
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ All user visible changes to this project will be documented in this file. This p



## [alpine3.13-r1] · 2021-03-23
[alpine3.13-r1]: /../../tree/alpine3.13-r1

[Diff](/../../compare/alpine3.13-r0...alpine3.13-r1)

### Added

- Support of `linux/arm64`, `linux/arm/v6`, `linux/arm/v7`, `linux/ppc64le` and `linux/s390x` platforms ([#5]).

[#5]: /../../issues/5




## [alpine3.13-r0] · 2021-03-23
[alpine3.13-r0]: /../../tree/alpine3.13-r0

Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
ARG alpine_ver=3.13
FROM alpine:${alpine_ver}

ARG build_rev=0
ARG build_rev=1

LABEL org.opencontainers.image.source="\
https://github.com/instrumentisto/rsync-ssh-docker-image"
Expand Down
148 changes: 99 additions & 49 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ TAGS ?= alpine$(ALPINE_VER)-r$(BUILD_REV) \
alpine \
latest
VERSION ?= $(word 1,$(subst $(comma), ,$(TAGS)))
PLATFORMS ?= linux/amd64 \
linux/arm64 \
linux/arm/v6 \
linux/arm/v7 \
linux/ppc64le \
linux/s390x
MAIN_PLATFORM ?= $(word 1,$(subst $(comma), ,$(PLATFORMS)))



Expand All @@ -43,8 +50,6 @@ push: docker.push

release: git.release

tags: docker.tags

test: test.docker


Expand All @@ -58,62 +63,86 @@ docker-namespaces = $(strip $(if $(call eq,$(namespaces),),\
$(NAMESPACES),$(subst $(comma), ,$(namespaces))))
docker-tags = $(strip $(if $(call eq,$(tags),),\
$(TAGS),$(subst $(comma), ,$(tags))))
docker-platforms = $(strip $(if $(call eq,$(platforms),),\
$(PLATFORMS),$(subst $(comma), ,$(platforms))))


# Build Docker image with the given tag.
#
# Usage:
# make docker.image [tag=($(VERSION)|<docker-tag>)]] [no-cache=(no|yes)]
# [ALPINE_VER=<alpine-version>]
# [BUILD_REV=<build-revision>]

docker.image:
docker build --network=host --force-rm \
# Runs `docker buildx build` command allowing to customize it for the purpose of
# re-tagging or pushing.
define docker.buildx
$(eval namespace := $(strip $(1)))
$(eval tag := $(strip $(2)))
$(eval platform := $(strip $(3)))
$(eval no-cache := $(strip $(4)))
$(eval args := $(strip $(5)))
docker buildx build --force-rm $(args) \
--platform $(platform) \
$(if $(call eq,$(no-cache),yes),--no-cache --pull,) \
--build-arg alpine_ver=$(ALPINE_VER) \
--build-arg build_rev=$(BUILD_REV) \
-t instrumentisto/$(NAME):$(if $(call eq,$(tag),),$(VERSION),$(tag)) ./
-t $(namespace)/$(NAME):$(tag) .
endef


# Manually push Docker images to container registries.
# Pre-build cache for Docker image builds.
#
# WARNING: This command doesn't apply tag to the built Docker image, just
# creates a build cache. To produce a Docker image with a tag, use
# `docker.tag` command right after running this one.
#
# Usage:
# make docker.build.cache
# [platforms=($(PLATFORMS)|<platform-1>[,<platform-2>...])]
# [no-cache=(no|yes)]
# [ALPINE_VER=<alpine-version>]
# [BUILD_REV=<build-revision>]

docker.build.cache:
$(call docker.buildx,\
instrumentisto,\
build-cache,\
$(shell echo "$(docker-platforms)" | tr -s '[:blank:]' ','),\
$(no-cache),\
--output 'type=image$(comma)push=false')


# Build Docker image on the given platform with the given tag.
#
# Usage:
# make docker.push [tags=($(TAGS)|<docker-tag-1>[,<docker-tag-2>...])]
# [namespaces=($(NAMESPACES)|<prefix-1>[,<prefix-2>...])]
# make docker.image
# [tag=($(VERSION)|<tag>)]
# [platform=($(MAIN_PLATFORM)|<platform>)]
# [no-cache=(no|yes)]
# [ALPINE_VER=<alpine-version>]
# [BUILD_REV=<build-revision>]

docker.push:
$(foreach tag,$(subst $(comma), ,$(docker-tags)),\
$(foreach namespace,$(subst $(comma), ,$(docker-namespaces)),\
$(call docker.push.do,$(namespace),$(tag))))
define docker.push.do
$(eval repo := $(strip $(1)))
$(eval tag := $(strip $(2)))
docker push $(repo)/$(NAME):$(tag)
endef
docker.image:
$(call docker.buildx,\
instrumentisto,\
$(if $(call eq,$(tag),),$(VERSION),$(tag)),\
$(if $(call eq,$(platform),),$(MAIN_PLATFORM),$(platform)),\
$(no-cache),\
--load)


# Tag Docker image with the given tags.
# Push Docker images to their repositories (container registries),
# along with the required multi-arch manifests.
#
# Usage:
# make docker.tags [of=($(VERSION)|<docker-tag>)]
# [tags=($(TAGS)|<docker-tag-1>[,<docker-tag-2>...])]
# [namespaces=($(NAMESPACES)|<prefix-1>[,<prefix-2>...])]

docker-tags-of = $(if $(call eq,$(of),),$(VERSION),$(of))

docker.tags:
$(foreach tag,$(subst $(comma), ,$(docker-tags)),\
$(foreach namespace,$(subst $(comma), ,$(docker-namespaces)),\
$(call docker.tags.do,$(docker-tags-of),$(namespace),$(tag))))
define docker.tags.do
$(eval from := $(strip $(1)))
$(eval repo := $(strip $(2)))
$(eval to := $(strip $(3)))
docker tag instrumentisto/$(NAME):$(from) $(repo)/$(NAME):$(to)
endef

# make docker.push
# [namespaces=($(NAMESPACES)|<prefix-1>[,<prefix-2>...])]
# [tags=($(TAGS)|<tag-1>[,<tag-2>...])]
# [platforms=($(PLATFORMS)|<platform-1>[,<platform-2>...])]
# [ALPINE_VER=<alpine-version>]
# [BUILD_REV=<build-revision>]

docker.test: test.docker
docker.push:
$(foreach namespace,$(docker-namespaces),\
$(foreach tag,$(docker-tags),\
$(call docker.buildx,\
$(namespace),\
$(tag),\
$(shell echo "$(docker-platforms)" | tr -s '[:blank:]' ','),,\
--push)))



Expand All @@ -128,16 +157,37 @@ docker.test: test.docker
# https://github.com/bats-core/bats-core
#
# Usage:
# make test.docker [tag=($(VERSION)|<tag>)]

# make test.docker
# [tag=($(VERSION)|<tag>)]
# [platforms=($(MAIN_PLATFORM)|@all|<platform-1>[,<platform-2>...])]
# [( [build=no]
# | build=yes [HARAKA_VER=<haraka-version>]
# [NODE_VER=<node-version>]
# [BUILD_REV=<build-revision>] )]

test-docker-platforms = $(strip $(if $(call eq,$(platforms),),$(MAIN_PLATFORM),\
$(if $(call eq,$(platforms),@all),$(PLATFORMS),\
$(docker-platforms))))
test.docker:
ifeq ($(wildcard node_modules/.bin/bats),)
@make npm.install
endif
IMAGE=instrumentisto/$(NAME):$(if $(call eq,$(tag),),$(VERSION),$(tag)) \
$(foreach platform,$(test-docker-platforms),\
$(call test.docker.do,\
$(if $(call eq,$(tag),),$(VERSION),$(tag)),\
$(platform)))
define test.docker.do
$(eval tag := $(strip $(1)))
$(eval platform := $(strip $(2)))
$(if $(call eq,$(build),yes),\
@make docker.image no-cache=no tag=$(tag) platform=$(platform) \
ALPINE_VER=$(ALPINE_VER) \
BUILD_REV=$(BUILD_REV) ,)
IMAGE=instrumentisto/$(NAME):$(tag) PLATFORM=$(platform) \
node_modules/.bin/bats \
--timing $(if $(call eq,$(CI),),--pretty,--formatter tap) \
tests/main.bats
endef



Expand Down Expand Up @@ -188,8 +238,8 @@ endif
# .PHONY section #
##################

.PHONY: image push release tags test \
docker.image docker.push docker.tags docker.test \
.PHONY: image push release test \
docker.build.cache docker.image docker.push \
git.release \
npm.install \
test.docker
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Rsync + SSH Docker image

## Supported tags and respective `Dockerfile` links

- [`alpine3.13-r0`, `alpine3.13`, `alpine`, `latest`][d1]
- [`alpine3.13-r1`, `alpine3.13`, `alpine`, `latest`][d1]



Expand Down
27 changes: 24 additions & 3 deletions tests/main.bats
Original file line number Diff line number Diff line change
@@ -1,18 +1,39 @@
#!/usr/bin/env bats


@test "Built on correct arch" {
run docker run --rm --platform $PLATFORM --entrypoint sh $IMAGE -c \
'uname -m'
[ "$status" -eq 0 ]
if [ "$PLATFORM" = "linux/amd64" ]; then
[ "$output" = "x86_64" ]
elif [ "$PLATFORM" = "linux/arm64" ]; then
[ "$output" = "aarch64" ]
elif [ "$PLATFORM" = "linux/arm/v6" ]; then
[ "$output" = "armv7l" ]
elif [ "$PLATFORM" = "linux/arm/v7" ]; then
[ "$output" = "armv7l" ]
else
[ "$output" = "$(echo $PLATFORM | cut -d '/' -f2-)" ]
fi
}


@test "SSH is installed" {
run docker run --rm --entrypoint sh $IMAGE -c 'which ssh'
run docker run --rm --platform $PLATFORM --entrypoint sh $IMAGE -c \
'which ssh'
[ "$status" -eq 0 ]
}


@test "rsync is installed" {
run docker run --rm --entrypoint sh $IMAGE -c 'which rsync'
run docker run --rm --platform $PLATFORM --entrypoint sh $IMAGE -c \
'which rsync'
[ "$status" -eq 0 ]
}

@test "rsync runs ok" {
run docker run --rm --entrypoint sh $IMAGE -c 'rsync --help'
run docker run --rm --platform $PLATFORM --entrypoint sh $IMAGE -c \
'rsync --help'
[ "$status" -eq 0 ]
}

0 comments on commit b6c09cb

Please sign in to comment.