From b4d88566402e95a5e02f1ffde85cf27c5554dfb6 Mon Sep 17 00:00:00 2001 From: Kenneth Bingham Date: Fri, 24 Sep 2021 15:45:46 -0400 Subject: [PATCH] add an Actions workflow to build the multi-platform container image with buildx --- .github/workflows/main.yml | 44 +++++++++++++++++++++- ziti-tunnel/docker/Dockerfile | 6 +-- ziti-tunnel/docker/Dockerfile.copy | 43 ++++++++++++++++++++++ ziti-tunnel/docker/buildx.sh | 49 +++++++++++++------------ ziti-tunnel/docker/docker-entrypoint.sh | 2 +- ziti-tunnel/docker/fetch-ziti-bins.sh | 22 ++++++++--- 6 files changed, 132 insertions(+), 34 deletions(-) create mode 100644 ziti-tunnel/docker/Dockerfile.copy diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4c6f023da..30e556ab6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,6 +5,7 @@ on: branches: - main - release-v* + - builx-action # TODO: prune after initial testing pull_request: workflow_dispatch: @@ -71,7 +72,7 @@ jobs: aws s3 sync --no-progress release/ s3://ziti-cmd-build-tmp/${{ github.run_id }} tag-and-publish: - name: Build Linux Binaries, Tag and Publish + name: Build Linux Binaries and Docker Image, Tag, and Publish runs-on: ubuntu-18.04 needs: [ mac-os-build, windows-build ] steps: @@ -127,3 +128,44 @@ jobs: run: | $(go env GOPATH)/bin/ziti-ci publish-to-artifactory $(go env GOPATH)/bin/ziti-ci trigger-jenkins-smoke-build + + - name: Set up QEMU + uses: docker/setup-qemu-action@master + with: + platforms: amd64,arm64,arm + + - name: Set up builder + id: buildx + uses: docker/setup-buildx-action@master + + - name: Login to Docker Hub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKER_HUB_API_USER }} + password: ${{ secrets.DOCKER_HUB_API_TOKEN }} + + - name: Set up image tags + env: + DOCKER_IMAGE: openziti/ziti-tunnel + id: tagprep + run: | + TAGS="${DOCKER_IMAGE}:${GITHUB_SHA::8}" + # If this is release tag then add the semver and "latest" to image tags + if [[ $GITHUB_REF =~ refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + ZITI_VERSION=${GITHUB_REF#refs/tags/v} + TAGS+=",${DOCKER_IMAGE}:${ZITI_VERSION},${DOCKER_IMAGE}:latest" + fi + # Set output parameters. + echo ::set-output name=tags::${TAGS} + + - name: Build & Push Container Image to Hub + uses: docker/build-push-action@v2 + with: + builder: ${{ steps.buildx.outputs.name }} + context: . # build context is workspace so we can copy artifacts from ./release + file: ./ziti-tunnel/docker/Dockerfile.copy # a Dockerfile that does copy instead of fetch + build-args: | # base dir for copy/add operations in Dockerfile + DOCKER_BUILD_DIR=./ziti-tunnel/docker + platforms: linux/amd64,linux/arm/v7,linux/arm64 + push: true + tags: ${{ steps.tagprep.outputs.tags }} diff --git a/ziti-tunnel/docker/Dockerfile b/ziti-tunnel/docker/Dockerfile index 818d46707..0119cbdc8 100644 --- a/ziti-tunnel/docker/Dockerfile +++ b/ziti-tunnel/docker/Dockerfile @@ -1,5 +1,5 @@ -#FROM debian:stable-slim as fetch-ziti-artifacts -FROM debian:buster-slim as fetch-ziti-artifacts +FROM debian:stable-slim as fetch-ziti-artifacts + # This build stage grabs artifacts that are copied into the final image. # It uses the same base as the final image to maximize docker cache hits. @@ -25,7 +25,7 @@ RUN bash ./fetch-ziti-bins.sh ziti-tunnel # ################ -FROM debian:buster-slim +FROM debian:stable-slim RUN mkdir -p /usr/local/bin /etc/ssl/certs RUN apt-get -q update && apt-get -q install -y --no-install-recommends iptables diff --git a/ziti-tunnel/docker/Dockerfile.copy b/ziti-tunnel/docker/Dockerfile.copy new file mode 100644 index 000000000..082e42b86 --- /dev/null +++ b/ziti-tunnel/docker/Dockerfile.copy @@ -0,0 +1,43 @@ +FROM debian:stable-slim as fetch-ziti-artifacts + +# This build stage grabs artifacts that are copied into the final image. +# It uses the same base as the final image to maximize docker cache hits. + +ARG ARTIFACTS_DIR=./release +# e.g. linux +ARG TARGETOS +# e.g. arm +ARG TARGETARCH +# e.g. v7 (OS variant) +# TARGETVARIANT + +WORKDIR /tmp + +RUN apt-get -q update && apt-get -q install -y --no-install-recommends curl ca-certificates +# workaround for `openssl rehash` not working on arm. +RUN /bin/bash -c "if ! compgen -G '/etc/ssl/certs/*.[0-9]' > /dev/null; then c_rehash /etc/ssl/certs; fi" + +COPY ${ARTIFACTS_DIR}/${TARGETARCH}/${TARGETOS}/ziti-tunnel . + +################ +# +# Main Image +# +################ + +FROM debian:stable-slim + +ARG DOCKER_BUILD_DIR=. +ARG ZITI_TUNNELER_BIN=ziti-tunnel + +RUN mkdir -p /usr/local/bin /etc/ssl/certs +RUN apt-get -q update && apt-get -q install -y --no-install-recommends iptables +# Use 32-bit arm binaries on arm64 until we have 64-bit arm builds. This also affects fetch-ziti-bins.sh. +RUN if [ "$(uname -m)" = "aarch64" ]; then dpkg --add-architecture armhf; apt update; apt install -y libc6:armhf; fi +COPY --from=fetch-ziti-artifacts /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs +COPY --from=fetch-ziti-artifacts /tmp/${ZITI_TUNNELER_BIN} /usr/local/bin +COPY ${DOCKER_BUILD_DIR}/docker-entrypoint.sh / +RUN chmod +x /docker-entrypoint.sh + +ENTRYPOINT [ "/docker-entrypoint.sh" ] +CMD [ "run" ] diff --git a/ziti-tunnel/docker/buildx.sh b/ziti-tunnel/docker/buildx.sh index 03d327b76..5315a318a 100755 --- a/ziti-tunnel/docker/buildx.sh +++ b/ziti-tunnel/docker/buildx.sh @@ -3,42 +3,46 @@ set -euo pipefail _usage(){ cat >&2 <<-EOF -Usage: VARIABLES ./buildx.sh [OPTION]... +Usage: VARIABLES ./${BASENAME} -r REPO [OPTIONS] Build multi-platform Docker container image on Linux. VARIABLES ZITI_VERSION e.g. "0.16.1" corresponding to Git tag "v0.16.1" -OPTIONS - -r REPO container image repository e.g. netfoundry/ziti-edge-tunnel - -c don't check out v\${ZITI_VERSION} (use Git working copy) +REQUIRED + -r REPO required container image repository e.g. netfoundry/ziti-edge-tunnel +OPTIONS + -c don't check out v\${ZITI_VERSION} (use Git working copy) + -P don't push the container image to Hub EXAMPLES - ZITI_VERSION=0.16.1 ./buildx.sh -c + ZITI_VERSION=0.16.1 ./${BASENAME} -c REFERENCE https://github.com/openziti/ziti-tunnel-sdk-c/blob/main/docker/BUILD.md EOF [[ $# -eq 1 ]] && { - return $1 + return "$1" } || { return 0 } } -BASENAME=$(basename $0) || exit $? -DIRNAME=$(dirname $0) || exit $? +BASENAME=$(basename "$0") || exit $? +DIRNAME=$(dirname "$0") || exit $? -while getopts :r:c OPT;do +while getopts :c:hPr: OPT;do case $OPT in - r) CONTAINER_REPO=$OPTARG - ;; c) FLAGS+=$OPT # don't checkout vZITI_VERSION ;; h) _usage; exit 0 # not an error ;; + P) FLAGS+=$OPT # don't push container image to Hub + ;; + r) CONTAINER_REPO=$OPTARG + ;; *|\?) _usage 1 # error ;; esac @@ -46,11 +50,10 @@ done shift "$((OPTIND-1))" # default to latest -: ${ZITI_VERSION:=$(git fetch --quiet --tags && git tag -l|sort -Vr|head -1|sed -E 's/^v(.*)/\1/')} +: "${ZITI_VERSION:=$(git fetch --quiet --tags && git tag -l|sort -Vr|head -1|sed -E 's/^v(.*)/\1/')}" -# required opts -[[ ! -z ${CONTAINER_REPO:+true} ]] || { - echo "ERROR: missing -r REPO option to define container image repository name for image push" >&2 +[[ -n "${CONTAINER_REPO:-}" ]] || { + echo "ERROR: missing -r REPO option to define container image repository name for tagging the image" >&2 _usage; exit 1 } @@ -59,21 +62,21 @@ if [[ ${FLAGS:-} =~ c ]]; then else git diff --exit-code # bail if unstaged differences git fetch --tags - git checkout v${ZITI_VERSION} + git checkout "v${ZITI_VERSION}" fi docker run --rm --privileged docker/binfmt:a7996909642ee92942dcd6cff44b9b95f08dad64 -egrep -q enabled /proc/sys/fs/binfmt_misc/qemu-arm -docker run --rm arm64v8/alpine uname -a|egrep -q 'aarch64 Linux' -docker run --rm arm32v7/alpine uname -a|egrep -q 'armv7l Linux' +grep -E -q enabled /proc/sys/fs/binfmt_misc/qemu-arm +docker run --rm arm64v8/alpine uname -a|grep -E -q 'aarch64 Linux' +docker run --rm arm32v7/alpine uname -a|grep -E -q 'armv7l Linux' docker buildx create --use --name=ziti-builder 2>/dev/null || docker buildx use --default ziti-builder -docker buildx build $DIRNAME \ +docker buildx build "$DIRNAME" \ --platform linux/amd64,linux/arm/v7,linux/arm64 \ - --build-arg ZITI_VERSION=${ZITI_VERSION} \ - --tag ${CONTAINER_REPO}:${ZITI_VERSION} \ - --tag ${CONTAINER_REPO}:latest \ + --build-arg "ZITI_VERSION=${ZITI_VERSION}" \ + --tag "${CONTAINER_REPO}:${ZITI_VERSION}" \ + --tag "${CONTAINER_REPO}:latest" \ --push docker buildx stop ziti-builder diff --git a/ziti-tunnel/docker/docker-entrypoint.sh b/ziti-tunnel/docker/docker-entrypoint.sh index abee5d54d..06d22ecaf 100755 --- a/ziti-tunnel/docker/docker-entrypoint.sh +++ b/ziti-tunnel/docker/docker-entrypoint.sh @@ -59,7 +59,7 @@ if [ ! -f "${json}" ]; then echo "ERROR: ${NF_REG_NAME}.jwt was not found in the expected locations" >&2 exit 1 fi - echo "INFO: enrolling ${jwt}" + echo "INFO: enrolling with token from file '${jwt}' and value '$(< ${jwt})'" ziti-tunnel enroll --jwt "${jwt}" --out "${json}" fi diff --git a/ziti-tunnel/docker/fetch-ziti-bins.sh b/ziti-tunnel/docker/fetch-ziti-bins.sh index d99b3748e..deedb83d0 100755 --- a/ziti-tunnel/docker/fetch-ziti-bins.sh +++ b/ziti-tunnel/docker/fetch-ziti-bins.sh @@ -7,8 +7,8 @@ set -euo pipefail exit 1 } -: ${ARTIFACTORY_BASE_URL:="https://netfoundry.jfrog.io/netfoundry"} -: ${ARTIFACTORY_REPO:="ziti-release"} +: "${ARTIFACTORY_BASE_URL:="https://netfoundry.jfrog.io/netfoundry"}" +: "${ARTIFACTORY_REPO:="ziti-release"}" for var in ARTIFACTORY_BASE_URL ARTIFACTORY_REPO ZITI_VERSION; do if [ -z "${!var:-}" ]; then echo "ERROR: ${var} must be set when fetching binaries from Artifactory." >&2 @@ -16,6 +16,11 @@ for var in ARTIFACTORY_BASE_URL ARTIFACTORY_REPO ZITI_VERSION; do fi done +[[ "$ZITI_VERSION" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]] || { + echo "ERROR: '$ZITI_VERSION' is not a semantic version like 2.0.0" >&2 + exit 1 +} + echo "Fetching from Artifactory." # map host architecture/os to directories that we use in netfoundry.jfrog.io. @@ -31,10 +36,15 @@ esac host_os=$(uname -s) case "${host_os}" in -"Linux") artifact_os="linux";; -"Darwin") artifact_os="darwin";; -"Windows") artifact_os="windows";; -*) echo "ERROR: ziti binaries do not exist for os ${host_os}"; exit 1;; + "Linux") artifact_os="linux" + ;; + "Darwin") artifact_os="darwin" + ;; + "Windows") artifact_os="windows" + ;; + *) echo "ERROR: ziti binaries do not exist for os ${host_os}"; + exit 1 + ;; esac for exe in "${@}"; do