Skip to content

Commit

Permalink
Merge pull request kubernetes-sigs#974 from mainred/polish-node-manag…
Browse files Browse the repository at this point in the history
…er-image-building

chore: Polish node manager image building
  • Loading branch information
k8s-ci-robot authored and Qingchuan Hao committed Jan 12, 2022
1 parent c96252f commit 3dee88d
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 77 deletions.
168 changes: 97 additions & 71 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,6 @@ SHELL=/bin/bash -o pipefail
BIN_DIR=bin
PKG_CONFIG=.pkg_config

ARCH ?= amd64
# golang/strecth supports only amd64, arm32v7, arm64v8 and i386, before we have an
# explicit requirement for other arch support, let's keep golang/stretch
# https://github.com/docker-library/official-images/blob/master/library/golang
LINUX_ARCHS = amd64 arm arm64

# The output type for `docker buildx build` could either be docker (local), or registry.
OUTPUT_TYPE ?= docker

AKSENGINE_VERSION ?= master
ENABLE_GIT_COMMAND ?= true
TEST_RESULTS_DIR=testResults
Expand All @@ -40,16 +31,30 @@ CCM_E2E_ARGS ?= -ginkgo.skip=\\[Serial\\]\\[Slow\\]
#The test args for Kubernetes e2e tests
TEST_E2E_ARGS ?= '--ginkgo.focus=Port\sforwarding'

IMAGE_REGISTRY ?= local
STAGING_REGISTRY := gcr.io/k8s-staging-provider-azure
K8S_VERSION ?= v1.18.0-rc.1
HYPERKUBE_IMAGE ?= gcrio.azureedge.net/google_containers/hyperkube-amd64:$(K8S_VERSION)
# Generate all combination of all OS, ARCH, and OSVERSIONS for iteration

# The OS Version for the Windows images: 1809, 2004, 20H2
ALL_ARCH.linux = amd64 arm arm64
# as windows server core does not support arm64 windows image, trakced by the following link,
# and only 1809 has arm64 nanoserver support, we support here only amd64 windows image
# https://github.com/microsoft/Windows-Containers/issues/195
ALL_ARCH.windows = amd64
ALL_OSVERSIONS.windows := 1809 2004 20H2 ltsc2022
ALL_OS_ARCH.windows = $(foreach arch, $(ALL_ARCH.windows), $(foreach osversion, ${ALL_OSVERSIONS.windows}, ${osversion}-${arch}))

# The current context of image building
# The architecture of the image
ARCH ?= amd64
# OS Version for the Windows images: 1809, 2004, 20H2, ltsc2022
WINDOWS_OSVERSION ?= 1809
ALL_WINDOWS_OSVERSIONS = 1809 2004 20H2
# The output type for `docker buildx build` could either be docker (local), or registry.
OUTPUT_TYPE ?= docker

BASE.windows := mcr.microsoft.com/windows/nanoserver

IMAGE_REGISTRY ?= local
K8S_VERSION ?= v1.18.0-rc.1
HYPERKUBE_IMAGE ?= gcrio.azureedge.net/google_containers/hyperkube-amd64:$(K8S_VERSION)

# `docker buildx` and `docker manifest` requires enabling DOCKER_CLI_EXPERIMENTAL for docker version < 1.20
export DOCKER_CLI_EXPERIMENTAL=enabled

Expand All @@ -70,15 +75,11 @@ endif
IMAGE=$(IMAGE_REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG)
# cloud node manager image
NODE_MANAGER_IMAGE_NAME=azure-cloud-node-manager
NODE_MANAGER_LINUX_IMAGE_NAME=azure-cloud-node-manager-linux
NODE_MANAGER_WINDOWS_IMAGE_NAME=azure-cloud-node-manager-windows
NODE_MANAGER_IMAGE=$(IMAGE_REGISTRY)/$(NODE_MANAGER_IMAGE_NAME):$(IMAGE_TAG)
NODE_MANAGER_LINUX_FULL_IMAGE=$(IMAGE_REGISTRY)/$(NODE_MANAGER_LINUX_IMAGE_NAME)
NODE_MANAGER_WINDOWS_IMAGE=$(IMAGE_REGISTRY)/$(NODE_MANAGER_WINDOWS_IMAGE_NAME):$(IMAGE_TAG)

ALL_NODE_MANAGER_IMAGES = $(foreach arch, ${LINUX_ARCHS}, $(NODE_MANAGER_LINUX_FULL_IMAGE):$(IMAGE_TAG)-${arch}) $(foreach osversion, ${ALL_WINDOWS_OSVERSIONS}, $(NODE_MANAGER_WINDOWS_IMAGE)-${osversion})
ALL_LINUX_NODE_MANAGER_IMAGES = $(foreach arch, ${LINUX_ARCHS}, $(NODE_MANAGER_LINUX_FULL_IMAGE):$(IMAGE_TAG)-${arch})

NODE_MANAGER_FULL_IMAGE_NAME=$(IMAGE_REGISTRY)/$(NODE_MANAGER_IMAGE_NAME)
NODE_MANAGER_IMAGE=$(NODE_MANAGER_FULL_IMAGE_NAME):$(IMAGE_TAG)
NODE_MANAGER_LINUX_FULL_IMAGE_PREFIX=$(NODE_MANAGER_FULL_IMAGE_NAME):$(IMAGE_TAG)-linux
NODE_MANAGER_WINDOWS_FULL_IMAGE_PREFIX=$(NODE_MANAGER_FULL_IMAGE_NAME):$(IMAGE_TAG)-windows
ALL_NODE_MANAGER_IMAGES = $(foreach arch, ${ALL_ARCH.linux}, $(NODE_MANAGER_LINUX_FULL_IMAGE_PREFIX)-${arch}) $(foreach osversion-arch, ${ALL_OS_ARCH.windows}, $(NODE_MANAGER_WINDOWS_FULL_IMAGE_PREFIX)-${osversion-arch})

# ccm e2e test image
CCM_E2E_TEST_IMAGE_NAME=cloud-provider-azure-e2e
Expand All @@ -102,7 +103,7 @@ $(BIN_DIR)/azure-cloud-node-manager: $(PKG_CONFIG) $(wildcard cmd/cloud-node-man
CGO_ENABLED=0 GOOS=linux GOARCH=${ARCH} go build -a -o $(BIN_DIR)/azure-cloud-node-manager $(shell cat $(PKG_CONFIG)) ./cmd/cloud-node-manager

$(BIN_DIR)/azure-cloud-node-manager.exe: $(PKG_CONFIG) $(wildcard cmd/cloud-node-manager/*) $(wildcard cmd/cloud-node-manager/**/*) $(wildcard pkg/**/*) ## Build node-manager binary for Windows.
CGO_ENABLED=0 GOOS=windows go build -a -o $(BIN_DIR)/azure-cloud-node-manager.exe $(shell cat $(PKG_CONFIG)) ./cmd/cloud-node-manager
CGO_ENABLED=0 GOOS=windows GOARCH=${ARCH} go build -a -o $(BIN_DIR)/azure-cloud-node-manager-${ARCH}.exe $(shell cat $(PKG_CONFIG)) ./cmd/cloud-node-manager

$(BIN_DIR)/azure-cloud-controller-manager: $(PKG_CONFIG) $(wildcard cmd/cloud-controller-manager/*) $(wildcard cmd/cloud-controller-manager/**/*) $(wildcard pkg/**/*) ## Build binary for controller-manager.
CGO_ENABLED=0 GOOS=linux GOARCH=${ARCH} go build -a -o $(BIN_DIR)/azure-cloud-controller-manager $(shell cat $(PKG_CONFIG)) ./cmd/cloud-controller-manager
Expand Down Expand Up @@ -136,8 +137,8 @@ build-ccm-image: buildx-setup docker-pull-prerequisites ## Build controller-mana
--file Dockerfile \
--tag $(IMAGE) .

.PHONY: build-node-image
build-node-image: buildx-setup docker-pull-prerequisites ## Build node-manager image.
.PHONY: build-node-image-linux
build-node-image-linux: buildx-setup docker-pull-prerequisites ## Build node-manager image.
docker buildx build \
--pull \
--output=type=$(OUTPUT_TYPE) \
Expand All @@ -146,13 +147,27 @@ build-node-image: buildx-setup docker-pull-prerequisites ## Build node-manager i
--build-arg ARCH="$(ARCH)" \
--build-arg VERSION="$(VERSION)" \
--file cloud-node-manager.Dockerfile \
--tag $(NODE_MANAGER_LINUX_FULL_IMAGE):$(IMAGE_TAG)-$(ARCH) .
--tag $(NODE_MANAGER_LINUX_FULL_IMAGE_PREFIX)-$(ARCH) .

# TODO(mainred): When using ACR, `az acr login` impacts the authentication of `docker buildx build --push` when the
# ACR, capz in our case, has anonymous pull enabled.
# Use `docker login` as a suggested workaround and remove this target when the issue is resolved.
# Issue link: https://github.com/Azure/acr/issues/582
# Failed building link: https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/974/pull-cloud-provider-azure-e2e-ccm-capz/1480459040440979456
.PHONY: docker-login-acr
docker-login-acr:
ifneq (,$(findstring capzci.azurecr.io,$(IMAGE_REGISTRY)))
docker login -u $(AZURE_CLIENT_ID) -p $(AZURE_CLIENT_SECRET) capzci.azurecr.io
endif

.PHONY: build-and-push-node-image-windows
build-and-push-node-image-windows: buildx-setup ## Build node-manager image for Windows and push it to registry.
go build -a -o $(BIN_DIR)/azure-cloud-node-manager.exe ./cmd/cloud-node-manager
docker buildx build --pull --push --output=type=registry --platform windows/amd64 \
-t $(NODE_MANAGER_WINDOWS_IMAGE)-$(WINDOWS_OSVERSION) --build-arg OSVERSION=$(WINDOWS_OSVERSION) \
.PHONY: build-node-image-windows
build-node-image-windows: buildx-setup $(BIN_DIR)/azure-cloud-node-manager.exe docker-login-acr ## Build node-manager image for Windows.
docker buildx build --pull \
--output=type=$(OUTPUT_TYPE) \
--platform windows/$(ARCH) \
-t $(NODE_MANAGER_WINDOWS_FULL_IMAGE_PREFIX)-$(WINDOWS_OSVERSION)-$(ARCH) \
--build-arg OSVERSION=$(WINDOWS_OSVERSION) \
--build-arg ARCH=$(ARCH) \
-f cloud-node-manager-windows.Dockerfile .

.PHONY: build-ccm-e2e-test-image
Expand All @@ -163,9 +178,9 @@ build-ccm-e2e-test-image: ## Build e2e test image.
push-ccm-image: build-ccm-image ## Push controller-manager image.
docker push $(IMAGE)

.PHONY: push-node-image
push-node-image: ## Push node-manager image for Linux.
docker push $(NODE_MANAGER_LINUX_FULL_IMAGE):$(IMAGE_TAG)-$(ARCH)
.PHONY: push-node-image-linux
push-node-image-linux: ## Push node-manager image for Linux.
docker push $(NODE_MANAGER_LINUX_FULL_IMAGE_PREFIX)-$(ARCH)

.PHONY: release-ccm-e2e-test-image
release-ccm-e2e-test-image: ## Build and release e2e test image.
Expand All @@ -182,67 +197,78 @@ endif
##@ All Arch or OS Version
## --------------------------------------

# NOTE(mainred): build-images target is going to be deprecated
.PHONY: build-images
build-images: build-all-ccm-images build-all-node-images ## Build all images.
build-images: image

# NOTE(mainred): push-images target is going to be deprecated
.PHONY: push-images
push-images: push

.PHONY: image
image: build-all-ccm-images build-all-node-images ## Build all images.

.PHONY: push-images
push-images: push-all-ccm-images push-all-node-images ## Push all images.

.PHONY: push
push: push-all-ccm-images push-all-node-images ## Push all images.
push: push-all-ccm-images push-multi-arch-node-manager-image ## Push all images.

.PHONY: push-node-manager-manifest
push-node-manager-manifest: push-all-node-images push-all-windows-node-images ## Create and push a manifest list containing all the Windows and Linux images.
.PHONY: push-multi-arch-node-manager-image ## Push multi-arch node-manager image
push-multi-arch-node-manager-image: push-all-node-images ## Create and push a manifest list containing all the Windows and Linux images.
docker manifest create --amend $(NODE_MANAGER_IMAGE) $(ALL_NODE_MANAGER_IMAGES)
for arch in $(LINUX_ARCHS); do \
docker manifest annotate --os linux --arch $${arch} $(NODE_MANAGER_IMAGE) $(NODE_MANAGER_LINUX_FULL_IMAGE):$(IMAGE_TAG)-$${arch}; \
for arch in $(ALL_ARCH.linux); do \
docker manifest annotate --os linux --arch $${arch} $(NODE_MANAGER_IMAGE) $(NODE_MANAGER_LINUX_FULL_IMAGE_PREFIX)-$${arch}; \
done
# For Windows images, we also need to include the "os.version" in the manifest list, so the Windows node can pull the proper image it needs.
# we use awk to also trim the quotes around the OS version string.
set -x; \
for osversion in $(ALL_WINDOWS_OSVERSIONS); do \
full_version=`docker manifest inspect ${BASE.windows}:$${osversion} | grep "os.version" | head -n 1 | awk -F\" '{print $$4}'` || true; \
docker manifest annotate --os windows --arch amd64 --os-version $${full_version} $(NODE_MANAGER_IMAGE) $(NODE_MANAGER_WINDOWS_IMAGE)-$${osversion}; \
for windowsarch in $(ALL_ARCH.windows); do \
for osversion in $(ALL_OSVERSIONS.windows); do \
full_version=`docker manifest inspect ${BASE.windows}:$${osversion} | jq -r '.manifests[0].platform["os.version"]'`; \
docker manifest annotate --os windows --arch $${windowsarch} --os-version $${full_version} $(NODE_MANAGER_IMAGE) $(NODE_MANAGER_WINDOWS_FULL_IMAGE_PREFIX)-$${osversion}-$${windowsarch}; \
done; \
done
docker manifest push --purge $(NODE_MANAGER_IMAGE)

# TODO(mainred): Currently we push only Linux multi-arch docker images for node image, after fully support Windows docker image building,
# we need to replace push-all-node-images with push-all-node-images to push multi-arch and multi-os node image,
# which is tracked https://github.com/kubernetes-sigs/cloud-provider-azure/issues/829
.PHONY: push-all-node-images
push-all-node-images: $(addprefix push-node-image-,$(LINUX_ARCHS))
docker manifest create --amend $(NODE_MANAGER_IMAGE) $(ALL_LINUX_NODE_MANAGER_IMAGES)
for arch in $(LINUX_ARCHS); do \
docker manifest annotate --os linux --arch $${arch} $(NODE_MANAGER_IMAGE) $(NODE_MANAGER_LINUX_FULL_IMAGE):$(IMAGE_TAG)-$${arch}; \
done
docker manifest push --purge $(NODE_MANAGER_IMAGE)
.PHONY: push-all-node-images ## Push node-manager image for os and archs.
push-all-node-images: push-all-node-images-linux push-all-node-images-windows

.PHONY: push-all-node-images-linux ## Push node-manager image for Linux.
push-all-node-images-linux: $(addprefix push-node-image-linux-,$(ALL_ARCH.linux))

.PHONY: push-all-node-images-windows ## Push node-manager image for Windows.
push-all-node-images-windows: $(addprefix push-node-image-windows-,$(ALL_OS_ARCH.windows))

# split words on hyphen, access by 1-index
word-hyphen = $(word $2,$(subst -, ,$1))

push-node-image-linux-%:
$(MAKE) ARCH=$* push-node-image-linux

push-node-image-windows-%:
$(MAKE) WINDOWS_OSVERSION=$(call word-hyphen,$*,1) ARCH=$(call word-hyphen,$*,2) OUTPUT_TYPE=registry build-node-image-windows

.PHONY: push-all-windows-node-images
push-all-windows-node-images: $(addprefix push-node-image-windows-,$(ALL_WINDOWS_OSVERSIONS))
.PHONY: build-all-node-images ## Build node-manager image for all OS and archs.
build-all-node-images: build-all-node-images-linux build-all-node-images-windows

.PHONY: build-all-node-images
build-all-node-images: $(addprefix build-node-image-,$(LINUX_ARCHS))
.PHONY: build-all-node-images-linux ## Build node-manager image for Linux.
build-all-node-images-linux: $(addprefix build-node-image-linux-,$(ALL_ARCH.linux))

build-node-image-%:
$(MAKE) ARCH=$* build-node-image
.PHONY: build-all-node-images-windows ## Build node-manager image for Windows.
build-all-node-images-windows: $(addprefix build-node-image-windows-,$(ALL_OS_ARCH.windows))

push-node-image-windows-%: ## Push node-manager image for Windows.
$(MAKE) WINDOWS_OSVERSION=$* build-and-push-node-image-windows
build-node-image-linux-%:
$(MAKE) ARCH=$* build-node-image-linux

push-node-image-%:
$(MAKE) ARCH=$* push-node-image
build-node-image-windows-%:
$(MAKE) WINDOWS_OSVERSION=$(call word-hyphen,$*,1) ARCH=$(call word-hyphen,$*,2) build-node-image-windows

.PHONY: build-all-ccm-images
build-all-ccm-images: $(addprefix build-ccm-image-,$(LINUX_ARCHS))
build-all-ccm-images: $(addprefix build-ccm-image-,$(ALL_ARCH.linux))

build-ccm-image-%:
$(MAKE) ARCH=$* build-ccm-image

.PHONY: push-all-ccm-images
push-all-ccm-images: $(addprefix push-ccm-image-,$(LINUX_ARCHS))
push-all-ccm-images: $(addprefix push-ccm-image-,$(ALL_ARCH.linux))

push-ccm-image-%:
$(MAKE) ARCH=$* push-ccm-image
Expand Down Expand Up @@ -321,4 +347,4 @@ deploy: image push ## Build, push and deploy an aks-engine cluster.

.PHONY: release-staging
release-staging: ## Release the cloud provider images.
ENABLE_GIT_COMMAND=$(ENABLE_GIT_COMMAND) IMAGE_REGISTRY=$(STAGING_REGISTRY) $(MAKE) build-images push-images
ENABLE_GIT_COMMAND=$(ENABLE_GIT_COMMAND) $(MAKE) image push
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ Build docker image for azure-cloud-controller-manager:
IMAGE_REGISTRY=<registry> make image
```

More detailed directions for image building, please read [here](http://kubernetes-sigs.github.io/cloud-provider-azure/development/image-building/).

## Run

Run azure-cloud-controller-manager locally:
Expand Down
9 changes: 7 additions & 2 deletions cloud-node-manager-windows.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,19 @@
# limitations under the License.

ARG OSVERSION=1809
ARG ARCH=amd64

# NOTE(claudiub): Instead of pulling the servercore image, which is ~2GB in side, we
# can instead pull the windows-servercore-cache image, which is only a few MBs in size.
# The image contains the netapi32.dll we need.
FROM --platform=linux/amd64 gcr.io/k8s-staging-e2e-test-images/windows-servercore-cache:1.0-linux-amd64-$OSVERSION as servercore-helper
FROM --platform=linux/amd64 gcr.io/k8s-staging-e2e-test-images/windows-servercore-cache:1.0-linux-${ARCH}-$OSVERSION as servercore-helper

FROM mcr.microsoft.com/windows/nanoserver:$OSVERSION

ARG OSVERSION
ARG ARCH

COPY --from=servercore-helper /Windows/System32/netapi32.dll /Windows/System32/netapi32.dll
COPY bin/azure-cloud-node-manager.exe /cloud-node-manager.exe
COPY bin/azure-cloud-node-manager-${ARCH}.exe /cloud-node-manager.exe
USER ContainerAdministrator
ENTRYPOINT ["/azure-cloud-node-manager.exe"]
1 change: 1 addition & 0 deletions cloudbuild.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ steps:
- ENABLE_GIT_COMMAND=false
- DOCKER_CLI_EXPERIMENTAL=enabled
- DOCKER_BUILDKIT=1
- IMAGE_REGISTRY=gcr.io/k8s-staging-provider-azure
args:
- release-staging
substitutions:
Expand Down
4 changes: 3 additions & 1 deletion site/content/en/development/custom-images.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Switch to the project root directory and run the following command to build both
make image
```

If you want to build only one of them, try `make build-ccm-image` or `make build-node-image`.
If you want to build only one of them, try `make build-ccm-image` or `ARCH=amd64 make build-node-image-linux`.

To push the images to your own image registry, you can specify the registry and image tag while building:

Expand All @@ -22,3 +22,5 @@ IMAGE_REGISTRY=<image registry name> IMAGE_TAG=<tag name> make image
```

After building, you can push them to your image registry by `make push`.

Please follow [here](http://kubernetes-sigs.github.io/cloud-provider-azure/development/image-building/) to build multi-arch image
4 changes: 2 additions & 2 deletions site/content/en/development/e2e/e2e-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ description: >
cd $GOPATH/src/sigs.k8s.io/cloud-provider-azure
export IMAGE_REGISTRY=<username>
export IMAGE_TAG=<tag>
make build-images
make push-images # or manually `docker push`
make image
make push # or manually `docker push`
```

3. Deploy a Kubernetes cluster with the above `azure-cloud-controller-manager` image.
Expand Down
2 changes: 1 addition & 1 deletion site/content/en/development/future.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: "Future Plans"
linkTitle: "Future Plans"
type: docs
weight: 5
weight: 6
description: >
Future Plans.
---
Expand Down
40 changes: 40 additions & 0 deletions site/content/en/development/image-building.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
title: "Image building"
linkTitle: "Image building"
type: docs
weight: 5
description: >
Image building.
---

## multi-arch image

Currently, only Linux multi-arch cloud-node-manager image is supported as a result of customer requests and windows limitations.
Supported Linux archs are defined by `ALL_ARCH.linux` in Makefile, and Windows os versions are by `ALL_OSVERSIONS.windows`.

### Windows multi-arch image limitation

Images [nanoserver](https://hub.docker.com/_/microsoft-windows-nanoserver) and [servercore](https://hub.docker.com/_/microsoft-windows-servercore) are referenced to build a Windows image, but as current officially published servercore images does not support non-amd64 image, and only Windows server 1809 has the support of non-amd64 for nanoserver, amd64 is the only supported arch for a range of Windows OS version so far.
This issue is tracked [here](https://github.com/microsoft/Windows-Containers/issues/195)

## hand-on examples

To build and publish the multi-arch image for node manager

```sh
IMAGE_REGISTRY=<registry> make build-all-node-images
IMAGE_REGISTRY=<registry> make push-multi-arch-node-manager-image
```

To build a specific Linux arch image for node manager

```sh
IMAGE_REGISTRY=<registry> ARCH=amd64 make build-node-image-linux
```

To build specific Windows OS and arch image for node manager

```sh
IMAGE_REGISTRY=<registry> OUTPUT_TYPE=registry ARCH=amd64 WINDOWS_OSVERSION=1809 build-node-image-windows
```
The `OUTPUT_TYPE` registry here means the built image will be published to the registry, this is necessary to build a Windows image from a Linux working environment. An alternative is to export the image tarball to a local destination, like `OUTPUT_TYPE=docker,dest=dstdir/azure-cloud-node-manager.tar`. For more info about `docker buildx` output type, please check out [here](https://docs.docker.com/engine/reference/commandline/buildx_build/#output)

0 comments on commit 3dee88d

Please sign in to comment.