introduce docker container production (#660)

Introduces the production of docker containers as a CI step.
Currently only provides a rolling-release version that builds
on every push to main.  Images are deployed to ghcr.io.

The PR includes two variations on building the images.  We'll
likely only want to stick with one or the other.
This commit is contained in:
Keepers 2022-09-01 09:06:57 -06:00 committed by GitHub
parent 7d5e72925a
commit 127b6d061a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 245 additions and 36 deletions

3
.dockerignore Normal file
View File

@ -0,0 +1,3 @@
.git
.gitignore
.dockerignore

114
.github/workflows/container.yml vendored Normal file
View File

@ -0,0 +1,114 @@
name: Publish Docker Container Images
on:
push:
branches: [main]
env:
REGISTRY: ghcr.io
REPO_NAME: ${{ github.repository }}
permissions:
contents: read
packages: write
jobs:
# ------------------------------------------------------------------------------------------
# To be decided: Script-Deploy or Dockerfile-Deploy:
# Script:
# + Separates the golang build from the corso build.
# - Haven't figured out multiplatform builds yet.
# - Doesn't cache, always takes 10-15 minutes per build in the matrix.
# Dockerfile:
# + Once cached, takes <1m to deploy.
# + Multiplatform.
# + Extended features (such as tagging) can be handled by more github actions.
# - When not cached, can take >2 hours to build (at least initially).
# - Currently includes the complete golang:1.18 image.
# ------------------------------------------------------------------------------------------
Script-Deploy:
runs-on: ubuntu-latest
defaults:
run:
working-directory: build
strategy:
matrix:
BUILD_ARCH: [amd64, arm64]
BUILD_OS: [linux]
env:
IMAGE_PREFIX: ghcr.io
VERSION_SUFFIX: rolling
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Run build script
run: >
./build-container.sh
--arch ${{ matrix.BUILD_ARCH }}
--prefix ${{ env.IMAGE_PREFIX }}
--suffix ${{ env.VERSION_SUFFIX }}
# login step boilerplate from:
# https://docs.github.com/en/packages/managing-github-packages-using-github-actions-workflows/publishing-and-installing-a-package-with-github-actions#upgrading-a-workflow-that-accesses-ghcrio
- name: Log in to registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin
- name: Push image
env:
IMAGE_ID: ${{ env.IMAGE_PREFIX }}/alcionai/corso
VERSION: ${{ matrix.BUILD_OS }}-${{ matrix.BUILD_ARCH }}-${{ env.VERSION_SUFFIX }}
run: |
docker images -a
docker push ${{ env.IMAGE_ID }}:${{ env.VERSION }}
Dockerfile-Deploy:
runs-on: ubuntu-latest
env:
TARGETOS: linux
TARGETARCH: arm64
steps:
- name: Checkout repository
uses: actions/checkout@v3
# apparently everyone uses this step
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
# setup Docker buld action
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v2
# In case we want to switch to dockerhub
# - name: Login to DockerHub
# uses: docker/login-action@v2
# with:
# username: ${{ secrets.DOCKERHUB_USERNAME }}
# password: ${{ secrets.DOCKERHUB_TOKEN }}
# retrieve credentials for ghcr.io
- name: Login to Github Packages
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# build the image
- name: Build image and push to Docker Hub and GitHub Container Registry
uses: docker/build-push-action@v3
with:
context: .
file: ./docker/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: ghcr.io/alcionai/corso:rolling
# use the github cache
cache-from: type=gha
cache-to: type=gha,mode=max
# check the image digest
- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}

View File

@ -22,7 +22,16 @@ TODO - Link to the appropriate page in the published docs.
./build/build-container.sh ./build/build-container.sh
``` ```
## Contribution Guidelines # Containers
Corso images are hosted on [ghrc.io](https://github.com/alcionai/corso/pkgs/container/corso).
Rolling release
```sh
docker pull ghcr.io/alcionai/corso:{SHA} --platform linux/arm64
```
# Contribution Guidelines
TODO TODO

15
build/Dockerfile Normal file
View File

@ -0,0 +1,15 @@
# syntax=docker/dockerfile:1
# This dockerfile is configured to be run by the /corso/build/build-container.sh
# script. Using docker to build this file directly will fail.
FROM gcr.io/distroless/base-debian10
# FROM gcr.io/distroless/base:debug
WORKDIR /
COPY ./bin/corso ./
USER nonroot:nonroot
ENTRYPOINT ["/corso"]

View File

@ -10,12 +10,15 @@ usage() {
echo "-----" echo "-----"
echo "Flags" echo "Flags"
echo " -h|--help Help" echo " -h|--help Help"
echo " |--arm Set the architecture to arm64 (default: amd64)" echo " -a|--arch Set the architecture to the specified value (default: amd64)"
echo " -p|--prefix Prefixes the image name."
echo " -s|--suffix Suffixes the version."
echo " " echo " "
echo "-----" echo "-----"
echo "Example Usage:" echo "Example Usage:"
echo " ./build/build-container.sh" echo " ./build/build-container.sh"
echo " ./build/build-container.sh --arm" echo " ./build/build-container.sh --arch arm64"
echo " ./build/build-container.sh --arch arm64 --prefix ghcr.io --suffix nightly"
echo " " echo " "
exit 0 exit 0
} }
@ -25,6 +28,8 @@ PROJECT_ROOT=$(dirname ${SCRIPT_ROOT})
OS=linux OS=linux
ARCH=amd64 ARCH=amd64
IMAGE_NAME_PREFIX=
IMAGE_TAG_SUFFIX=
while [ "$#" -gt 0 ] while [ "$#" -gt 0 ]
do do
@ -33,31 +38,52 @@ do
usage usage
exit 0 exit 0
;; ;;
--arm) -a|--arch)
ARCH=arm64 ARCH=$2
shift
;;
-p|--prefix)
IMAGE_NAME_PREFIX=$2
shift
;;
-s|--suffix)
IMAGE_TAG_SUFFIX=$2
shift
;; ;;
-*) -*)
echo "Invalid option '$1'. Use -h|--help to see the valid options" >&2 echo "Invalid flag '$1'. Use -h|--help to see the valid options" >&2
return 1 return 1
;; ;;
*) *)
echo "Invalid option '$1'. Use -h|--help to see the valid options" >&2 echo "Invalid arg '$1'. Use -h|--help to see the valid options" >&2
return 1 return 1
;; ;;
esac esac
shift shift
done done
IMAGE_TAG=${OS}-${ARCH}-$(git describe --tags --always --dirty) IMAGE_TAG=${OS}-${ARCH}
if [ ! -z "${IMAGE_TAG_SUFFIX}" ]; then
IMAGE_TAG=${IMAGE_TAG}-${IMAGE_TAG_SUFFIX}
fi
IMAGE_NAME=alcionai/corso:${IMAGE_TAG} IMAGE_NAME=alcionai/corso:${IMAGE_TAG}
if [ ! -z "${IMAGE_NAME_PREFIX}" ]; then
IMAGE_NAME=${IMAGE_NAME_PREFIX}/${IMAGE_NAME}
fi
${SCRIPT_ROOT}/build.sh --arch ${ARCH} ${SCRIPT_ROOT}/build.sh --arch ${ARCH}
echo "building container" echo "-----"
echo "building corso container ${IMAGE_NAME}"
echo "-----"
set -x set -x
docker buildx build --tag ${IMAGE_NAME} \ docker buildx build --tag ${IMAGE_NAME} \
--platform ${OS}/${ARCH} \ --platform ${OS}/${ARCH} \
--file ${PROJECT_ROOT}/docker/Dockerfile \ --file ${PROJECT_ROOT}/build/Dockerfile \
${PROJECT_ROOT} ${PROJECT_ROOT}
set +x set +x
echo "container built successfully ${IMAGE_NAME}"
echo "-----"
echo "container built successfully"

View File

@ -4,12 +4,19 @@ set -e
SCRIPT_ROOT=$(dirname $(readlink -f $0)) SCRIPT_ROOT=$(dirname $(readlink -f $0))
PROJECT_ROOT=$(dirname ${SCRIPT_ROOT}) PROJECT_ROOT=$(dirname ${SCRIPT_ROOT})
SRC_DIR=${PROJECT_ROOT}
CORSO_BUILD_CONTAINER=/go/src/github.com/alcionai/corso
CORSO_BUILD_CONTAINER_SRC=${CORSO_BUILD_CONTAINER}/src
CORSO_BUILD_PKG_MOD=/go/pkg/mod
CORSO_BUILD_TMP=/tmp/.corsobuild
CORSO_BUILD_TMP_CACHE=${CORSO_BUILD_TMP}/cache
CORSO_BUILD_TMP_MOD=${CORSO_BUILD_TMP}/mod
CORSO_CACHE=${CORSO_BUILD_TMP_CACHE}
CORSO_MOD_CACHE=${CORSO_BUILD_PKG_MOD}/cache
CORSO_BUILD_ARGS='' CORSO_BUILD_ARGS=''
CORSO_BUILD_CONTAINER_DIR=/go/src/github.com/alcionai/corso GOVER=1.18
CORSO_BUILD_CONTAINER_SRC_DIR=${CORSO_BUILD_CONTAINER_DIR}/src
GOOS=linux GOOS=linux
GOARCH=amd64 GOARCH=amd64
@ -25,26 +32,31 @@ do
done done
# temporary directory for caching go build # temporary directory for caching go build
mkdir -p /tmp/.corsobuild/cache mkdir -p ${CORSO_BUILD_TMP_CACHE}
# temporary directory for caching go modules (needed for fast cross-platform build) # temporary directory for caching go modules (needed for fast cross-platform build)
mkdir -p /tmp/.corsobuild/mod mkdir -p ${CORSO_BUILD_TMP_MOD}
echo "-----"
echo "building corso binary for ${GOOS}-${GOARCH}"
echo "-----"
echo "building corso"
set -x set -x
docker run --rm --mount type=bind,src=${SRC_DIR},dst=${CORSO_BUILD_CONTAINER_DIR} \ docker run --rm \
--mount type=bind,src=/tmp/.corsobuild/cache,dst=/tmp/.corsobuild/cache \ --mount type=bind,src=${PROJECT_ROOT},dst=${CORSO_BUILD_CONTAINER} \
--mount type=bind,src=/tmp/.corsobuild/mod,dst=/go/pkg/mod \ --mount type=bind,src=${CORSO_BUILD_TMP_CACHE},dst=${CORSO_BUILD_TMP_CACHE} \
--workdir ${CORSO_BUILD_CONTAINER_SRC_DIR} \ --mount type=bind,src=${CORSO_BUILD_TMP_MOD},dst=${CORSO_BUILD_PKG_MOD} \
--env GOCACHE=/tmp/.corsobuild/cache \ --workdir ${CORSO_BUILD_CONTAINER_SRC} \
--env GOOS=${GOOS} \ --env GOMODCACHE=${CORSO_MOD_CACHE} \
--env GOARCH=${GOARCH} \ --env GOCACHE=${CORSO_CACHE} \
--env GOCACHE=/tmp/.corsobuild/cache \ --env GOOS=${GOOS} \
--entrypoint /usr/local/go/bin/go \ --env GOARCH=${GOARCH} \
golang:1.18 \ --entrypoint /usr/local/go/bin/go \
build ${CORSO_BUILD_ARGS} golang:${GOVER} \
build ${CORSO_BUILD_ARGS}
mkdir -p ${PROJECT_ROOT}/bin
set +x set +x
echo "creating binary image in bin/corso" mkdir -p ${PROJECT_ROOT}/bin
mv ${PROJECT_ROOT}/src/corso ${PROJECT_ROOT}/bin/corso mv ${PROJECT_ROOT}/src/corso ${PROJECT_ROOT}/bin/corso
echo "-----"
echo "created binary image in ${PROJECT_ROOT}/bin/corso"

View File

@ -1,11 +1,29 @@
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
# This dockerfile is able to make a quick, local image of corso.
# It is not used for deployments.
## Build
FROM golang:1.18 AS base
WORKDIR /src
COPY ./src/go.mod .
COPY ./src/go.sum .
RUN go mod download
COPY ./src .
FROM base AS build
ARG TARGETOS
ARG TARGETARCH
RUN GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o /corso .
## Deploy
FROM gcr.io/distroless/base-debian10 FROM gcr.io/distroless/base-debian10
WORKDIR / COPY --from=build /corso /
COPY ./bin/corso ./
USER nonroot:nonroot USER nonroot:nonroot
ENTRYPOINT ["/corso"] ENTRYPOINT ["/corso"]

12
docker/docker-bake.hcl Normal file
View File

@ -0,0 +1,12 @@
// docker-bake.hcl
target "docker-metadata-action" {}
target "build" {
inherits = ["docker-metadata-action"]
context = "./"
dockerfile = "Dockerfile"
platforms = [
"linux/amd64",
"linux/arm64",
]
}