diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b3d9fe0..71bfaa4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,7 +47,7 @@ jobs: - name: Build image run: | eval $(minikube -p minikube docker-env) && \ - make docker-build && \ + make docker-build CI=false && \ echo "docker_image=$(docker images --format '{{.Repository}}:{{.Tag}}' | head -n 1)" >> "$GITHUB_ENV" working-directory: ${{ github.workspace }}/${{ github.repository }} - name: Create pod diff --git a/Makefile b/Makefile index 5f0865e..740480d 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,15 @@ MAKEFLAGS += --warn-undefined-variables # App Code location CONFIG_APP_CODE += ./cmd/offloader +# Operating system arch +ifneq (, $(shell which go)) +ARCH ?= $(shell go version | awk '{print substr($$4,index($$4,"/")+1)}') +endif +# Target OS will always be linux. +OS := linux +# Fallback to amd64 if ARCH is still unset. +ARCH ?= amd64 + ## Docker Variables # Docker executable DOCKER := $(shell which docker) @@ -37,16 +46,30 @@ DOCKER_OPTS += --rm -u $$(id -u):$$(id -g) --platform "linux/amd64" # Registry to upload images DOCKER_REGISTRY ?= docker.io DOCKER_REGISTRY_REPO ?= mattermost/${APP_NAME}-daily +DOCKER_TAG ?= ${APP_NAME}:${APP_VERSION} # Registry credentials DOCKER_USER ?= user DOCKER_PASSWORD ?= password ## Docker Images -DOCKER_IMAGE_GO += "golang:${GO_VERSION}@sha256:337543447173c2238c78d4851456760dcc57c1dfa8c3bcd94cbee8b0f7b32ad0" +DOCKER_IMAGE_GO += "golang:${GO_VERSION}" DOCKER_IMAGE_GOLINT += "golangci/golangci-lint:v1.54.2@sha256:abe731fe6bb335a30eab303a41dd5c2b630bb174372a4da08e3d42eab5324127" -DOCKER_IMAGE_DOCKERLINT += "hadolint/hadolint:v2.9.2@sha256:d355bd7df747a0f124f3b5e7b21e9dafd0cb19732a276f901f0fdee243ec1f3b" +DOCKER_IMAGE_DOCKERLINT += "hadolint/hadolint:v2.12.0@sha256:9259e253a4e299b50c92006149dd3a171c7ea3c5bd36f060022b5d2c1ff0fbbe" DOCKER_IMAGE_COSIGN += "bitnami/cosign:1.8.0@sha256:8c2c61c546258fffff18b47bb82a65af6142007306b737129a7bd5429d53629a" DOCKER_IMAGE_GH_CLI += "ghcr.io/supportpal/github-gh-cli:2.31.0@sha256:71371e36e62bd24ddd42d9e4c720a7e9954cb599475e24d1407af7190e2a5685" +# When running locally we default to the current architecture. +DOCKER_BUILD_PLATFORMS := "${OS}/${ARCH}" +DOCKER_BUILD_OUTPUT_TYPE := "docker" +DOCKER_BUILDER := "multiarch" +DOCKER_BUILDER_MISSING := $(shell docker buildx inspect ${DOCKER_BUILDER} > /dev/null 2>&1; echo $$?) + +# When running on CI we want to use our official release targets. +ifeq ($(CI),true) +DOCKER_BUILD_PLATFORMS := "linux/amd64,linux/arm64" +DOCKER_BUILD_OUTPUT_TYPE := "registry" +DOCKER_TAG := ${DOCKER_REGISTRY}/${DOCKER_REGISTRY_REPO}:${APP_VERSION} +endif + ## Cosign Variables # The public key COSIGN_PUBLIC_KEY ?= akey @@ -66,7 +89,7 @@ GO_LDFLAGS += -X "github.com/mattermost/${APP_NAME}/service.bu GO_LDFLAGS += -X "github.com/mattermost/${APP_NAME}/service.buildDate=$(BUILD_DATE)" GO_LDFLAGS += -X "github.com/mattermost/${APP_NAME}/service.goVersion=$(GO_VERSION)" # Architectures to build for -GO_BUILD_PLATFORMS ?= linux-amd64 linux-arm64 darwin-amd64 darwin-arm64 freebsd-amd64 +GO_BUILD_PLATFORMS ?= linux-amd64 linux-arm64 GO_BUILD_PLATFORMS_ARTIFACTS = $(foreach cmd,$(addprefix go-build/,${APP_NAME}),$(addprefix $(cmd)-,$(GO_BUILD_PLATFORMS))) # Build options GO_BUILD_OPTS += -mod=readonly -trimpath @@ -128,7 +151,7 @@ build: go-build-docker ## to build release: build github-release ## to build and release artifacts .PHONY: package -package: docker-login docker-build docker-push ## to build, package and push the artifact to a container registry +package: docker-login docker-build ## to build, package and push the artifact to a container registry .PHONY: sign sign: docker-sign docker-verify ## to sign the artifact and perform verification @@ -141,26 +164,30 @@ test: go-test ## to test .PHONY: docker-build docker-build: ## to build the docker image - @$(INFO) Performing Docker build ${APP_NAME}:${APP_VERSION} - $(AT)$(DOCKER) build \ - --build-arg GO_IMAGE=${DOCKER_IMAGE_GO} \ + @$(INFO) Performing Docker build ${APP_NAME}:${APP_VERSION} for ${DOCKER_BUILD_PLATFORMS} +ifeq ($(DOCKER_BUILDER_MISSING),1) +ifeq ($(CI),true) + @$(INFO) Creating ${DOCKER_BUILDER} builder + $(AT)$(DOCKER) buildx create --name ${DOCKER_BUILDER} --use +endif +endif + $(AT)$(DOCKER) buildx build \ + --platform ${DOCKER_BUILD_PLATFORMS} \ + --output=type=${DOCKER_BUILD_OUTPUT_TYPE} \ + --build-arg GO_VERSION=${GO_VERSION} \ -f ${DOCKER_FILE} . \ - -t ${APP_NAME}:${APP_VERSION} || ${FAIL} - @$(OK) Performing Docker build ${APP_NAME}:${APP_VERSION} - -.PHONY: docker-push -docker-push: ## to push the docker image - @$(INFO) Pushing to registry... - $(AT)$(DOCKER) tag ${APP_NAME}:${APP_VERSION} $(DOCKER_REGISTRY)/${DOCKER_REGISTRY_REPO}:${APP_VERSION} || ${FAIL} - $(AT)$(DOCKER) push $(DOCKER_REGISTRY)/${DOCKER_REGISTRY_REPO}:${APP_VERSION} || ${FAIL} -# if we are on a latest semver APP_VERSION tag, also push latest + -t ${DOCKER_TAG} || ${FAIL} + @$(OK) Performing Docker build ${APP_NAME}:${APP_VERSION} for ${DOCKER_BUILD_PLATFORMS} ifneq ($(shell echo $(APP_VERSION) | egrep '^v([0-9]+\.){0,2}(\*|[0-9]+)'),) - ifeq ($(shell git tag -l --sort=v:refname | tail -n1),$(APP_VERSION)) - $(AT)$(DOCKER) tag ${APP_NAME}:${APP_VERSION} $(DOCKER_REGISTRY)/${DOCKER_REGISTRY_REPO}:latest || ${FAIL} - $(AT)$(DOCKER) push $(DOCKER_REGISTRY)/${DOCKER_REGISTRY_REPO}:latest || ${FAIL} - endif +ifeq ($(shell git tag -l --sort=v:refname | tail -n1),$(APP_VERSION)) + $(AT)$(DOCKER) buildx build \ + --platform ${DOCKER_BUILD_PLATFORMS} \ + --output=type=${DOCKER_BUILD_OUTPUT_TYPE} \ + --build-arg GO_VERSION=${GO_VERSION} \ + -f ${DOCKER_FILE} . \ + -t ${DOCKER_REGISTRY}/${DOCKER_REGISTRY_REPO}:latest || ${FAIL} +endif endif - @$(OK) Pushing to registry $(DOCKER_REGISTRY)/${DOCKER_REGISTRY_REPO}:${APP_VERSION} .PHONY: docker-sign docker-sign: ## to sign the docker image @@ -252,13 +279,8 @@ go-build: $(GO_BUILD_PLATFORMS_ARTIFACTS) ## to build binaries go-build/%: @$(INFO) go build $*... $(AT)target="$*"; \ - command="${APP_NAME}"; \ - platform_ext="$${target#$$command-*}"; \ - platform="$${platform_ext%.*}"; \ - export GOOS="$${platform%%-*}"; \ - export GOARCH="$${platform#*-}"; \ - echo export GOOS=$${GOOS}; \ - echo export GOARCH=$${GOARCH}; \ + GOOS=${OS} \ + GOARCH=${ARCH} \ CGO_ENABLED=0 \ $(GO) build ${GO_BUILD_OPTS} \ -ldflags '${GO_LDFLAGS}' \ diff --git a/build/Dockerfile b/build/Dockerfile index de774a0..4dd010b 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -1,22 +1,25 @@ -# This dockerfile is used to build Mattermost rtcd +# This dockerfile is used to build Mattermost calls-offloader # A multi stage build, with golang used as a builder # and gcr.io/distroless/static as runner -ARG GO_IMAGE=golang:1.21@sha256:b17c35044f4062d83c815434615997eed97697daae8745c6dd39dc3673b87efb -# hadolint ignore=DL3006 -FROM ${GO_IMAGE} as builder +ARG GO_VERSION +FROM --platform=$BUILDPLATFORM golang:${GO_VERSION} as builder -#GO_BUILD_PLATFORMS holds the platforms that we will build the docker image against -ARG GO_BUILD_PLATFORMS=linux-amd64 +ARG TARGETOS +ARG TARGETARCH +# GO_BUILD_PLATFORMS holds the platforms that we will build the docker image against +ARG GO_BUILD_PLATFORMS=${TARGETOS}-${TARGETARCH} # Setup directories structure and compile COPY . /src WORKDIR /src RUN make go-build -# Shrink final image since we only need the rtcd binary +# Shrink final image since we only need the offloader binary # and use distroless container image as runner for security -FROM gcr.io/distroless/static@sha256:d6fa9db9548b5772860fecddb11d84f9ebd7e0321c0cb3c02870402680cc315f as runner -COPY --from=builder /src/dist/calls-offloader-linux-amd64 /opt/calls-offloader/bin/calls-offloader +FROM --platform=$TARGETPLATFORM gcr.io/distroless/static@sha256:a43abc840a7168c833a8b3e4eae0f715f7532111c9227ba17f49586a63a73848 as runner +ARG TARGETOS +ARG TARGETARCH +COPY --from=builder /src/dist/calls-offloader-${TARGETOS}-${TARGETARCH} /opt/calls-offloader/bin/calls-offloader # Create and use unprivileged user to run the service COPY ./build/group ./build/passwd /etc/