Skip to content

Commit

Permalink
Adding multi arch container image generation for magpie and testrp (#…
Browse files Browse the repository at this point in the history
…7748)

# Description
- Removed `make docker-test-image-build` and `make
docker-test-image-push` because they were creating single arch builds.
- Added **testrp** and **magpie** as part of multi arch builds:
https://github.com/radius-project/radius/pull/7748/files#diff-267abdbaab3ee4a767a1905f07cb0033220b32d4a8c035502fe24dad37ee2e03R105-R106.
- Added **testrp** and **magpie** as part of multi arch builds and
pushes:
https://github.com/radius-project/radius/pull/7748/files#diff-e5017862a52d1de76ba232f290f53785637620580359895b37c593f181afc6c1R115-R119.
- Updated Dockerfiles for ucpd, applications-rp, and controller:
- Removed unnecessary `TARGETPLATFORM:-linux/amd64` because that was
throwing a warning stating that the TARGETPLATFORM is already
`linux/amd64` by default if not provided.
 - Updated Dockerfiles for testrp and magpiego:
- Made them more like the other Dockerfiles: ucpd, applications-rp, and
controller.
 - Updated dependencies for magpiego (because I was there).
 - Reformatted a few files.

## Type of change
Fixes: #7743

Signed-off-by: ytimocin <[email protected]>
  • Loading branch information
ytimocin authored Jul 31, 2024
1 parent c62434f commit 78b52b1
Show file tree
Hide file tree
Showing 11 changed files with 213 additions and 188 deletions.
39 changes: 18 additions & 21 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# 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
#
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
Expand All @@ -31,12 +31,12 @@ on:
- release/*

permissions:
id-token: write # Required for requesting the JWT
contents: write # Required for creating releases
issues: write # Required for creating comments
checks: write # Required for updating check runs
id-token: write # Required for requesting the JWT
contents: write # Required for creating releases
issues: write # Required for creating comments
checks: write # Required for updating check runs
pull-requests: write # Required for updating pull requests
packages: write # Required for uploading the package
packages: write # Required for uploading the package

concurrency:
# Cancel the previously triggered build for only PR build.
Expand All @@ -45,16 +45,16 @@ concurrency:

env:
# Go version to install
GOVER: '1.22.2'
GOVER: "1.22.2"

# gotestsum version - see: https://github.com/gotestyourself/gotestsum
GOTESTSUMVERSION: 1.10.0

# GitHub Actor for pushing images to GHCR
GHCR_ACTOR: rad-ci-bot

# Container registry url for GitHub container registry.
CONTAINER_REGISTRY: 'ghcr.io/radius-project'
CONTAINER_REGISTRY: "ghcr.io/radius-project"

# Local file path to the release binaries.
RELEASE_PATH: ./release
Expand Down Expand Up @@ -105,8 +105,8 @@ jobs:
- name: Run make test (unit tests)
if: matrix.target_arch == 'amd64' && matrix.target_os == 'linux'
env:
GOTESTSUM_OPTS: '--junitfile ./dist/unit_test/results.xml'
GOTEST_OPTS: '-race -coverprofile ./dist/unit_test/ut_coverage.out'
GOTESTSUM_OPTS: "--junitfile ./dist/unit_test/results.xml"
GOTEST_OPTS: "-race -coverprofile ./dist/unit_test/ut_coverage.out"
run: |
mkdir -p ./dist/unit_test
go install gotest.tools/gotestsum@v${{ env.GOTESTSUMVERSION }}
Expand All @@ -125,9 +125,9 @@ jobs:
# Always is required here to make sure this target runs even when tests fail.
if: always() && matrix.target_arch == 'amd64' && matrix.target_os == 'linux'
with:
test_group_name: 'Unit Tests'
artifact_name: 'unit_test_results'
result_directory: 'dist/unit_test/'
test_group_name: "Unit Tests"
artifact_name: "unit_test_results"
result_directory: "dist/unit_test/"
- name: Copy cli binaries to release (unix-like)
if: matrix.target_os != 'windows'
run: |
Expand Down Expand Up @@ -190,23 +190,20 @@ jobs:
platforms: linux/amd64,linux/arm64,linux/arm/v7
- name: Push container images (latest)
run: |
make docker-test-image-build && make docker-test-image-push
make docker-multi-arch-push
if: (github.ref == 'refs/heads/main') # push image to latest on merge to main
env:
DOCKER_REGISTRY: ${{ env.CONTAINER_REGISTRY }}
DOCKER_TAG_VERSION: latest
- name: Build container images (PR) # Don't push on PR, agent will not have permission.
run: |
make docker-test-image-build
make docker-multi-arch-build
if: github.event_name == 'pull_request'
env:
DOCKER_REGISTRY: ${{ env.CONTAINER_REGISTRY }}
DOCKER_TAG_VERSION: ${{ env.REL_VERSION }} # includes PR number
- name: Push container images (release)
run: |
make docker-test-image-build && make docker-test-image-push
make docker-multi-arch-push
if: startsWith(github.ref, 'refs/tags/v') # push image on tag
env:
Expand All @@ -215,7 +212,7 @@ jobs:

build-and-push-helm-chart:
name: Helm chart build
needs: ['build-and-push-images']
needs: ["build-and-push-images"]
runs-on: ubuntu-latest
# Don't push on PR, agent will not have permission.
if: github.repository == 'radius-project/radius' && ((startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main'))
Expand All @@ -226,14 +223,14 @@ jobs:
OCI_REGISTRY: ghcr.io
# We only push the chart on pushes to main or to a tag. The versioning logic will select the right
# version for us.
OCI_REPOSITORY: 'radius-project/helm-chart'
OCI_REPOSITORY: "radius-project/helm-chart"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install helm
uses: azure/setup-helm@v4
with:
version: 'v3.11.1'
version: "v3.11.1"
- name: Parse release version and set environment variables
run: python ./.github/scripts/get_release_version.py
- name: Run Helm linter
Expand Down Expand Up @@ -264,7 +261,7 @@ jobs:
publish-release:
name: Publish GitHub Release
needs: ['build-and-push-cli']
needs: ["build-and-push-cli"]
runs-on: ubuntu-latest
if: github.repository == 'radius-project/radius' && startsWith(github.ref, 'refs/tags/v')
env:
Expand Down
51 changes: 43 additions & 8 deletions build/build.mk
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,26 @@ GOOS ?= $(shell go env GOOS)
GOARCH ?= $(shell go env GOARCH)
GOPATH := $(shell go env GOPATH)

# Set GOBIN environment variable.
# If it is not set, use GOPATH/bin.
ifeq (,$(shell go env GOBIN))
GOBIN=$(shell go env GOPATH)/bin
else
GOBIN=$(shell go env GOBIN)
endif

# Check Operating System and set binary extension,
# and golangci-lint binary name.
ifeq ($(GOOS),windows)
BINARY_EXT = .exe
GOLANGCI_LINT:=golangci-lint.exe
else
GOLANGCI_LINT:=golangci-lint
endif

# Check if DEBUG is set to 1 or not.
# If DEBUG is set to 1, then build debug binaries.
# If DEBUG is not set, then build release binaries.
ifeq ($(origin DEBUG), undefined)
BUILDTYPE_DIR:=release
GCFLAGS:=""
Expand All @@ -45,7 +52,10 @@ else
GCFLAGS:="all=-N -l"
endif

# Linker flags: https://cmake.org/cmake/help/latest/envvar/LDFLAGS.html.
LDFLAGS := "-s -w -X $(BASE_PACKAGE_NAME)/pkg/version.channel=$(REL_CHANNEL) -X $(BASE_PACKAGE_NAME)/pkg/version.release=$(REL_VERSION) -X $(BASE_PACKAGE_NAME)/pkg/version.commit=$(GIT_COMMIT) -X $(BASE_PACKAGE_NAME)/pkg/version.version=$(GIT_VERSION) -X $(BASE_PACKAGE_NAME)/pkg/version.chartVersion=$(CHART_VERSION)"

# Combination of flags into GOARGS.
GOARGS := -v -gcflags $(GCFLAGS) -ldflags $(LDFLAGS)

export GO111MODULE ?= on
Expand Down Expand Up @@ -82,28 +92,53 @@ endef
# $(2): the ARCH
# $(3): the binary name for the target
# $(4): the binary main directory
#
# Note: testrp and magpiego have their own modules.
# That is why we need to change the directory to the binary main directory as we do on line 101.
# Otherwise we get the following error:
# `main module (github.com/radius-project/radius) does not contain package github.com/radius-project/radius/test/testrp`
define generatePlatformBuildTarget
.PHONY: build-$(3)-$(1)-$(2)
build-$(3)-$(1)-$(2):
$(eval BINS_OUT_DIR_$(1)_$(2) := $(OUT_DIR)/$(1)_$(2)/$(BUILDTYPE_DIR))
@echo "$(ARROW) Building $(3) on $(1)/$(2) to $(BINS_OUT_DIR_$(1)_$(2))/$(3)$(BINARY_EXT)"
GOOS=$(1) GOARCH=$(2) go build \
cd $(4) && GOOS=$(1) GOARCH=$(2) go build \
-v \
-gcflags $(GCFLAGS) \
-ldflags=$(LDFLAGS) \
-o $(BINS_OUT_DIR_$(1)_$(2))/$(3)$(BINARY_EXT) \
$(4)/
-o $(CURDIR)/$(BINS_OUT_DIR_$(1)_$(2))/$(3)$(BINARY_EXT)
endef

# defines a target for each binary
GOOSES := darwin linux windows
GOARCHES := amd64 arm arm64
BINARIES := docgen rad applications-rp ucpd controller
$(foreach ITEM,$(BINARIES),$(eval $(call generateBuildTarget,$(ITEM),./cmd/$(ITEM))))
$(foreach ARCH,$(GOARCHES),$(foreach OS,$(GOOSES),$(foreach ITEM,$(BINARIES),$(eval $(call generatePlatformBuildTarget,$(OS),$(ARCH),$(ITEM),./cmd/$(ITEM))))))

# list of 'outputs' to build for all binaries
BINARY_TARGETS:=$(foreach ITEM,$(BINARIES),build-$(ITEM))
# List of binaries to build.
# Format: binaryName:binaryMainDirectory
# Example: docgen:./cmd/docgen
BINARIES := docgen:./cmd/docgen \
rad:./cmd/rad \
applications-rp:./cmd/applications-rp \
ucpd:./cmd/ucpd \
controller:./cmd/controller \
testrp:./test/testrp \
magpiego:./test/magpiego

# This function parses binary name and entrypoint from an item in the BINARIES list.
define parseBinary
$(eval NAME := $(shell echo $(1) | cut -d: -f1))
$(eval ENTRYPOINT := $(shell echo $(1) | cut -d: -f2))
endef

# Generate build targets for each binary.
$(foreach ITEM,$(BINARIES),$(eval $(call parseBinary,$(ITEM)) $(call generateBuildTarget,$(NAME),$(ENTRYPOINT))))

# Generate platform build targets for each binary and each platform.
# This will generate a target for each combination of OS and ARCH for each item in the BINARIES list.
$(foreach ARCH,$(GOARCHES),$(foreach OS,$(GOOSES),$(foreach ITEM,$(BINARIES),$(eval $(call parseBinary,$(ITEM)) $(call generatePlatformBuildTarget,$(OS),$(ARCH),$(NAME),$(ENTRYPOINT))))))

# Generate a `build` target for each item in the BINARIES list.
BINARY_TARGETS := $(foreach ITEM,$(BINARIES),$(eval $(call parseBinary,$(ITEM))) build-$(NAME))

.PHONY: build-binaries
build-binaries: $(BINARY_TARGETS) ## Builds all go binaries.
Expand Down
53 changes: 26 additions & 27 deletions build/docker.mk
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ IMAGE_SRC?=https://github.com/radius-project/radius
# Generate a target for each image we define
# Params:
# $(1): the image name for the target
# $(2): the Dockerfile path
# $(2): the context directory
# $(3): the Dockerfile path
define generateDockerTargets
ifeq ($(strip $(4)),go)
.PHONY: docker-build-$(1)
Expand Down Expand Up @@ -97,50 +98,48 @@ configure-buildx:
docker buildx inspect --builder radius-builder --bootstrap; \
fi

# defines a target for each image
DOCKER_IMAGES := ucpd applications-rp controller

$(foreach IMAGE,$(DOCKER_IMAGES),$(eval $(call generateDockerTargets,$(IMAGE),.,./deploy/images/$(IMAGE)/Dockerfile, go)))

# multi arch container image targets for each binaries
$(foreach IMAGE,$(DOCKER_IMAGES),$(eval $(call generateDockerMultiArches,$(IMAGE),.,./deploy/images/$(IMAGE)/Dockerfile)))
# Define a target for each image with name and Dockerfile location
APPS_MAP := ucpd:./deploy/images/ucpd \
applications-rp:./deploy/images/applications-rp \
controller:./deploy/images/controller \
testrp:./test/testrp \
magpiego:./test/magpiego

# Function to extract the name and the directory of the Dockerfile from the app string
define parseApp
$(eval NAME := $(shell echo $(1) | cut -d: -f1))
$(eval DIR := $(shell echo $(1) | cut -d: -f2))
endef

# magpie comes from our test directory.
$(eval $(call generateDockerTargets,magpiego,./test/magpiego/,./test/magpiego/Dockerfile))
# This command will dynamically generate the targets for each image in the APPS_MAP list.
$(foreach APP,$(APPS_MAP),$(eval $(call parseApp,$(APP)) $(call generateDockerTargets,$(NAME),.,$(DIR)/Dockerfile,go)))

# testrp comes from our test directory.
$(eval $(call generateDockerTargets,testrp,./test/testrp/,./test/testrp/Dockerfile))
# This command will dynamically generate the multi-arch targets for each image in the APPS_MAP list.
$(foreach APP,$(APPS_MAP),$(eval $(call parseApp,$(APP)) $(call generateDockerMultiArches,$(NAME),.,$(DIR)/Dockerfile)))

# list of 'outputs' to build all images
DOCKER_BUILD_TARGETS:=$(foreach IMAGE,$(DOCKER_IMAGES),docker-build-$(IMAGE))
DOCKER_BUILD_TARGETS := $(foreach APP,$(APPS_MAP),$(eval $(call parseApp,$(APP))) docker-build-$(NAME))

# list of 'outputs' to push all images
DOCKER_PUSH_TARGETS:=$(foreach IMAGE,$(DOCKER_IMAGES),docker-push-$(IMAGE))
DOCKER_PUSH_TARGETS := $(foreach APP,$(APPS_MAP),$(eval $(call parseApp,$(APP))) docker-push-$(NAME))

# list of 'outputs' to build all multi arch images
DOCKER_BUILD_MULTI_TARGETS:=$(foreach IMAGE,$(DOCKER_IMAGES),docker-multi-arch-build-$(IMAGE))
DOCKER_BUILD_MULTI_TARGETS := $(foreach APP,$(APPS_MAP),$(eval $(call parseApp,$(APP))) docker-multi-arch-build-$(NAME))

# list of 'outputs' to push all multi arch images
DOCKER_PUSH_MULTI_TARGETS:=$(foreach IMAGE,$(DOCKER_IMAGES),docker-multi-arch-push-$(IMAGE))

# targets to build test images
.PHONY: docker-test-image-build
docker-test-image-build: docker-build-magpiego docker-build-testrp ## Builds all test Docker images.

.PHONY: docker-test-image-push
docker-test-image-push: docker-push-magpiego docker-push-testrp ## Pushes all test Docker images.
DOCKER_PUSH_MULTI_TARGETS := $(foreach APP,$(APPS_MAP),$(eval $(call parseApp,$(APP))) docker-multi-arch-push-$(NAME))

# targets to build development images
.PHONY: docker-build
docker-build: $(DOCKER_BUILD_TARGETS) docker-test-image-build ## Builds all Docker images.
docker-build: $(DOCKER_BUILD_TARGETS) ## Builds all Docker images.

.PHONY: docker-push
docker-push: $(DOCKER_PUSH_TARGETS) docker-test-image-push ## Pushes all Docker images (without building).
docker-push: $(DOCKER_PUSH_TARGETS) ## Pushes all Docker images (without building).

# targets to build and push multi arch images. If you run this target in your machine,
# ensure you have qemu and buildx installed by running make configure-buildx.
.PHONY: docker-multi-arch-build
docker-multi-arch-build: $(DOCKER_BUILD_MULTI_TARGETS) ## Builds all non-test docker images for multiple architectures.
docker-multi-arch-build: $(DOCKER_BUILD_MULTI_TARGETS) ## Builds all docker images for multiple architectures.

.PHONY: docker-multi-arch-push
docker-multi-arch-push: $(DOCKER_PUSH_MULTI_TARGETS) ## Pushes all non-test docker images for multiple architectures after building.
docker-multi-arch-push: $(DOCKER_PUSH_MULTI_TARGETS) ## Pushes all docker images for multiple architectures after building.
17 changes: 10 additions & 7 deletions deploy/images/applications-rp/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
# Note: Using Alpine image to enable Git installation for Terraform module downloads.
# Use Alpine image to enable Git installation for Terraform module downloads.
# Switch to distroless when Terraform execution is moved to a separate container.
FROM --platform=${TARGETPLATFORM:-linux/amd64} alpine:3.18
FROM alpine:3.20

ARG TARGETPLATFORM
ARG TARGETARCH

# Install ca-certificates and Git (required for Terraform module downloads)
RUN apk --no-cache add ca-certificates git

# Create non-root user
RUN addgroup -g 65532 rpuser && \
# Create non-root user in a single RUN command to minimize layers
RUN apk --no-cache add ca-certificates git && \
addgroup -g 65532 rpuser && \
adduser -u 65532 -G rpuser -s /bin/sh -D rpuser

WORKDIR /

# Copy the application binary
COPY ./linux_${TARGETARCH:-amd64}/release/applications-rp /

# Set the user to non-root
USER rpuser

# Expose the application port
EXPOSE 8080

# Set the entrypoint to the application binary
ENTRYPOINT ["/applications-rp"]
11 changes: 8 additions & 3 deletions deploy/images/controller/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
# Note: distroless already includes ca-certificates
FROM --platform=${TARGETPLATFORM:-linux/amd64} gcr.io/distroless/static:nonroot
# Use distroless image which already includes ca-certificates
FROM gcr.io/distroless/static:nonroot

ARG TARGETPLATFORM
# Argument for target architecture
ARG TARGETARCH

# Set the working directory
WORKDIR /

# Copy the application binary for the specified architecture
COPY ./linux_${TARGETARCH:-amd64}/release/controller /

# Set the user to non-root (65532:65532 is the default non-root user in distroless)
USER 65532:65532

# Set the entrypoint to the application binary
ENTRYPOINT ["/controller"]
11 changes: 8 additions & 3 deletions deploy/images/ucpd/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
# Note: distroless already includes ca-certificates
FROM --platform=${TARGETPLATFORM:-linux/amd64} gcr.io/distroless/static:nonroot
# Use distroless image which already includes ca-certificates
FROM gcr.io/distroless/static:nonroot

ARG TARGETPLATFORM
# Argument for target architecture
ARG TARGETARCH

# Set the working directory
WORKDIR /

# Copy the application binary for the specified architecture
COPY ./linux_${TARGETARCH:-amd64}/release/ucpd /

# Set the user to non-root (65532:65532 is the default non-root user in distroless)
USER 65532:65532

# Set the entrypoint to the application binary
ENTRYPOINT ["/ucpd"]
Loading

0 comments on commit 78b52b1

Please sign in to comment.