Skip to content

Commit

Permalink
Feature: Add release docker image
Browse files Browse the repository at this point in the history
Co-authored-by: Michael Wyraz <[email protected]>
Signed-off-by: Leonard Jonathan Oh <[email protected]>
  • Loading branch information
leojonathanoh and micw committed Dec 12, 2023
1 parent 1fb5bf6 commit 04a99b6
Show file tree
Hide file tree
Showing 6 changed files with 430 additions and 1 deletion.
157 changes: 157 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
name: docker
on:
push:
# Build on main
branches:
- main
tags:
- '**'
# TODO: Remove pull_request before merging
pull_request:
branches:
- main

permissions:
contents: read
packages: write
# Ensure cosign can request for Github's OIDC JWT ID token
# See: https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-cloud-providers#adding-permissions-settings
id-token: write

jobs:
# This job builds the binaries and uploads it as github artifacts.
# This allows us to use the same binaries for any release CI jobs.
build:
name: Build all linux architectures
runs-on: ubuntu-latest
steps:
- name: setup go
uses: actions/setup-go@v3
with:
go-version: ${{ env.GO_VERSION }}

- uses: actions/checkout@v3
with:
# Fetch all tags
fetch-depth: 0

- name: Build on all supported architectures
run: |
set -e
./scripts/release.sh
- uses: actions/upload-artifact@v3
with:
name: binaries-${{ github.sha }}
path: |
release*/*
# This job downloads the binaries previously uploaded as artifacts, and builds multi-arch images
build-docker-image:
needs: [build]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
# Fetch all tags
fetch-depth: 0

- name: Prepare
id: prep
run: |
set -e
TAG=$( git describe --tags --dirty ) # E.g. v1.2.0-23-g60ee190
echo "TAG=$TAG" >> $GITHUB_ENV
# This step generates the docker tags
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
with:
images: |
${{ github.repository }}
ghcr.io/${{ github.repository }}
# type=ref,event=pr generates tag(s) on PRs only. E.g. 'pr-123', 'pr-123-abc0123'
# type=ref,event=branch generates tag(s) on branch only. E.g. 'main-abc0123'
# type=semver generates tag(s) on tags only. E.g. 'v0', 'v0.0', 'v0.0.0', and 'latest'
tags: |
type=ref,event=pr
type=ref,suffix=-{{sha}},event=branch
type=semver,pattern=v{{major}}
type=semver,pattern=v{{major}}.{{minor}}
type=semver,pattern=v{{major}}.{{minor}}.{{patch}}
# The rest of the org.opencontainers.image.xxx labels are dynamically generated
labels: |
org.opencontainers.image.description=CNI Plugins
org.opencontainers.image.licenses=Apache License 2.0
# See: https://github.com/docker/build-push-action/blob/v2.6.1/docs/advanced/cache.md#github-cache
- name: Set up QEMU
uses: docker/setup-qemu-action@v2

- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v2

- name: Cache Docker layers
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Login to Docker Hub registry
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- uses: actions/download-artifact@v3
with:
name: binaries-${{ github.sha }}

- run: |
ls -al release*/
- name: Build and push
id: build-and-push
# TODO: Remove pull_request before merging
if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')
uses: docker/build-push-action@v3
with:
build-args: |
TAG=${{ env.TAG }}
context: '.'
file: Dockerfile
platforms: linux/amd64,linux/arm,linux/arm64,linux/mips64le,linux/ppc64le,linux/riscv64,linux/s390x
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max

- name: Install cosign
uses: sigstore/cosign-installer@1fc5bd396d372bee37d608f955b336615edf79c8 # v3.2.0
- name: Check install!
run: cosign version

# This signs the image using ACTIONS_ID_TOKEN_REQUEST_TOKEN
- name: Sign the published Docker image
run: echo "${{ steps.meta.outputs.tags }}" | xargs -I {} cosign sign --yes {}@${{ steps.build-and-push.outputs.digest }}

# Temp fix
# https://github.com/docker/build-push-action/issues/252
# https://github.com/moby/buildkit/issues/1896
- name: Move cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
42 changes: 42 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
FROM busybox as test

ADD docker-installer/install_cni_plugins.sh /script/install_cni_plugins.sh
ADD docker-installer/test_install_cni_plugins.sh /script/test_install_cni_plugins.sh
WORKDIR /script
RUN /script/test_install_cni_plugins.sh

FROM busybox as build
ARG TAG
# Get buildx automatic platform vars: https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope
ARG TARGETPLATFORM
ARG TARGETOS
ARG TARGETARCH
ARG TARGETVARIANT
ARG BUILDPLATFORM
ARG BUILDOS
ARG BUILDARCH
ARG BUILDVARIANT
RUN echo TARGETPLATFORM=$TARGETPLATFORM
RUN echo TARGETOS=$TARGETOS
RUN echo TARGETARCH=$TARGETARCH
RUN echo TARGETVARIANT=$TARGETVARIANT
RUN echo BUILDPLATFORM=$BUILDPLATFORM
RUN echo BUILDOS=$BUILDOS
RUN echo BUILDARCH=$BUILDARCH
RUN echo BUILDVARIANT=$BUILDVARIANT
# Use buildx automatic platform vars
COPY release-$TAG/cni-plugins-$TARGETOS-$TARGETARCH-$TAG.tgz cni-plugins-$TARGETOS-$TARGETARCH-$TAG.tgz
COPY release-$TAG/cni-plugins-$TARGETOS-$TARGETARCH-$TAG.tgz.sha512 cni-plugins-$TARGETOS-$TARGETARCH-$TAG.tgz.sha512
RUN set -eux; \
sha512sum -c cni-plugins-$TARGETOS-$TARGETARCH-$TAG.tgz.sha512; \
mkdir -p /opt/cni/bin; \
tar -xvf cni-plugins-$TARGETOS-$TARGETARCH-$TAG.tgz -C /opt/cni/bin;

# This is the final, minimal container
FROM busybox as final
COPY docker-installer/install_cni_plugins.sh /script/install_cni_plugins.sh
COPY --from=build /opt/cni/bin /opt/cni/bin
ENV FORCE=
WORKDIR /opt/cni/bin
VOLUME /host/opt/cni/bin
CMD ["/script/install_cni_plugins.sh","/opt/cni/bin","/host/opt/cni/bin"]
9 changes: 9 additions & 0 deletions docker-installer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
This scripts are used in the docker image.

The docker image installs the plug-ins to /host/opt/cni/bin which should be bind-mounted to /opt/cni/bin on the host.

The installer-script keeps track of plug-ins it installs and ensures:
- that no existing plug-ins that have been installed or updated by someone else are overwriten
- that plug-ins installed by this script are updated if a new version of this image is used

A unit-test shell script for the installer script is part of the docker build process.
69 changes: 69 additions & 0 deletions docker-installer/install_cni_plugins.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/bin/sh

set -eu

if [ $# -ne 2 ]; then
echo "USAGE: $0 source-dir dest-dir"
echo "Env vars:"
echo " FORCE Overwrite existing binaries"
exit 1
fi

SRC=$1
DST=$2
FORCE=${FORCE:-}

install_cni_plugin() {
NAME=$1
MD5=$( md5sum $SRC/$NAME | awk '{ print $1 }' )
if [ -e $DST/$NAME ]; then
if [ ! -e $DST/$NAME.by_cni_installer_image ]; then
# The file already exists but there's no marker that
# it was installed by this installer -> keep untouched
if [ -z "$FORCE" ]; then
echo "* '$NAME' ignored (exists but not installed by me)"
return
fi
else
OTHER_MD5=$( md5sum $DST/$NAME | awk '{ print $1 }' )
INSTALLED_MD5=$( cat $DST/$NAME.by_cni_installer_image )

if [ "$OTHER_MD5" != "$INSTALLED_MD5" ]; then
# The file was previously installed by this installer
# but later changed -> keep untouched
if [ -z "$FORCE" ]; then
echo "* '$NAME' ignored (previously installed by me but changed by someone else)"
return
fi
fi

if [ "$OTHER_MD5" == "$MD5" ]; then
# The file was previously installed by this installer
# and is up-to-date
echo "* '$NAME' is up-to-date"
return
fi
fi

# The file was previously installed by this installer
# but needs an update
cp -a $SRC/$NAME $DST/.$NAME.new
mv $DST/.$NAME.new $DST/$NAME
echo $MD5 > $DST/$NAME.by_cni_installer_image
echo "* '$NAME' updated"

else
cp -a $SRC/$NAME $DST/.$NAME.new
mv $DST/.$NAME.new $DST/$NAME
echo $MD5 > $DST/$NAME.by_cni_installer_image
echo "* '$NAME' installed"
fi
}

echo "Installing CNI plug-ins to $DST"
echo

for FILE in $( find $SRC -maxdepth 1 -type f ); do
NAME=$( basename $FILE )
install_cni_plugin $NAME
done
Loading

0 comments on commit 04a99b6

Please sign in to comment.