# Copyright 2019 The KUARD Authors. # # 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 # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # This is a pretty complicated Makefile that builds the go binary (in a # container) and then automates packaging it up into an image and pushing it. It # then allows you to do this across multiple architectures and "fake versions". # # There is a bunch of funkiness around creating volumes so that intermetiate # files (such as go libraries and npm module downloads) are cached across builds # to speed things up. # # Some of the ideas here are taken from # https://github.com/thockin/go-build-template and # https://github.com/bowei/go-build-template. # We don't need make's built-in rules. MAKEFLAGS += --no-builtin-rules .SUFFIXES: # Golang package. PKG := github.com/kubernetes-up-and-running/kuard # Registry to push to. REGISTRY ?= gcr.io/kuar-demo # For demo purposes, we want to build multiple versions. They will all be # mostly the same but will let us demonstrate rollouts. FAKEVER ?= blue ALL_FAKEVER = blue green purple # This is the real version. We'll grab it from git and use tags. VERSION_BASE ?= $(shell git describe --tags --always --dirty) # Set to 1 to print more verbose output from the build. export VERBOSE ?= 0 # Default architecture to build for. ARCH ?= amd64 ALL_ARCH := amd64 arm arm64 ppc64le # Set default base image dynamically for each arch ifeq ($(ARCH),amd64) BASEIMAGE?=alpine endif ifeq ($(ARCH),arm) BASEIMAGE?=arm32v6/alpine endif ifeq ($(ARCH),arm64) BASEIMAGE?=arm64v8/alpine endif ifeq ($(ARCH),ppc64le) BASEIMAGE?=ppc64le/alpine endif BUILD_IMAGE := kuard-build DOCKER_RUN_FLAGS := --rm DOCKER_BUILD_FLAGS := --rm ifeq ($(VERBOSE), 1) VERBOSE_OUTPUT := >&1 else DOCKER_BUILD_FLAGS += -q VERBOSE_OUTPUT := >/dev/null MAKEFLAGS += -s endif DOCKER_MOUNTS:= \ -v $(BUILD_IMAGE)-data:/data:delegated \ -v $(BUILD_IMAGE)-node:/data/go/src/$(PKG)/client/node_modules:delegated \ -v $$(pwd):/data/go/src/$(PKG):delegated \ -v $$(pwd)/build:/build:delegated \ -v $$(pwd)/bin/$(FAKEVER)/$(ARCH):/data/go/bin:delegated \ -v $$(pwd)/bin/$(FAKEVER)/$(ARCH):/data/go/bin/linux_$(ARCH):delegated DOCKER_ENVS:= \ -e VERBOSE=$(VERBOSE) \ -e ARCH=$(ARCH) \ -e PKG=$(PKG) \ -e VERSION=$(VERSION_BASE)-$(FAKEVER) \ ############################################################################## # Default rule all: build ############################################################################## # Build container image # Build the build image. This depends on the dockerfile for this image and the # "init_data" script that initializes some volumes. We use a "timestamp" to # keep track of when this image was built and mirror the state of docker into # the filesystem. BUILD_IMAGE_BUILDSTAMP := .$(subst .,_,$(BUILD_IMAGE))-image $(BUILD_IMAGE_BUILDSTAMP): build/init_data.sh Dockerfile.build @echo "container image: $(BUILD_IMAGE)" @echo " Building container image" docker build \ $(DOCKER_BUILD_FLAGS) \ -t $(BUILD_IMAGE) \ --build-arg "ALL_ARCH=$(ALL_ARCH)" \ -f Dockerfile.build . \ $(VERBOSE_OUTPUT) @echo " Creating volume $(BUILD_IMAGE)-data" -docker volume rm $(BUILD_IMAGE)-data $(VERBOSE_OUTPUT) 2>&1 docker volume create $(BUILD_IMAGE)-data $(VERBOSE_OUTPUT) @echo " Creating volume $(BUILD_IMAGE)-node" -docker volume rm $(BUILD_IMAGE)-node $(VERBOSE_OUTPUT) 2>&1 docker volume create $(BUILD_IMAGE)-node $(VERBOSE_OUTPUT) @echo " Running build/init_data.sh in build container to init volumes" docker run $(DOCKER_RUN_FLAGS) \ -v $(BUILD_IMAGE)-data:/data:delegated \ -v $(BUILD_IMAGE)-node:/data/go/src/$(PKG)/client/node_modules:delegated \ -v $$(pwd)/build:/build:delegated \ -e TARGET_UIDGID=$$(id -u):$$(id -g) \ $(BUILD_IMAGE) \ /build/init_data.sh \ $(VERBOSE_OUTPUT) echo "$(BUILD_IMAGE)" > $@ docker images -q $(BUILD_IMAGE) >> $@ build-env: $(BUILD_IMAGE_BUILDSTAMP) @echo "Launching into build environment" docker run -ti \ $(DOCKER_RUN_FLAGS) \ $(DOCKER_MOUNTS) \ --sig-proxy=true \ $(DOCKER_ENVS) \ -u $$(id -u):$$(id -g) \ -w /data/go/src/$(PKG) \ $(BUILD_IMAGE) \ ash ############################################################################## # Build the kuard binary BINARYPATH:=bin/$(FAKEVER)/$(ARCH)/kuard .PHONY: build build: $(BINARYPATH) $(BINARYPATH): build/build.sh $(BUILD_IMAGE_BUILDSTAMP) @echo "building binary: $@" @mkdir -p $(shell pwd)/bin/$(FAKEVER)/$(ARCH) docker run \ $(DOCKER_RUN_FLAGS) \ $(DOCKER_MOUNTS) \ --sig-proxy=true \ $(DOCKER_ENVS) \ -u $$(id -u):$$(id -g) \ -w /data/go/src/$(PKG) \ $(BUILD_IMAGE) \ ./build/build.sh $(VERBOSE_OUTPUT) ############################################################################## # Build the final container image # Dockerfile for the final image. We use SED to slam a bunch of things in there. BIN_DOCKERFILE:=.kuard-$(ARCH)-$(FAKEVER)-dockerfile $(BIN_DOCKERFILE): Dockerfile.kuard @echo "generating Dockerfile $@ from $<" sed \ -e 's|ARG_ARCH|$(ARCH)|g' \ -e 's|ARG_FROM|$(BASEIMAGE)|g' \ -e 's|ARG_FAKEVER|$(FAKEVER)|g' \ $< > $@ CONTAINER_NAME := $(REGISTRY)/kuard-$(ARCH) BUILDSTAMP_NAME := $(subst /,_,$(CONTAINER_NAME)-$(FAKEVER)) .$(BUILDSTAMP_NAME)-image: $(BIN_DOCKERFILE) $(BINARYPATH) @echo "container image: $(CONTAINER_NAME):$(VERSION_BASE)-$(FAKEVER)" docker build \ $(DOCKER_BUILD_FLAGS) \ -t $(CONTAINER_NAME):$(VERSION_BASE)-$(FAKEVER) \ -f .kuard-$(ARCH)-$(FAKEVER)-dockerfile . \ $(VERBOSE_OUTPUT) echo "$(CONTAINER_NAME):$(VERSION_BASE)-$(FAKEVER)" > $@ @echo "container image tag: $(CONTAINER_NAME):$(FAKEVER)" docker tag $(CONTAINER_NAME):$(VERSION_BASE)-$(FAKEVER) $(CONTAINER_NAME):$(FAKEVER) echo "$(CONTAINER_NAME):$(FAKEVER)" >> $@ docker images -q $(CONTAINER_NAME):$(VERSION_BASE)-$(FAKEVER) >> $@ .PHONY: images images: .$(BUILDSTAMP_NAME)-image ############################################################################## # Push to the registry PUSH_BUILDSTAMP:=.$(BUILDSTAMP_NAME)-push .PHONY: push push: $(PUSH_BUILDSTAMP) .%-push: .%-image @echo "pushing image: " $$(sed -n '1p' $<) docker push $$(sed -n '1p' $<) $(VERBOSE_OUTPUT) @echo "pushing image: " $$(sed -n '2p' $<) docker push $$(sed -n '2p' $<) $(VERBOSE_OUTPUT) cat $< > $@ ############################################################################## # Rules for dealing with fake versions build-fakever-%: $(MAKE) --no-print-directory FAKEVER=$* build images-fakever-%: $(MAKE) --no-print-directory FAKEVER=$* images push-fakever-%: $(MAKE) --no-print-directory FAKEVER=$* push .PHONY: all-fakever-build all-fakever-build: $(addprefix build-fakever-, $(ALL_FAKEVER)) .PHONY: all-fakever-containers all-fakever-containers: $(addprefix containers-fakever-, $(ALL_FAKEVER)) .PHONY: all-fakever-push all-fakever-push: $(addprefix push-fakever-, $(ALL_FAKEVER)) ############################################################################## # Rules for dealing with multiple/all architectures at once build-arch-%: $(MAKE) --no-print-directory ARCH=$* build images-arch-%: $(MAKE) --no-print-directory ARCH=$* images push-arch-%: $(MAKE) --no-print-directory ARCH=$* push .PHONY: all-arch-build all-arch-build: $(addprefix build-arch-, $(ALL_ARCH)) .PHONY: all-arch-containers all-arch-containers: $(addprefix containers-arch-, $(ALL_ARCH)) .PHONY: all-arch-push all-arch-push: $(addprefix push-arch-, $(ALL_ARCH)) ############################################################################## # Deal with all fakevers, all archs .PHONY: all-build all-build: @$(foreach ARCH,$(ALL_ARCH),\ $(foreach FAKEVER,$(ALL_FAKEVER),\ $(MAKE) --no-print-directory ARCH=$(ARCH) FAKEVER=$(FAKEVER) build;)) .PHONY: all-images all-images: @$(foreach ARCH,$(ALL_ARCH),\ $(foreach FAKEVER,$(ALL_FAKEVER),\ $(MAKE) --no-print-directory ARCH=$(ARCH) FAKEVER=$(FAKEVER) images;)) .PHONY: all-push all-push: @$(foreach ARCH,$(ALL_ARCH),\ $(foreach FAKEVER,$(ALL_FAKEVER),\ $(MAKE) --no-print-directory ARCH=$(ARCH) FAKEVER=$(FAKEVER) push;)) ############################################################################## # Misc commands .PHONY: version version: @echo $(VERSION_BASE) .PHONY: clean clean: container-clean bin-clean .PHONY: container-clean container-clean: docker volume rm -f $(BUILD_IMAGE)-data $(BUILD_IMAGE)-node $(VERBOSE_OUTPUT) rm -f .*-container .*-dockerfile .*-push .*-image .PHONY: bin-clean bin-clean: rm -rf bin .PHONY: client-clean rm -rf client/node_modules sitedata/built .PHONY: help help: @echo "make targets" @echo @echo " all, build build all binaries" @echo " images build the container image" @echo " push push images to the registry" @echo " clean clean up all files and docker volumes/images" @echo " help this help message" @echo " version show package version" @echo @echo " {build,images,push}-arch-ARCH do action for specific ARCH" @echo " all-arch-{build,images,push} do action for all arches" @echo @echo " {build,images,push}-fakever-FAKEVER do action for specific FAKEVER" @echo " all-fakever-{build,images,push} do action for all fakevers" @echo @echo " all-{build,images,push} do action fo all arches and all fakevers" @echo @echo " Available ARCH: $(ALL_ARCH)" @echo " Default FAKEVERS: $(ALL_FAKEVER)" @echo @echo " Setting VERBOSE=1 will show additional build logging." @echo @echo " Setting VERSION_BASE will override the container version tag."