Merge pull request #91452 from claudiubelu/windows/pause-image

Add support for building Windows pause image
This commit is contained in:
Kubernetes Prow Robot 2020-10-23 04:05:45 -07:00 committed by GitHub
commit 68e4f1ff64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 276 additions and 52 deletions

View File

@ -20,6 +20,7 @@ filegroup(
name = "all-srcs", name = "all-srcs",
srcs = [ srcs = [
":package-srcs", ":package-srcs",
"//build/pause/windows/wincat:all-srcs",
"//build/release-tars:all-srcs", "//build/release-tars:all-srcs",
"//build/visible_to:all-srcs", "//build/visible_to:all-srcs",
], ],

View File

@ -152,7 +152,7 @@ dependencies:
match: tag = match: tag =
- name: "k8s.gcr.io/pause" - name: "k8s.gcr.io/pause"
version: 3.3 version: 3.4
refPaths: refPaths:
- path: build/pause/Makefile - path: build/pause/Makefile
match: TAG = match: TAG =

View File

@ -12,7 +12,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
FROM scratch ARG BASE
FROM ${BASE}
ARG ARCH ARG ARCH
ADD bin/pause-${ARCH} /pause ADD bin/pause-linux-${ARCH} /pause
ENTRYPOINT ["/pause"] ENTRYPOINT ["/pause"]

View File

@ -0,0 +1,25 @@
# Copyright 2020 The Kubernetes 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.
ARG BASE
FROM ${BASE}
ARG ARCH
ADD bin/pause-windows-${ARCH}.exe /pause.exe
ADD bin/wincat-windows-amd64 /Windows/System32/wincat.exe
# NOTE(claudiub): docker buildx sets the PATH env variable to a Linux-like PATH,
# which is not desirable. See: https://github.com/moby/buildkit/issues/1560
# TODO(claudiub): remove this once the issue has been resolved.
ENV PATH="C:\Windows\system32;C:\Windows;"
ENTRYPOINT ["/pause.exe"]

View File

@ -12,91 +12,132 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
.PHONY: all push container clean orphan all-push push-manifest .PHONY: all container clean orphan all-push push-manifest
REGISTRY ?= staging-k8s.gcr.io REGISTRY ?= staging-k8s.gcr.io
IMAGE = $(REGISTRY)/pause IMAGE = $(REGISTRY)/pause
IMAGE_WITH_ARCH = $(IMAGE)-$(ARCH) IMAGE_WITH_OS_ARCH = $(IMAGE)-$(OS)-$(ARCH)
TAG = 3.3 TAG = 3.4
REV = $(shell git describe --contains --always --match='v*') REV = $(shell git describe --contains --always --match='v*')
# Architectures supported: amd64, arm, arm64, ppc64le and s390x # Architectures supported: amd64, arm, arm64, ppc64le and s390x
ARCH ?= amd64 ARCH ?= amd64
# Operating systems supported: linux, windows
OS ?= linux
# OS Version for the Windows images: 1809, 1903, 1909 2004
OSVERSION ?= 1809 1903 1909 2004
ALL_ARCH = amd64 arm arm64 ppc64le s390x # The output type could either be docker (local), or registry.
# If it is registry, it will also allow us to push the Windows images.
OUTPUT_TYPE ?= docker
ALL_OS = linux windows
ALL_ARCH.linux = amd64 arm arm64 ppc64le s390x
ALL_OS_ARCH.linux = $(foreach arch, ${ALL_ARCH.linux}, linux-$(arch))
ALL_ARCH.windows = amd64
ALL_OSVERSIONS.windows := 1809 1903 1909 2004
ALL_OS_ARCH.windows = $(foreach arch, $(ALL_ARCH.windows), $(foreach osversion, ${ALL_OSVERSIONS.windows}, windows-$(arch)-${osversion}))
ALL_OS_ARCH = $(foreach os, $(ALL_OS), ${ALL_OS_ARCH.${os}})
CFLAGS = -Os -Wall -Werror -static -DVERSION=v$(TAG)-$(REV) CFLAGS = -Os -Wall -Werror -static -DVERSION=v$(TAG)-$(REV)
KUBE_CROSS_IMAGE ?= k8s.gcr.io/build-image/kube-cross KUBE_CROSS_IMAGE.linux ?= k8s.gcr.io/build-image/kube-cross
KUBE_CROSS_VERSION ?= $(shell cat ../build-image/cross/VERSION) KUBE_CROSS_VERSION.linux ?= $(shell cat ../build-image/cross/VERSION)
KUBE_CROSS_IMAGE.windows ?= dockcross/windows-static-x64
KUBE_CROSS_VERSION.windows ?= latest
KUBE_CROSS_IMAGE := ${KUBE_CROSS_IMAGE.${OS}}
KUBE_CROSS_VERSION := ${KUBE_CROSS_VERSION.${OS}}
BIN = pause # NOTE(claudiub): The Windows pause image also requires the wincat binary we're compiling for the
SRCS = pause.c # port-forwarding scenarios. If it's no longer necessary, it can be removed.
# For more information, see: https://github.com/kubernetes/kubernetes/pull/91452
BIN.linux = pause
BIN.windows = pause wincat
BIN := ${BIN.${OS}}
SRCS.linux = linux/pause.c
SRCS.windows = windows/pause.c
SRCS := ${SRCS.${OS}}
ifeq ($(ARCH),amd64) EXTENSION.linux =
TRIPLE ?= x86_64-linux-gnu EXTENSION.windows = .exe
endif EXTENSION := ${EXTENSION.${OS}}
ifeq ($(ARCH),arm) # The manifest command is still experimental as of Docker 18.09.3
TRIPLE ?= arm-linux-gnueabihf export DOCKER_CLI_EXPERIMENTAL=enabled
endif
ifeq ($(ARCH),arm64) TRIPLE.windows-amd64 := x86_64-w64-mingw32.static
TRIPLE ?= aarch64-linux-gnu TRIPLE.linux-amd64 := x86_64-linux-gnu
endif TRIPLE.linux-arm := arm-linux-gnueabihf
TRIPLE.linux-arm64 := aarch64-linux-gnu
ifeq ($(ARCH),ppc64le) TRIPLE.linux-ppc64le := powerpc64le-linux-gnu
TRIPLE ?= powerpc64le-linux-gnu TRIPLE.linux-s390x := s390x-linux-gnu
endif TRIPLE := ${TRIPLE.${OS}-${ARCH}}
BASE.linux := scratch
ifeq ($(ARCH),s390x) BASE.windows := mcr.microsoft.com/windows/nanoserver
TRIPLE ?= s390x-linux-gnu BASE := ${BASE.${OS}}
endif
# If you want to build AND push all containers, see the 'all-push' rule. # If you want to build AND push all containers, see the 'all-push' rule.
all: all-container all: all-container-docker
all-push: all-push-images push-manifest # NOTE(claudiub): A non-default builder instance is needed in order to build Windows images.
all-push: all-container-registry push-manifest
push-manifest: push-manifest:
docker manifest create --amend $(IMAGE):$(TAG) $(shell echo $(ALL_ARCH) | sed -e "s~[^ ]*~$(IMAGE)\-&:$(TAG)~g") docker manifest create --amend $(IMAGE):$(TAG) $(shell echo $(ALL_OS_ARCH) | sed -e "s~[^ ]*~$(IMAGE)\-&:$(TAG)~g")
set -x; for arch in $(ALL_ARCH); do docker manifest annotate --arch $${arch} ${IMAGE}:${TAG} ${IMAGE}-$${arch}:${TAG}; done set -x; for arch in $(ALL_ARCH.linux); do docker manifest annotate --os linux --arch $${arch} ${IMAGE}:${TAG} ${IMAGE}-linux-$${arch}:${TAG}; 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.
# At the moment, docker manifest annotate doesn't allow us to set the os.version, so we'll have to it ourselves. The manifest list can be found locally as JSONs.
# See: https://github.com/moby/moby/issues/41417
# TODO(claudiub): Clean this up once the above issue has been fixed.
set -x; \
registry_prefix=$(shell (echo ${REGISTRY} | grep -Eq "[a-z]*") && echo "docker.io/" || echo ""); \
manifest_image_folder=`echo "$${registry_prefix}${IMAGE}" | sed "s|/|_|g" | sed "s/:/-/"`; \
for arch in $(ALL_ARCH.windows); do \
for osversion in ${ALL_OSVERSIONS.windows}; do \
docker manifest annotate --os windows --arch $${arch} ${IMAGE}:${TAG} ${IMAGE}-windows-$${arch}-$${osversion}:${TAG}; \
BASEIMAGE=${BASE.windows}:$${osversion}; \
full_version=`docker manifest inspect ${BASE.windows}:$${osversion} | grep "os.version" | head -n 1 | awk '{print $$2}'` || true; \
sed -i -r "s/(\"os\"\:\"windows\")/\0,\"os.version\":$${full_version}/" "${HOME}/.docker/manifests/$${manifest_image_folder}-${TAG}/$${manifest_image_folder}-windows-$${arch}-$${osversion}-${TAG}"; \
done; \
done
docker manifest push --purge ${IMAGE}:${TAG} docker manifest push --purge ${IMAGE}:${TAG}
all-container-docker: $(addprefix sub-container-docker-,$(ALL_OS_ARCH.linux))
all-container-registry: $(addprefix sub-container-registry-,$(ALL_OS_ARCH))
# split words on hyphen, access by 1-index
word-hyphen = $(word $2,$(subst -, ,$1))
sub-container-%: sub-container-%:
$(MAKE) ARCH=$* container $(MAKE) OUTPUT_TYPE=$(call word-hyphen,$*,1) OS=$(call word-hyphen,$*,2) ARCH=$(call word-hyphen,$*,3) OSVERSION=$(call word-hyphen,$*,4) container
sub-push-%: build: $(foreach binary, ${BIN}, bin/${binary}-${OS}-${ARCH})
$(MAKE) ARCH=$* push
all-container: $(addprefix sub-container-,$(ALL_ARCH)) bin/${BIN.linux}-$(OS)-$(ARCH): $(SRCS)
all-push-images: $(addprefix sub-push-,$(ALL_ARCH))
build: bin/$(BIN)-$(ARCH)
bin/$(BIN)-$(ARCH): $(SRCS)
mkdir -p bin mkdir -p bin
docker run --rm -u $$(id -u):$$(id -g) -v $$(pwd):/build \ docker run --rm -u $$(id -u):$$(id -g) -v $$(pwd):/build \
$(KUBE_CROSS_IMAGE):$(KUBE_CROSS_VERSION) \ $(KUBE_CROSS_IMAGE):$(KUBE_CROSS_VERSION) \
/bin/bash -c "\ /bin/bash -c "\
cd /build && \ cd /build && \
$(TRIPLE)-gcc $(CFLAGS) -o $@ $^ && \ $(TRIPLE)-gcc $(CFLAGS) -o $@ $^ && \
$(TRIPLE)-strip $@" $(TRIPLE)-strip $(foreach binary, $@, ${binary}${EXTENSION})"
container: .container-$(ARCH) bin/wincat-windows-${ARCH}: windows/wincat/wincat.go
.container-$(ARCH): bin/$(BIN)-$(ARCH) CGO_ENABLED=0 GOOS=windows GOARCH=${ARCH} go build -o $@ $^
DOCKER_CLI_EXPERIMENTAL=enabled docker buildx build --load --pull --platform linux/$(ARCH) -t $(IMAGE_WITH_ARCH):$(TAG) --build-arg ARCH=$(ARCH) .
container: .container-${OS}-$(ARCH)
.container-linux-$(ARCH): bin/$(BIN)-$(OS)-$(ARCH)
docker buildx build --pull --output=type=${OUTPUT_TYPE} --platform ${OS}/$(ARCH) \
-t $(IMAGE_WITH_OS_ARCH):$(TAG) --build-arg BASE=${BASE} --build-arg ARCH=$(ARCH) .
touch $@ touch $@
push: .push-$(ARCH) .container-windows-$(ARCH): $(foreach binary, ${BIN}, bin/${binary}-${OS}-${ARCH})
.push-$(ARCH): .container-$(ARCH) docker buildx build --pull --output=type=${OUTPUT_TYPE} --platform ${OS}/$(ARCH) \
docker push $(IMAGE_WITH_ARCH):$(TAG) -t $(IMAGE_WITH_OS_ARCH)-${OSVERSION}:$(TAG) --build-arg BASE=${BASE}:${OSVERSION} --build-arg ARCH=$(ARCH) -f Dockerfile_windows .
touch $@ touch $@
# Useful for testing, not automatically included in container image # Useful for testing, not automatically included in container image
orphan: bin/orphan-$(ARCH) orphan: bin/orphan-linux-$(ARCH)
bin/orphan-$(ARCH): orphan.c bin/orphan-linux-$(ARCH): linux/orphan.c
mkdir -p bin mkdir -p bin
docker run -u $$(id -u):$$(id -g) -v $$(pwd):/build \ docker run -u $$(id -u):$$(id -g) -v $$(pwd):/build \
$(KUBE_CROSS_IMAGE):$(KUBE_CROSS_VERSION) \ $(KUBE_CROSS_IMAGE):$(KUBE_CROSS_VERSION) \
@ -106,4 +147,4 @@ bin/orphan-$(ARCH): orphan.c
$(TRIPLE)-strip $@" $(TRIPLE)-strip $@"
clean: clean:
rm -rf .container-* .push-* bin/ rm -rf .*-container-* .push-* bin/

View File

@ -16,4 +16,5 @@ steps:
- '-c' - '-c'
- | - |
gcloud auth configure-docker \ gcloud auth configure-docker \
&& docker buildx create --name img-builder --use \
&& make all-push && make all-push

View File

@ -0,0 +1,49 @@
/*
Copyright 2020 The Kubernetes 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.
*/
#include <windows.h>
#include <stdio.h>
BOOL WINAPI CtrlHandler(DWORD fdwCtrlType)
{
switch (fdwCtrlType)
{
case CTRL_C_EVENT:
fprintf(stderr, "Shutting down, got signal\n");
exit(0);
case CTRL_BREAK_EVENT:
fprintf(stderr, "Shutting down, got signal\n");
exit(0);
default:
return FALSE;
}
}
int main(void)
{
if (SetConsoleCtrlHandler(CtrlHandler, TRUE))
{
Sleep(INFINITE);
}
else
{
printf("\nERROR: Could not set control handler\n");
return 1;
}
return 0;
}

View File

@ -0,0 +1,28 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
go_library(
name = "go_default_library",
srcs = ["wincat.go"],
importpath = "k8s.io/kubernetes/build/pause/windows/wincat",
visibility = ["//visibility:private"],
)
go_binary(
name = "windows",
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,78 @@
/*
Copyright 2020 The Kubernetes 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.
*/
// package main connects to the given host and port and redirects its stdin to the connection and
// the connection's output to stdout. This is currently being used for port-forwarding for Windows Pods.
package main
import (
"fmt"
"io"
"log"
"net"
"os"
"sync"
)
func main() {
if len(os.Args) != 3 {
log.Fatalln("usage: wincat <host> <port>")
}
host := os.Args[1]
port := os.Args[2]
addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%s", host, port))
if err != nil {
log.Fatalf("Failed to resolve TCP addr %v %v", host, port)
}
conn, err := net.DialTCP("tcp", nil, addr)
if err != nil {
log.Fatalf("Failed to connect to %s:%s because %s", host, port, err)
}
defer conn.Close()
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer func() {
os.Stdout.Close()
os.Stdin.Close()
conn.CloseRead()
wg.Done()
}()
_, err := io.Copy(os.Stdout, conn)
if err != nil {
log.Printf("error while copying stream to stdout: %v", err)
}
}()
go func() {
defer func() {
conn.CloseWrite()
wg.Done()
}()
_, err := io.Copy(conn, os.Stdin)
if err != nil {
log.Printf("error while copying stream from stdin: %v", err)
}
}()
wg.Wait()
}