Merge pull request #970 from openziti/build-release-cli-container-image

release Docker images for cli, controller, router, and tunnel
This commit is contained in:
Ken Bingham
2023-01-24 13:58:23 -05:00
committed by GitHub
20 changed files with 437 additions and 572 deletions
+24 -55
View File
@@ -89,9 +89,8 @@ jobs:
fablab-smoketest:
name: Fablab Smoketest
if: github.repository_owner == 'openziti'
runs-on: ubuntu-20.04
outputs:
ZITI_VERSION: ${{ steps.get_version.outputs.ZITI_VERSION }}
steps:
- name: Git Checkout
uses: actions/checkout@v3
@@ -154,7 +153,7 @@ jobs:
# END linux-build-steps
publish:
name: Publish Binaries and Docker Image
name: Publish Binaries
runs-on: ubuntu-20.04
needs: [ mac-os-build, windows-build, fablab-smoketest ]
outputs:
@@ -193,6 +192,14 @@ jobs:
CC=arm-linux-gnueabihf-gcc $(go env GOPATH)/bin/gox -cgo -os=linux -arch=arm -output=$GOX_OUTPUT ./...
CC=aarch64-linux-gnu-gcc $(go env GOPATH)/bin/gox -cgo -os=linux -arch=arm64 -output=$GOX_OUTPUT ./...
# upload Linux artifacts so we can copy them into a container image in another workflow
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: linux-release-${{ github.run_id }}
path: release/
retention-days: 5
- name: Download darwin release artifact
uses: actions/download-artifact@v3
with:
@@ -210,9 +217,9 @@ jobs:
with:
version: 1.51.1
# remaining steps in job only run on the upstream repo, not forks
- name: Publish
if: github.repository_owner == 'openziti' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release-v'))
- name: Publish GitHub Release
# forks need to run this step with their own GPG key because ziti-ci creates the GH release
if: env.ziti_ci_gpg_key_id != null && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release-v'))
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ziti_ci_gpg_key: ${{ secrets.ZITI_CI_GPG_KEY }}
@@ -255,55 +262,6 @@ jobs:
JFROG_API_KEY: ${{ secrets.JFROG_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Set up QEMU
if: github.repository_owner == 'openziti' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release-v'))
uses: docker/setup-qemu-action@v2
with:
platforms: amd64,arm64,arm
- name: Set up Docker BuildKit
if: github.repository_owner == 'openziti' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release-v'))
id: buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
if: github.repository_owner == 'openziti' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release-v'))
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_HUB_API_USER }}
password: ${{ secrets.DOCKER_HUB_API_TOKEN }}
- name: Set up Docker image tags
if: github.repository_owner == 'openziti' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release-v'))
env:
SNAPSHOT_REPO: openziti/ziti-tunnel
RELEASE_REPO: netfoundry/ziti-tunnel
ZITI_VERSION: ${{ steps.get_version.outputs.ZITI_VERSION }}
id: tagprep
run: |
# the Docker cross-build only runs on branches main or release-v*
# where ziti-ci always computes and publishes a new release tag
DOCKER_TAGS=""
for REPO in ${SNAPSHOT_REPO} ${RELEASE_REPO}; do
DOCKER_TAGS+=",${REPO}:${ZITI_VERSION},${REPO}:latest"
done
DOCKER_TAGS=${DOCKER_TAGS#,} # drop leading comma char
echo "DEBUG: DOCKER_TAGS=${DOCKER_TAGS}"
echo DOCKER_TAGS="${DOCKER_TAGS}" >> $GITHUB_OUTPUT
- name: Build & Push Multi-Platform Container Image to Hub
if: github.repository_owner == 'openziti' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release-v'))
uses: docker/build-push-action@v3
with:
builder: ${{ steps.buildx.outputs.name }}
context: ${{ github.workspace }} # build context is workspace so we can copy artifacts from ./release
file: ${{ github.workspace }}/ziti-tunnel/docker/Dockerfile.copy # a Dockerfile that does copy instead of fetch
build-args: | # base dir for copy/add operations should be dir containing Dockerfile
DOCKER_BUILD_DIR=./ziti-tunnel/docker
platforms: linux/amd64,linux/arm/v7,linux/arm64
push: true
tags: ${{ steps.tagprep.outputs.DOCKER_TAGS }}
jenkins-smoketest:
# BEGIN smoketest-job
#
@@ -311,7 +269,18 @@ jobs:
#
needs: publish
name: Call the On-Demand Smoketest Workflow
# not applicable to forks
if: github.repository_owner == 'openziti'
uses: ./.github/workflows/jenkins-smoketest.yml
secrets: inherit
with:
ziti-version: ${{ needs.publish.outputs.ZITI_VERSION }}
call-publish-docker-images:
if: github.ref == 'refs/heads/main'
name: Publish Docker Images
needs: publish
uses: ./.github/workflows/publish-docker-images.yml
secrets: inherit
with:
ziti-version: ${{ needs.publish.outputs.ZITI_VERSION }}
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
mattermost-ziti-webhook:
runs-on: ubuntu-latest
name: POST Webhook
if: github.actor != 'dependabot[bot]'
if: github.repository_owner == 'openziti' && github.actor != 'dependabot[bot]'
env:
ZITI_LOG: 99
ZITI_NODEJS_LOG: 99
+134
View File
@@ -0,0 +1,134 @@
name: CI build
on:
workflow_call:
inputs:
ziti-version:
description: 'Ziti Release Version'
type: string
required: true
jobs:
publish-docker-images:
runs-on: ubuntu-latest
env:
ZITI_VERSION: ${{ inputs.ziti-version || github.event.inputs.ziti-version }}
steps:
- name: Checkout Workspace
uses: actions/checkout@v3
- name: Download Linux Release Artifacts
uses: actions/download-artifact@v3
with:
name: linux-release-${{ github.run_id }}
path: release/
- name: Set Up QEMU
uses: docker/setup-qemu-action@v2
with:
platforms: amd64,arm64
- name: Set Up Docker BuildKit
id: buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_HUB_API_USER }}
password: ${{ secrets.DOCKER_HUB_API_TOKEN }}
- name: Set Up Container Image Tags for Base CLI Container
env:
RELEASE_REPO: openziti/ziti-cli
id: tagprep_cli
run: |
DOCKER_TAGS=""
DOCKER_TAGS="${RELEASE_REPO}:${ZITI_VERSION},${RELEASE_REPO}:latest"
echo "DEBUG: DOCKER_TAGS=${DOCKER_TAGS}"
echo DOCKER_TAGS="${DOCKER_TAGS}" >> $GITHUB_OUTPUT
# this is the base image into which is stuffed the Linux binary for each
# arch that was downloaded in ./release/, hence the need to specify the
# Dockerfile and DOCKER_BUILD_DIR
- name: Build & Push Multi-Platform CLI Container Image to Hub
uses: docker/build-push-action@v3
with:
builder: ${{ steps.buildx.outputs.name }}
context: ${{ github.workspace }}/
file: ${{ github.workspace }}/docker-images/ziti-cli/Dockerfile
platforms: linux/amd64,linux/arm64
tags: ${{ steps.tagprep_cli.outputs.DOCKER_TAGS }}
build-args: |
DOCKER_BUILD_DIR=./docker-images/ziti-cli
push: true
- name: Set Up Container Image Tags for Controller Container
env:
RELEASE_REPO: openziti/ziti-controller
id: tagprep_ctrl
run: |
DOCKER_TAGS=""
DOCKER_TAGS="${RELEASE_REPO}:${ZITI_VERSION},${RELEASE_REPO}:latest"
echo "DEBUG: DOCKER_TAGS=${DOCKER_TAGS}"
echo DOCKER_TAGS="${DOCKER_TAGS}" >> $GITHUB_OUTPUT
# This is a use-case image based on the minimal CLI image. It needs the
# ZITI_VERSION env var so it can build from the versioned image that
# we pushed in the prior step.
- name: Build & Push Multi-Platform Controller Container Image to Hub
uses: docker/build-push-action@v3
with:
builder: ${{ steps.buildx.outputs.name }}
context: ${{ github.workspace }}/docker-images/ziti-controller/
platforms: linux/amd64,linux/arm64
tags: ${{ steps.tagprep_ctrl.outputs.DOCKER_TAGS }}
build-args: |
ZITI_VERSION=${{ env.ZITI_VERSION }}
push: true
- name: Set Up Container Image Tags for Router Container
env:
RELEASE_REPO: openziti/ziti-router
id: tagprep_router
run: |
DOCKER_TAGS=""
DOCKER_TAGS="${RELEASE_REPO}:${ZITI_VERSION},${RELEASE_REPO}:latest"
echo "DEBUG: DOCKER_TAGS=${DOCKER_TAGS}"
echo DOCKER_TAGS="${DOCKER_TAGS}" >> $GITHUB_OUTPUT
- name: Build & Push Multi-Platform Router Container Image to Hub
uses: docker/build-push-action@v3
with:
builder: ${{ steps.buildx.outputs.name }}
context: ${{ github.workspace }}/docker-images/ziti-router/
platforms: linux/amd64,linux/arm64
tags: ${{ steps.tagprep_router.outputs.DOCKER_TAGS }}
build-args: |
ZITI_VERSION=${{ env.ZITI_VERSION }}
push: true
- name: Set Up Container Image Tags for Go Tunneler Container
env:
SNAPSHOT_REPO: netfoundry/ziti-tunnel
RELEASE_REPO: openziti/ziti-tunnel
id: tagprep_tun
run: |
DOCKER_TAGS=""
for REPO in ${SNAPSHOT_REPO} ${RELEASE_REPO}; do
DOCKER_TAGS+=",${REPO}:${ZITI_VERSION},${REPO}:latest"
done
DOCKER_TAGS=${DOCKER_TAGS#,} # drop leading comma char
echo "DEBUG: DOCKER_TAGS=${DOCKER_TAGS}"
echo DOCKER_TAGS="${DOCKER_TAGS}" >> $GITHUB_OUTPUT
- name: Build & Push Multi-Platform Go Tunneler Container Image to Hub
uses: docker/build-push-action@v3
with:
builder: ${{ steps.buildx.outputs.name }}
context: ${{ github.workspace }}/docker-images/ziti-tunnel/
platforms: linux/amd64,linux/arm64
tags: ${{ steps.tagprep_tun.outputs.DOCKER_TAGS }}
build-args: |
ZITI_VERSION=${{ env.ZITI_VERSION }}
push: true
+34
View File
@@ -0,0 +1,34 @@
# this builds docker.io/openziti/ziti-cli
FROM registry.access.redhat.com/ubi8/ubi-minimal
# 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
ARG DOCKER_BUILD_DIR=.
# e.g. linux
ARG TARGETOS
# e.g. arm64
ARG TARGETARCH
### Required OpenShift Labels
LABEL name="openziti/ziti-cli" \
maintainer="developers@openziti.org" \
vendor="NetFoundry" \
summary="Run the OpenZiti CLI" \
description="Run the OpenZiti CLI"
USER root
### add licenses to this directory
RUN mkdir -m0755 /licenses
COPY ./LICENSE /licenses/apache.txt
RUN mkdir -p /usr/local/bin
COPY ${ARTIFACTS_DIR}/${TARGETARCH}/${TARGETOS}/ziti /usr/local/bin/
RUN chmod 0755 /usr/local/bin/ziti
COPY ${DOCKER_BUILD_DIR}/entrypoint.sh /
RUN chmod +x /entrypoint.sh
USER nobody
ENTRYPOINT [ "/entrypoint.sh" ]
CMD [ "ziti" ]
+5
View File
@@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -euo pipefail
exec ziti "${@}"
+20
View File
@@ -0,0 +1,20 @@
ARG ZITI_VERSION="latest"
# this builds docker.io/openziti/ziti-controller
FROM docker.io/openziti/ziti-cli:${ZITI_VERSION}
# 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.
### Required OpenShift Labels
LABEL name="openziti/ziti-controller" \
maintainer="developers@openziti.org" \
vendor="NetFoundry" \
summary="Run the OpenZiti Controller" \
description="Run the OpenZiti Controller"
USER root
COPY ./entrypoint.sh /
RUN chmod +x /entrypoint.sh
USER nobody
ENTRYPOINT [ "/entrypoint.sh" ]
CMD [ "run" ]
@@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -euo pipefail
exec ziti controller "${@}"
+20
View File
@@ -0,0 +1,20 @@
ARG ZITI_VERSION="latest"
# this builds docker.io/openziti/ziti-router
FROM docker.io/openziti/ziti-cli:${ZITI_VERSION}
# 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.
### Required OpenShift Labels
LABEL name="openziti/ziti-router" \
maintainer="developers@openziti.org" \
vendor="NetFoundry" \
summary="Run the OpenZiti Router" \
description="Run the OpenZiti Router"
USER root
COPY ./entrypoint.sh /
RUN chmod +x /entrypoint.sh
USER nobody
ENTRYPOINT [ "/entrypoint.sh" ]
CMD [ "run" ]
+5
View File
@@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -euo pipefail
exec ziti router "${@}"
+24
View File
@@ -0,0 +1,24 @@
ARG ZITI_VERSION="latest"
# this builds docker.io/openziti/ziti-router
FROM docker.io/openziti/ziti-cli:${ZITI_VERSION}
# 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.
### Required OpenShift Labels
LABEL name="openziti/ziti-tunnel" \
maintainer="developers@openziti.org" \
vendor="NetFoundry" \
summary="Run the OpenZiti Go Tunneler" \
description="Run the OpenZiti Go Tunneler"
### Add necessary Red Hat repos and packages: "mountpoint" used by entrypoint
USER root
RUN INSTALL_PKGS="util-linux iptables" && \
microdnf -y update --setopt=install_weak_deps=0 --setopt=tsflags=nodocs && \
microdnf -y install --setopt=install_weak_deps=0 --setopt=tsflags=nodocs ${INSTALL_PKGS}
COPY ./entrypoint.sh /
RUN chmod +x /entrypoint.sh
ENTRYPOINT [ "/entrypoint.sh" ]
CMD [ "run" ]
+165
View File
@@ -0,0 +1,165 @@
#!/usr/bin/env bash
#
# Copyright 2023 NetFoundry Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
set -e -u -o pipefail
function alldone() {
# if successfully sent to background then send SIGTERM to trigger a cleanup
# of resolver config, tun devices and associated routes
[[ "${ZITI_TUNNEL_PID:-}" =~ ^[0-9]+$ ]] && {
kill -TERM "$ZITI_TUNNEL_PID"
# let entrypoint script exit after ziti tunnel PID
kill -0 "$ZITI_TUNNEL_PID" && wait "$ZITI_TUNNEL_PID"
}
}
trap alldone SIGTERM SIGINT EXIT
IDENTITIES_DIR="/netfoundry"
if ! [[ -d "${IDENTITIES_DIR}" ]]; then
echo "ERROR: need directory ${IDENTITIES_DIR} to find tokens and identities" >&2
exit 1
fi
if ! mountpoint "${IDENTITIES_DIR}" &>/dev/null; then
echo "WARN: the identities directory is only available inside this container because ${IDENTITIES_DIR} is not a mounted volume. Be careful to not publish this image with identity inside or lose access to the identity by removing the image prematurely." >&2
else
if [[ -n "${ZITI_IDENTITY_JSON:-}" ]]; then
echo "WARNING: you supplied the Ziti identity as an env var and you mounted a volume on the identities dir. You may avoid this warning and future errors by not mounting a volume on ${IDENTITIES_DIR} when ZITI_IDENTITY_JSON is defined." >&2
fi
fi
#
## Map the preferred, Ziti var names to legacy NF names. This allows us to begin using the preferred vars right away
## while minimizing immediate differences to the main control structure. This eases code review. Later, the legacy
## names can be retired and replaced.
#
if [[ -n "${ZITI_IDENTITY_BASENAME:-}" ]]; then
echo "INFO: setting NF_REG_NAME to \${ZITI_IDENTITY_BASENAME} (${ZITI_IDENTITY_BASENAME})"
NF_REG_NAME="${ZITI_IDENTITY_BASENAME}"
fi
if [[ -n "${ZITI_ENROLL_TOKEN:-}" ]]; then
echo "INFO: setting NF_REG_TOKEN to \${ZITI_ENROLL_TOKEN} (${ZITI_ENROLL_TOKEN})"
NF_REG_TOKEN="${ZITI_ENROLL_TOKEN}"
fi
if [[ -n "${ZITI_IDENTITY_WAIT:-}" ]]; then
echo "INFO: setting NF_REG_WAIT to \${ZITI_IDENTITY_WAIT} (${ZITI_IDENTITY_WAIT})"
NF_REG_WAIT="${ZITI_IDENTITY_WAIT}"
fi
# treat IOTEDGE_DEVICEID, a standard var assigned by Azure IoT, as an alias for NF_REG_NAME
if [[ -z "${NF_REG_NAME:-}" ]]; then
if [[ -n "${IOTEDGE_DEVICEID:-}" ]]; then
echo "INFO: setting NF_REG_NAME to \${IOTEDGE_DEVICEID} (${IOTEDGE_DEVICEID})"
NF_REG_NAME="${IOTEDGE_DEVICEID}"
fi
fi
# if identity JSON var is defined then write to a file
if [[ -n "${ZITI_IDENTITY_JSON:-}" ]]; then
# if the basename is not defined then use a default basename to write JSON to a file
if [[ -z "${NF_REG_NAME:-}" ]]; then
NF_REG_NAME="ziti_id"
fi
if [[ -s "${IDENTITIES_DIR}/${NF_REG_NAME}.json" ]]; then
echo "ERROR: refusing to clobber non-empty Ziti identity file ${NF_REG_NAME}.json with contents of env var ZITI_IDENTITY_JSON!" >&2
exit 1
else
echo "${ZITI_IDENTITY_JSON}" > "${IDENTITIES_DIR}/${NF_REG_NAME}.json"
fi
fi
typeset -a TUNNEL_OPTS
# if identity file, else multiple identities dir
if [[ -n "${NF_REG_NAME:-}" ]]; then
IDENTITY_FILE="${IDENTITIES_DIR}/${NF_REG_NAME}.json"
TUNNEL_OPTS=("--identity" "${IDENTITY_FILE}")
: ${NF_REG_WAIT:=1}
if [[ "${NF_REG_WAIT}" =~ ^[0-9]+$ ]]; then
echo "DEBUG: waiting ${NF_REG_WAIT}s for ${IDENTITY_FILE} (or token) to appear"
elif (( "${NF_REG_WAIT}" < 0 )); then
echo "DEBUG: waiting forever for ${IDENTITY_FILE} (or token) to appear"
else
echo "ERROR: need integer for NF_REG_WAIT" >&2
exit 1
fi
while (( $NF_REG_WAIT > 0 || $NF_REG_WAIT < 0)); do
# if non-empty identity file
if [[ -s "${IDENTITY_FILE}" ]]; then
echo "INFO: found identity file ${IDENTITY_FILE}"
break 1
# look for enrollment token
else
echo "INFO: identity file ${IDENTITY_FILE} does not exist"
for dir in "/var/run/secrets/netfoundry.io/enrollment-token" \
"/enrollment-token" \
"${IDENTITIES_DIR}"; do
JWT_CANDIDATE="${dir}/${NF_REG_NAME}.jwt"
echo "INFO: looking for ${JWT_CANDIDATE}"
if [[ -s "${JWT_CANDIDATE}" ]]; then
JWT_FILE="${JWT_CANDIDATE}"
break 1
fi
done
if [[ -n "${JWT_FILE:-}" ]]; then
echo "INFO: enrolling ${JWT_FILE}"
ziti edge enroll --jwt "${JWT_FILE}" --out "${IDENTITY_FILE}" || {
echo "ERROR: failed to enroll with token from ${JWT_FILE} ($(wc -c < "${JWT_FILE}")B)" >&2
exit 1
}
elif [[ -n "${NF_REG_TOKEN:-}" ]]; then
echo "INFO: attempting enrollment with NF_REG_TOKEN"
if [[ -s "${IDENTITIES_DIR}/${NF_REG_NAME}.jwt" ]]; then
echo "ERROR: refusing to clobber non-empty enrollment OTP file ${NF_REG_NAME}.jwt with contents of env var NF_REG_TOKEN!" >&2
exit 1
else
echo "${NF_REG_TOKEN}" > "${IDENTITIES_DIR}/${NF_REG_NAME}.jwt"
fi
ziti edge enroll --jwt "${IDENTITIES_DIR}/${NF_REG_NAME}.jwt" --out "${IDENTITY_FILE}" || {
echo "ERROR: failed to enroll with token from NF_REG_TOKEN ($(wc -c <<<"${NF_REG_TOKEN}")B)" >&2
exit 1
}
fi
fi
# decrement the wait seconds until zero or forever if negative
(( NF_REG_WAIT-- ))
sleep 1
done
else
typeset -a JSON_FILES
mapfile -t JSON_FILES < <(ls -1 "${IDENTITIES_DIR}"/*.json)
if [[ ${#JSON_FILES[*]} -gt 0 ]]; then
echo "INFO: NF_REG_NAME not set, loading ${#JSON_FILES[*]} identities from ${IDENTITIES_DIR}"
TUNNEL_OPTS=("--identity-dir" "${IDENTITIES_DIR}")
else
echo "ERROR: NF_REG_NAME not set and zero identities found in ${IDENTITIES_DIR}" >&2
exit 1
fi
fi
echo "DEBUG: evaluating positionals: $*"
if (( ${#} )) && [[ ${1} =~ t?proxy|host ]]; then
TUNNEL_RUN_MODE=${1}
shift
else
TUNNEL_RUN_MODE=run
fi
echo "INFO: running \"ziti tunnel ${TUNNEL_RUN_MODE} ${TUNNEL_OPTS[*]} ${*}\""
ziti tunnel "${TUNNEL_RUN_MODE}" "${TUNNEL_OPTS[@]}" "${@}" &
ZITI_TUNNEL_PID=$!
wait $ZITI_TUNNEL_PID
-6
View File
@@ -1,6 +0,0 @@
# enrollments in-use with Docker Compose
*.json
*.jwt
# executable from fetch bins script
/ziti-tunnel
-112
View File
@@ -1,112 +0,0 @@
The Dockerfile and scripts in this directory build a `ziti-tunnel` (Go tunneler) Docker image. This procedure is highly similar to that of the `ziti-edge-tunnel` (C tunneler) Docker image [documented here](https://github.com/openziti/ziti-tunnel-sdk-c/blob/main/docker/BUILD.md).
Ziti binaries are downloaded from https://netfoundry.artifactory.io/netfoundry/ziti-release
by default. The following build arguments are supported:
| Build Argument | Description |
| -------------------- | ----------------------------------------------------------------- |
| ZITI_VERSION | The version of the ziti binaries to fetch from artifactory. |
| ARTIFACTORY_TOKEN | An Artifactory token with read access to the artifact repository. This is not needed if using the default ARTIFACTORY_BASE_URL / ARTIFACTORY_REPO. |
| ARTIFACTORY_BASE_URL | Defaults to "https://netfoundry.jfrog.io/netfoundry". |
| ARTIFACTORY_REPO | Defaults to "ziti-release". |
# Building multi-platform Images
Use this build method if you're pushing the ziti-tunnel image to a public image
registry.
This build method creates images for the amd64 and arm/v7 platforms, but it
requires experimental Docker features and may involve more setup than you're
willing to endure. See "Building for Development" if you just want to build the
ziti-tunnel image for use on your local workstation, and don't plan on pushing
the image to a public registry.
## Prerequisites
1. Enable Docker Experimental Features
See https://docs.docker.com/engine/reference/commandline/cli/#experimental-features
2. Install & Enable qemu Emulation for Arm (Docker CE / Linux only)
This is taken care of by Docker Desktop if you're building on macOS or Windows,
but you'll need to install qemu emulation support and register Arm binaries to
run on your (presumably) x86_64 build host if you are running Docker CE on Linux:
$ sudo dnf install -y qemu-system-arm
$ docker run --rm --privileged docker/binfmt:66f9012c56a8316f9244ffd7622d7c21c1f6f28d
Verify that the Arm qemu handler is registered:
$ cat /proc/sys/fs/binfmt_misc/qemu-arm
enabled
interpreter /usr/bin/qemu-arm
...
Ensure that the first line of the file is "enabled".
3. Create a Builder Instance
$ docker buildx create --use --name=ziti-builder
## Building
Run `docker buildx` like this:
$ ziti_version="0.19.11"
$ docker buildx build \
--platform linux/amd64,linux/arm/v7,linux/aarch64 \
--build-arg ZITI_VERSION="${ziti_version}" \
-t "netfoundry/ziti-tunnel:${ziti_version}" .
Notes:
- You'll need to append "--push" to this command, and then subsequently pull the
image to be able to use the image locally.
Unfortunately `buildx` doesn't currently support building images directly into
the local docker cache. Although the `--load` and `--output=type=docker` options
exist, the underlying capability to load a multi-platform image (OCI) will be
implemented in a future Docker release (see https://github.com/docker/buildx/issues/59).
In the meantime, you'll need to push your image builds (with the `--push` build option)
and then pull them to run the image locally when building with `buildx`.
- The armv8 image uses armv7 (32-bit) ziti executables. The 32-bit compatibility
libraries are installed in the image, but your Arm CPU must support 32-bit emulation.
## References:
- <https://docs.docker.com/buildx/working-with-buildx/>
- <https://www.docker.com/blog/multi-arch-images/>
- <https://community.arm.com/developer/tools-software/tools/b/tools-software-ides-blog/posts/getting-started-with-docker-for-arm-on-linux>
- <https://medium.com/@drpdishant/installing-docker-on-fedora-31-a073db823bb8>
# Building for Development
This build method produces an image for the CPU that is running the build host
(typically amd64), and places the resulting image into your local Docker image
cache.
$ git fetch --tags && git tag -l | sort -Vr | head -1
v0.19.11
$ ziti_version="0.19.11" \
$ docker build \
--build-arg ZITI_VERSION="${ziti_version}" \
-t "netfoundry/ziti-tunnel:${ziti_version}" .
## Shell Script for Linux
$ ./buildx.sh -h
Usage: VARIABLES ./buildx.sh [OPTION]...
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)
EXAMPLES
ZITI_VERSION=0.19.11 ./buildx.sh -r netfoundry/ziti-tunnel
-38
View File
@@ -1,38 +0,0 @@
FROM debian:buster-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 ZITI_VERSION
ARG ARTIFACTORY_TOKEN
ARG ARTIFACTORY_BASE_URL="https://netfoundry.jfrog.io/netfoundry"
# to fetch snapshots from the "feature-0.5" branch, set ZITI_REPO="ziti-snapshot/feature-0.5"
ARG ARTIFACTORY_REPO="ziti-release"
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 fetch-ziti-bins.sh .
RUN bash ./fetch-ziti-bins.sh ziti-tunnel
################
#
# Main Image
#
################
FROM debian:buster-slim
RUN mkdir -p /usr/local/bin /etc/ssl/certs
RUN apt-get -q update && apt-get -q install -y --no-install-recommends iptables
COPY --from=fetch-ziti-artifacts /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs
COPY --from=fetch-ziti-artifacts /tmp/ziti-tunnel /usr/local/bin
COPY ./docker-entrypoint.sh /
RUN chmod +x /docker-entrypoint.sh
ENTRYPOINT [ "/docker-entrypoint.sh" ]
CMD [ "run" ]
-41
View File
@@ -1,41 +0,0 @@
FROM debian:buster-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:buster-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
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" ]
-3
View File
@@ -1,3 +0,0 @@
# Ziti-tunnel Container Image
[Link to container tunneler docs](https://docs.openziti.io/docs/reference/tunnelers/linux/container/)
-89
View File
@@ -1,89 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
_usage(){
cat >&2 <<-EOF
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"
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 ./${BASENAME} -c
REFERENCE
https://github.com/openziti/ziti-tunnel-sdk-c/blob/main/docker/BUILD.md
EOF
[[ $# -eq 1 ]] && {
return "$1"
} || {
return 0
}
}
BASENAME=$(basename "$0") || exit $?
DIRNAME=$(dirname "$0") || exit $?
while getopts :chPr: OPT;do
case $OPT in
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
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/')}"
[[ -n "${CONTAINER_REPO:-}" ]] || {
echo "ERROR: missing -r REPO option to define container image repository name for tagging the image" >&2
_usage; exit 1
}
if [[ ${FLAGS:-} =~ c ]]; then
echo "WARN: not checking out Git tag v${ZITI_VERSION}"
else
git diff --exit-code # bail if unstaged differences
git fetch --tags
git checkout "v${ZITI_VERSION}"
fi
docker run --rm --privileged linuxkit/binfmt:v0.8
grep -E -q enabled /proc/sys/fs/binfmt_misc/qemu-arm
docker run --rm --platform arm arm32v7/alpine uname -a|grep -E -q 'armv7l Linux'
docker run --rm --platform arm64 arm64v8/alpine uname -a|grep -E -q 'aarch64 Linux'
docker buildx create --use --name=ziti-builder 2>/dev/null || docker buildx use --default ziti-builder
# if default then push to Hub
BUILDX_OUTPUT="--push"
if [[ ${FLAGS:-} =~ P ]]; then
# if no push then load in image cache
BUILDX_OUTPUT=""
fi
eval 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" \
"${BUILDX_OUTPUT:-}"
docker buildx stop ziti-builder
-54
View File
@@ -1,54 +0,0 @@
version: "3.9"
x-base-service: &base-service
image: netfoundry/ziti-tunnel:latest # https://hub.docker.com/r/netfoundry/ziti-tunnel/tags?page=1&ordering=last_updated
volumes:
- .:/netfoundry # mount current dir (relative to Compose file) with identity config file
environment:
- NF_REG_NAME # NF_REG_NAME=AcmeIdentity docker-compose up ziti-host
- NF_REG_TOKEN # NF_REG_NAME=AcmeIdentity NF_REG_TOKEN=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbSI6Im90dCIsImV4cCI6MTY1MzE2NzcwOCwiaXNzIjoiaHR0cHM6Ly81MGEyMDc4Zi01MGQyLTRhZTAtYWI4Ny0wYTdjMjM1OWVjOTYucHJvZHVjdGlvbi5uZXRmb3VuZHJ5LmlvOjQ0MyIsImp0aSI6IjFiMjJkMzc2LTMzMWItNDMxNS1iZTFiLWJkOTUzYThiYWM4ZiIsInN1YiI6InRGLnZnLjdwM1kifQ.TWbk3-kjBRKwQCXMoD93sXtyQhZOMZ1iJzV73Sqft-cEOkV2kjbA4TBRwl0nuLPCdJqkhPl9Yc1WG7YaYWYXV4ghE1Hk0Gta_HlpWdNjNlB1cVrzMyxaoCXhaX5xqGnwDuqfOK7q6DItuNsKouM2G6KKZvhGOacax6TvP-sunsxFz6AdYQJizNBoL5fJ14r1_O6yczGd5GSd8x9-eP5rNMQuRdUtiu69b-rEu1gO2SXVTrADTD5p8sP9khbT_eQzIDD9jgagXoJJvOKTVdsUAWS7YKfk1On0BpxNvv30bQ6eAkliwU7GTXDR2IPW-blZYt1Wtf3sgeuTDCCtVO_7gjSn7WM7YJqpsB72V-43Xz8I7LCDa0u48baSmmpPDUSphIBDa_nksPZk8jfwx4pHoHYbSbD4r47Af_9P-JUQRT8hzNuvktG56kmcqVCfEZHT-4xgK0Lvxxp4mzqdcNyCB0VwC6kdk7OlxwqmftDWrJhNuxKMy2MtyTjG0mwHxt4P0y_fZo1ZYJZU5AzvxrE9OLTjsQ4nV5NliJ3Qxaw_taCaIWxn98BeiHfAiIc3EL7bWGjAfXz-XWvWG8-AcCmK-cxIj7Pvj0U7lIWH7bVcRmVVc0fQnXdACkeQe7ixWr4IopV5YJ607zm6Qk_am_MrERla6xyXblvroWIITN2aEUk docker-compose up ziti-host
- PFXLOG_NO_JSON=true # suppress JSON logging
network_mode: host # use the Docker host's network, not the Docker bridge
x-iptables-capabilities: &iptables-capabilities
cap_add:
- NET_ADMIN # iptables filter
- NET_RAW # iptables mangle
services:
ziti-tproxy: # iptables transparent interceptor with DNS
<<: *base-service
<<: *iptables-capabilities
dns: # optionally, override DNS inherited from Docker host
- 127.0.0.1 # this first NS must match the built-in nameserver's bind address,
- 1.1.1.1 # and a recursive NS is also needed e.g. 8.8.8.8
command:
- tproxy
#- --resolver=udp://127.1.2.3:53 # override nameserver bind address (always 53/udp); default is 127.0.0.1
#- --dnsSvcIpRange=100.64.64.0/18 # override the IP range used for DNS intercepts; default is 100.64/10
ziti-tproxy-ip: # iptables transparent interceptor without DNS
<<: *base-service
<<: *iptables-capabilities
command:
- tproxy
- --resolver none
#- --dnsSvcIpRange=100.64.64.0/18 # override the IP range used for DNS intercepts; default is 100.64/10
ziti-test: # docker-compose exec ziti-test bash
<<: *base-service
<<: *iptables-capabilities
entrypoint: ["sh", "-c", "while true; do sleep infinity; done"]
ziti-host: # terminate a service for a server that's reachable by the host network
<<: *base-service
command: host
ziti-bridge: # terminate a service for a server that's reachable by this Docker network (default mode is "bridge")
<<: *base-service
network_mode: bridge
command: host
ziti-proxy: # bind a named service to a container TCP port, optionally forward host TCP port to container
<<: *base-service
ports:
- "8888:8888" # optionally forward host ports to container ports listening as TCP proxy
network_mode: bridge
command:
- proxy
- '"my example service":8888' # example named service and container port to bind as TCP proxy
-105
View File
@@ -1,105 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
function alldone() {
# if successfully sent to background then send SIGINT to trigger a cleanup
# of iptables mangle rules and loopback assignments
[[ "${ZITI_TUNNEL_PID:-}" =~ ^[0-9]+$ ]] && {
kill -INT "$ZITI_TUNNEL_PID"
# let entrypoint script exit after ziti-tunnel PID
wait "$ZITI_TUNNEL_PID"
}
}
trap alldone exit
# Ensure that ziti-tunnel's identity is stored on a volume
# so we don't throw away the one-time enrollment token
IDENTITIES_DIR="/netfoundry"
if ! mountpoint "${IDENTITIES_DIR}" &>/dev/null; then
echo "ERROR: please run this container with a volume mounted on ${IDENTITIES_DIR}" >&2
exit 1
fi
# IOTEDGE_DEVICEID is a standard var assigned by Azure IoT
if [[ -z "${NF_REG_NAME:-}" ]]; then
if [[ -n "${IOTEDGE_DEVICEID:-}" ]]; then
echo "DEBUG: setting NF_REG_NAME to \${IOTEDGE_DEVICEID} (${IOTEDGE_DEVICEID})"
NF_REG_NAME="${IOTEDGE_DEVICEID}"
fi
fi
typeset -a TUNNEL_OPTS
# if identity file name, else critical error
if [[ -n "${NF_REG_NAME:-}" ]]; then
IDENTITY_FILE="${IDENTITIES_DIR}/${NF_REG_NAME}.json"
TUNNEL_OPTS=("--identity" "${IDENTITY_FILE}")
# if non-empty identity file
if [[ -s "${IDENTITY_FILE}" ]]; then
echo "DEBUG: found identity file ${IDENTITY_FILE}"
# look for enrollment token
else
echo "DEBUG: identity file ${IDENTITY_FILE} does not exist"
for dir in "/var/run/secrets/netfoundry.io/enrollment-token" \
"/enrollment-token" \
"${IDENTITIES_DIR}"; do
JWT_CANDIDATE="${dir}/${NF_REG_NAME}.jwt"
echo "DEBUG: looking for ${JWT_CANDIDATE}"
if [[ -s "${JWT_CANDIDATE}" ]]; then
JWT_FILE="${JWT_CANDIDATE}"
break
fi
done
if [[ -n "${JWT_FILE:-}" ]]; then
echo "DEBUG: enrolling ${JWT_FILE}"
ziti-tunnel enroll --verbose --jwt "${JWT_FILE}" --identity "${IDENTITY_FILE}" || {
echo "ERROR: failed to enroll with token from ${JWT_FILE} ($(wc -c < "${JWT_FILE}")B)" >&2
exit 1
}
elif [[ -n "${NF_REG_TOKEN:-}" ]]; then
echo "DEBUG: attempting enrollment with NF_REG_TOKEN"
JWT_FILE=${IDENTITIES_DIR}/${NF_REG_NAME}.jwt
echo "${NF_REG_TOKEN}" >| ${JWT_FILE}
ziti-tunnel enroll --verbose --jwt ${JWT_FILE} --identity "${IDENTITY_FILE}" || {
echo "ERROR: failed to enroll with token from NF_REG_TOKEN ($(wc -c <<<"${NF_REG_TOKEN}")B)" >&2
exit 1
}
elif ! [[ -t 0 ]]; then
echo "DEBUG: trying to get token from stdin" >&2
JWT_FILE=${IDENTITIES_DIR}/${NF_REG_NAME}.jwt
while read -r; do
echo "$REPLY" >> ${JWT_FILE}
done
ziti-tunnel enroll --verbose --jwt ${JWT_FILE} --identity "${IDENTITY_FILE}" || {
echo "ERROR: failed to enroll with token from stdin, got $(wc -c < ${JWT_FILE})B" >&2
exit 1
}
else
echo "DEBUG: ${NF_REG_NAME}.jwt and env var \$NF_REG_TOKEN not found" >&2
exit 1
fi
fi
else
echo "ERROR: need NF_REG_NAME env var to save the identity file in volume mounted on ${IDENTITIES_DIR}" >&2
exit 1
fi
echo "INFO: probing iptables"
if iptables -t mangle -S --wait 2>&1 | grep -q "iptables-legacy tables present"; then
for LEGACY in {ip{,6},eb,arp}tables; do
if which ${LEGACY}-legacy &>/dev/null; then
echo "INFO: updating $LEGACY alternative to ${LEGACY}-legacy"
update-alternatives --set $LEGACY "$(which ${LEGACY}-legacy)"
else
echo "WARN: not updating $LEGACY alternative to ${LEGACY}-legacy" >&2
fi
done
fi
# optionally run an alternative shell CMD
echo "running ziti-tunnel"
set -x
ziti-tunnel "${TUNNEL_OPTS[@]}" "${@}" &
ZITI_TUNNEL_PID=$!
wait $ZITI_TUNNEL_PID
-68
View File
@@ -1,68 +0,0 @@
#!/bin/bash
set -euo pipefail
[[ $# -eq 0 ]] && {
echo "ERROR: need the base name(s) of the executable(s) to fetch e.g. \"ziti-tunnel ...\"." >&2
exit 1
}
: "${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
exit 1
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.
# (our artifact directories seem to align with Docker's TARGETARCH and TARGETOS
# build arguments, which we could rely on if we fully committed to "docker buildx" - see
# https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope)
host_arch=$(uname -m)
case "${host_arch}" in
"x86_64") artifact_arch="amd64";;
"armv7l") artifact_arch="arm";;
"aarch64") artifact_arch="arm64";;
*) echo "ERROR: ziti binaries do not exist for architecture ${host_arch}"; exit 1;;
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
;;
esac
for exe in "${@}"; do
url="${ARTIFACTORY_BASE_URL}/${ARTIFACTORY_REPO}/${exe}/${artifact_arch}/${artifact_os}/${ZITI_VERSION}/${exe}.tar.gz"
echo "Fetching ${exe} from ${url}"
rm -f "${exe}" "${exe}.tar.gz" "${exe}.exe"
token_header="${ARTIFACTORY_TOKEN:+X-JFrog-Art-Api:$ARTIFACTORY_TOKEN}"
if { command -v curl > /dev/null; } 2>&1; then
curl ${token_header:+-H "$token_header"} -fLsS -O "${url}"
elif { command -v wget > /dev/null; } 2>&1; then
wget ${token_header:+--header "$token_header"} "${url}"
else
echo "ERROR: need one of curl or wget to fetch the artifact." >&2
exit 1
fi
tar -xzf "${exe}.tar.gz"
if [ -f "${exe}" ]; then chmod 755 "${exe}"; fi
if [ -f "${exe}.exe" ]; then chmod 755 "${exe}.exe"; fi
rm "${exe}.tar.gz"
done