From 9d84b3d416388f9a538d96f61c92f72d1487411b Mon Sep 17 00:00:00 2001 From: Jun Gong Date: Tue, 15 Sep 2020 14:43:43 +0800 Subject: [PATCH] Support build multi arch image, e.g. arm64 --- Makefile | 11 ++++ build/docker/Dockerfile_arch | 36 +++++++++++ build/lib/common.mk | 64 +++++++++++++++++++ build/lib/create-manifest.sh | 53 ++++++++++++++++ build/lib/image.mk | 119 +++++++++++++++++++++++++++++++++++ build/lib/install-buildx.sh | 32 ++++++++++ 6 files changed, 315 insertions(+) create mode 100644 build/docker/Dockerfile_arch create mode 100644 build/lib/common.mk create mode 100755 build/lib/create-manifest.sh create mode 100644 build/lib/image.mk create mode 100755 build/lib/install-buildx.sh diff --git a/Makefile b/Makefile index 4060746..c1372e3 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,12 @@ clean: build: hack/build.sh +# ============================================================================== +# Includes + +include build/lib/common.mk +include build/lib/image.mk + .PHONY: verify verify: hack/verify-all.sh @@ -24,4 +30,9 @@ format: image: hack/build-image.sh +## release.multiarch: Build docker images for multiple platforms and push manifest lists to registry. +.PHONY: release.multiarch +release.multiarch: + @$(MAKE) image.manifest.push.multiarch BINS="cron-hpa-controller" + # vim: set ts=2 sw=2 tw=0 noet : diff --git a/build/docker/Dockerfile_arch b/build/docker/Dockerfile_arch new file mode 100644 index 0000000..87f6621 --- /dev/null +++ b/build/docker/Dockerfile_arch @@ -0,0 +1,36 @@ +# Tencent is pleased to support the open source community by making TKEStack +# available. +# +# Copyright (C) 2012-2019 Tencent. All Rights Reserved. +# +# 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://opensource.org/licenses/Apache-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 OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +FROM golang:1.14.4 AS builder +ARG TARGETPLATFORM +RUN echo "building for ${TARGETPLATFORM}" +ARG WORKDIR="/go/src/tkestack.io/cron-hpa/" +RUN mkdir -p ${WORKDIR} +WORKDIR ${WORKDIR} + +COPY . ${WORKDIR} +RUN make build + + +FROM alpine:3.10 + +RUN mkdir /etc/certs +ADD build/docker/ca.crt /etc/certs +ADD build/docker/tls.crt /etc/certs +ADD build/docker/tls.key /etc/certs +COPY --from=builder /go/src/tkestack.io/cron-hpa/bin/cron-hpa-controller /usr/local/bin + +ENTRYPOINT ["/usr/local/bin/cron-hpa-controller"] \ No newline at end of file diff --git a/build/lib/common.mk b/build/lib/common.mk new file mode 100644 index 0000000..0ecec5b --- /dev/null +++ b/build/lib/common.mk @@ -0,0 +1,64 @@ +# Tencent is pleased to support the open source community by making TKEStack +# available. +# +# Copyright (C) 2012-2019 Tencent. All Rights Reserved. +# +# 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://opensource.org/licenses/Apache-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 OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +SHELL := /bin/bash + +# include the common make file +COMMON_SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST))) + +ifeq ($(origin ROOT_DIR),undefined) +ROOT_DIR := $(abspath $(shell cd $(COMMON_SELF_DIR)/../.. && pwd -P)) +endif +ifeq ($(origin OUTPUT_DIR),undefined) +OUTPUT_DIR := $(ROOT_DIR)/_output +$(shell mkdir -p $(OUTPUT_DIR)) +endif +ifeq ($(origin TOOLS_DIR),undefined) +TOOLS_DIR := $(OUTPUT_DIR)/tools +$(shell mkdir -p $(TOOLS_DIR)) +endif +ifeq ($(origin TMP_DIR),undefined) +TMP_DIR := $(OUTPUT_DIR)/tmp +$(shell mkdir -p $(TMP_DIR)) +endif + +# set the version number. you should not need to do this +# for the majority of scenarios. +ifeq ($(origin VERSION), undefined) +VERSION := $(shell git describe --dirty --always --tags | sed 's/-/./g') +endif +GIT_COMMIT:=$(shell git log --first-parent -1 --oneline | awk '{print $$1}') + +PLATFORMS ?= linux_amd64 linux_arm64 + +# Set a specific PLATFORM +# Target OS must be linux +ifeq ($(origin PLATFORM), undefined) + ifeq ($(origin GOOS), undefined) + GOOS := linux + endif + ifeq ($(origin GOARCH), undefined) + GOARCH := $(shell go env GOARCH) + endif + PLATFORM := $(GOOS)_$(GOARCH) +else + GOOS := $(word 1, $(subst _, ,$(PLATFORM))) + GOARCH := $(word 2, $(subst _, ,$(PLATFORM))) +endif + +COMMA := , +SPACE := +SPACE += diff --git a/build/lib/create-manifest.sh b/build/lib/create-manifest.sh new file mode 100755 index 0000000..726c70d --- /dev/null +++ b/build/lib/create-manifest.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash + +# Tencent is pleased to support the open source community by making TKEStack +# available. +# +# Copyright (C) 2012-2019 Tencent. All Rights Reserved. +# +# 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://opensource.org/licenses/Apache-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 OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +REGISTRY_PREFIX=${REGISTRY_PREFIX:-"tkestack"} +PLATFORMS=${PLATFORMS:-"linux_amd64 linux_arm64"} + +if [ -z ${IMAGE} ]; then + echo "Please provide IMAGE." + exit 1 +fi + +if [ -z ${VERSION} ]; then + echo "Please provide VERSION." + exit 1 +fi + +rm -rf ${HOME}/.docker/manifests/docker.io_${REGISTRY_PREFIX}_${IMAGE}-${VERSION} +DES_REGISTRY=${REGISTRY_PREFIX}/${IMAGE} +for platform in ${PLATFORMS}; do + os=${platform%_*} + arch=${platform#*_} + variant="" + if [ ${arch} == "arm64" ]; then + variant="--variant unknown" + fi + + docker manifest create --amend ${DES_REGISTRY}:${VERSION} \ + ${DES_REGISTRY}-${arch}:${VERSION} + + docker manifest annotate ${DES_REGISTRY}:${VERSION} \ + ${DES_REGISTRY}-${arch}:${VERSION} \ + --os ${os} --arch ${arch} ${variant} +done +docker manifest push --purge ${DES_REGISTRY}:${VERSION} \ No newline at end of file diff --git a/build/lib/image.mk b/build/lib/image.mk new file mode 100644 index 0000000..a10c75c --- /dev/null +++ b/build/lib/image.mk @@ -0,0 +1,119 @@ +# Tencent is pleased to support the open source community by making TKEStack +# available. +# +# Copyright (C) 2012-2019 Tencent. All Rights Reserved. +# +# 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://opensource.org/licenses/Apache-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 OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +# ============================================================================== +# Makefile helper functions for docker image + +DOCKER := DOCKER_CLI_EXPERIMENTAL=enabled docker +DOCKER_SUPPORTED_API_VERSION ?= 1.40 +DOCKER_VERSION ?= 19.03 + +REGISTRY_PREFIX ?= tkestack + +EXTRA_ARGS ?= +_DOCKER_BUILD_EXTRA_ARGS := + +ifdef HTTP_PROXY +_DOCKER_BUILD_EXTRA_ARGS += --build-arg http_proxy=${HTTP_PROXY} +endif +ifdef HTTPS_PROXY +_DOCKER_BUILD_EXTRA_ARGS += --build-arg https_proxy=${HTTPS_PROXY} +endif + +ifneq ($(EXTRA_ARGS), ) +_DOCKER_BUILD_EXTRA_ARGS += $(EXTRA_ARGS) +endif + +.PHONY: image.verify +image.verify: + $(eval API_VERSION := $(shell $(DOCKER) version | grep -E 'API version: {1,6}[0-9]' | head -n1 | awk '{print $$3} END { if (NR==0) print 0}' )) + $(eval PASS := $(shell echo "$(API_VERSION) >= $(DOCKER_SUPPORTED_API_VERSION)" | bc)) + @if [ $(PASS) -ne 1 ]; then \ + $(DOCKER) -v ;\ + echo "Unsupported docker version. Docker API version should be greater than $(DOCKER_SUPPORTED_API_VERSION) (Or docker version: $(DOCKER_VERSION))"; \ + exit 1; \ + fi + +.PHONY: image.buildx.verify +image.buildx.verify: image.verify + $(eval PASS := $(shell $(DOCKER) buildx version > /dev/null && echo 1 || echo 0)) + @if [ $(PASS) -ne 1 ]; then \ + $(MAKE) image.buildx.install; \ + fi + +.PHONY: image.buildx.install +image.buildx.install: + @$(ROOT_DIR)/build/lib/install-buildx.sh + +.PHONY: image.build +image.build: image.buildx.verify $(addprefix image.build., $(addprefix $(PLATFORM)., $(BINS))) + +.PHONY: image.build.multiarch +image.build.multiarch: image.buildx.verify $(foreach p,$(PLATFORMS),$(addprefix image.build., $(addprefix $(p)., $(BINS)))) + +.PHONY: image.build.% +image.build.%: + $(eval PLATFORM := $(word 1,$(subst ., ,$*))) + $(eval IMAGE := $(word 2,$(subst ., ,$*))) + $(eval OS := $(word 1,$(subst _, ,$(PLATFORM)))) + $(eval ARCH := $(word 2,$(subst _, ,$(PLATFORM)))) + $(eval IMAGE_PLAT := $(subst _,/,$(PLATFORM))) + $(eval IMAGE_NAME := $(REGISTRY_PREFIX)/$(IMAGE)-$(ARCH):$(VERSION)) + @echo "===========> Building docker image $(IMAGE) $(VERSION) for $(IMAGE_PLAT)" + $(DOCKER) buildx build --platform $(IMAGE_PLAT) --load -t $(IMAGE_NAME) $(_DOCKER_BUILD_EXTRA_ARGS) \ + -f $(ROOT_DIR)/build/docker/Dockerfile_arch $(ROOT_DIR) + +.PHONY: image.push +image.push: image.buildx.verify $(addprefix image.push., $(addprefix $(PLATFORM)., $(BINS))) + +.PHONY: image.push.multiarch +image.push.multiarch: image.buildx.verify $(foreach p,$(PLATFORMS),$(addprefix image.push., $(addprefix $(p)., $(BINS)))) + +.PHONY: image.push.% +image.push.%: image.build.% + @echo "===========> Pushing image $(IMAGE) $(VERSION) to $(REGISTRY_PREFIX)" + $(DOCKER) push $(REGISTRY_PREFIX)/$(IMAGE)-$(ARCH):$(VERSION) + +.PHONY: image.manifest.push +image.manifest.push: export DOCKER_CLI_EXPERIMENTAL := enabled +image.manifest.push: image.buildx.verify $(addprefix image.manifest.push., $(addprefix $(PLATFORM)., $(BINS))) + +.PHONY: image.manifest.push.% +image.manifest.push.%: image.push.% image.manifest.remove.% + @echo "===========> Pushing manifest $(IMAGE) $(VERSION) to $(REGISTRY_PREFIX) and then remove the local manifest list" + @$(DOCKER) manifest create $(REGISTRY_PREFIX)/$(IMAGE):$(VERSION) \ + $(REGISTRY_PREFIX)/$(IMAGE)-$(ARCH):$(VERSION) + @$(DOCKER) manifest annotate $(REGISTRY_PREFIX)/$(IMAGE):$(VERSION) \ + $(REGISTRY_PREFIX)/$(IMAGE)-$(ARCH):$(VERSION) \ + --os $(OS) --arch ${ARCH} + @$(DOCKER) manifest push --purge $(REGISTRY_PREFIX)/$(IMAGE):$(VERSION) + +# Docker cli has a bug: https://github.com/docker/cli/issues/954 +# If you find your manifests were not updated, +# Please manually delete them in $HOME/.docker/manifests/ +# and re-run. +.PHONY: image.manifest.remove.% +image.manifest.remove.%: + @rm -rf ${HOME}/.docker/manifests/docker.io_$(REGISTRY_PREFIX)_$(IMAGE)-$(VERSION) + +.PHONY: image.manifest.push.multiarch +image.manifest.push.multiarch: image.push.multiarch $(addprefix image.manifest.push.multiarch., $(BINS)) + +.PHONY: image.manifest.push.multiarch.% +image.manifest.push.multiarch.%: + @echo "===========> Pushing manifest $* $(VERSION) to $(REGISTRY_PREFIX) and then remove the local manifest list" + REGISTRY_PREFIX=$(REGISTRY_PREFIX) PLATFROMS="$(PLATFORMS)" IMAGE=$* VERSION=$(VERSION) DOCKER_CLI_EXPERIMENTAL=enabled \ + $(ROOT_DIR)/build/lib/create-manifest.sh diff --git a/build/lib/install-buildx.sh b/build/lib/install-buildx.sh new file mode 100755 index 0000000..f07d454 --- /dev/null +++ b/build/lib/install-buildx.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +# Tencent is pleased to support the open source community by making TKEStack +# available. +# +# Copyright (C) 2012-2019 Tencent. All Rights Reserved. +# +# 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://opensource.org/licenses/Apache-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 OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +BUILDX_VERSION=${BUILDX_VERSION:-"v0.4.1"} +ARCH=${ARCH:-"amd64"} +BUILDX_BIN="https://github.com/docker/buildx/releases/download/${BUILDX_VERSION}/buildx-${BUILDX_VERSION}.linux-${ARCH}" + +echo "Downloading docker-buildx" +wget -c ${BUILDX_BIN} -O ./docker-buildx +mkdir -p ~/.docker/cli-plugins/ +mv ./docker-buildx ~/.docker/cli-plugins/ +chmod a+x ~/.docker/cli-plugins/docker-buildx +docker buildx version \ No newline at end of file