From c225d13abc453ea216050937e3f5577787b1608d Mon Sep 17 00:00:00 2001 From: Davanum Srinivas Date: Sat, 16 May 2020 20:17:23 -0400 Subject: [PATCH] Switch to static bash for etcd - use bash-static and avoid dragging in all of debian-base - use distroless as the base image - the shell script needs a `cp` utility, add a go based one for just files (no support for directories!) - Rework the calls to `mv` and recursive `cp` in the code - we don't need to support windows in this container image - the test case was slightly off as it was assuming that the old directory was copied into the new directory, but the desired functionality is that all files in the old directory should be in the new directory. Signed-off-by: Davanum Srinivas --- cluster/BUILD | 1 + cluster/images/etcd/Dockerfile | 14 +++- cluster/images/etcd/Makefile | 10 ++- cluster/images/etcd/cp/BUILD | 28 +++++++ cluster/images/etcd/cp/cp.go | 62 +++++++++++++++ cluster/images/etcd/migrate-if-needed.sh | 7 +- cluster/images/etcd/migrate/BUILD | 81 ++++++++++++++------ cluster/images/etcd/migrate/data_dir.go | 3 +- cluster/images/etcd/migrate/data_dir_test.go | 4 + cluster/images/etcd/migrate/migrator.go | 3 +- cluster/images/etcd/migrate/util_others.go | 27 +++++++ cluster/images/etcd/migrate/utils_windows.go | 25 ++++++ go.mod | 2 +- 13 files changed, 232 insertions(+), 35 deletions(-) create mode 100644 cluster/images/etcd/cp/BUILD create mode 100644 cluster/images/etcd/cp/cp.go create mode 100644 cluster/images/etcd/migrate/util_others.go create mode 100644 cluster/images/etcd/migrate/utils_windows.go diff --git a/cluster/BUILD b/cluster/BUILD index 8ae35f0eda7..cf5401cf108 100644 --- a/cluster/BUILD +++ b/cluster/BUILD @@ -17,6 +17,7 @@ filegroup( "//cluster/gce:all-srcs", "//cluster/images/conformance:all-srcs", "//cluster/images/etcd-version-monitor:all-srcs", + "//cluster/images/etcd/cp:all-srcs", "//cluster/images/etcd/migrate:all-srcs", "//cluster/images/kubemark:all-srcs", ], diff --git a/cluster/images/etcd/Dockerfile b/cluster/images/etcd/Dockerfile index d7ae7766cea..6c811ea1b98 100644 --- a/cluster/images/etcd/Dockerfile +++ b/cluster/images/etcd/Dockerfile @@ -12,8 +12,20 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM BASEIMAGE +FROM BASEIMAGE as builder + +RUN apt-get update -y \ + && apt-get -yy -q install --no-install-recommends --no-install-suggests --fix-missing \ + bash-static + +RUN cp /bin/bash-static /sh + +FROM RUNNERIMAGE +WORKDIR / + +COPY --from=builder /sh /bin/ EXPOSE 2379 2380 4001 7001 COPY etcd* etcdctl* /usr/local/bin/ +COPY cp* /bin/ COPY migrate-if-needed.sh migrate /usr/local/bin/ diff --git a/cluster/images/etcd/Makefile b/cluster/images/etcd/Makefile index 5287e1736be..49612dadfd9 100644 --- a/cluster/images/etcd/Makefile +++ b/cluster/images/etcd/Makefile @@ -34,7 +34,7 @@ LATEST_ETCD_VERSION?=3.4.7 # REVISION provides a version number fo this image and all it's bundled # artifacts. It should start at zero for each LATEST_ETCD_VERSION and increment # for each revision of this image at that etcd version. -REVISION?=1 +REVISION?=2 # IMAGE_TAG Uniquely identifies k8s.gcr.io/etcd docker image with a tag of the form "-". IMAGE_TAG=$(LATEST_ETCD_VERSION)-$(REVISION) @@ -82,6 +82,8 @@ ifeq ($(ARCH),s390x) BASEIMAGE?=us.gcr.io/k8s-artifacts-prod/build-image/debian-base-s390x:v2.1.0 endif +RUNNERIMAGE?=gcr.io/distroless/static:latest + build: # Explicitly copy files to the temp directory $(BIN_INSTALL) migrate-if-needed.sh $(TEMP_DIR) @@ -91,7 +93,10 @@ build: migrate_tmp_dir=$(shell mktemp -d); \ docker run --interactive -v $(shell pwd)/../../../:/go/src/k8s.io/kubernetes$(DOCKER_VOL_OPTS) -v $${migrate_tmp_dir}:/build$(DOCKER_VOL_OPTS) -e GOARCH=$(ARCH) golang:$(GOLANG_VERSION) \ /bin/bash -c "CGO_ENABLED=0 go build -o /build/migrate k8s.io/kubernetes/cluster/images/etcd/migrate"; \ - $(BIN_INSTALL) $${migrate_tmp_dir}/migrate $(TEMP_DIR) + $(BIN_INSTALL) $${migrate_tmp_dir}/migrate $(TEMP_DIR); \ + docker run --interactive -v $(shell pwd)/../../../:/go/src/k8s.io/kubernetes$(DOCKER_VOL_OPTS) -v $${migrate_tmp_dir}:/build$(DOCKER_VOL_OPTS) -e GOARCH=$(ARCH) golang:$(GOLANG_VERSION) \ + /bin/bash -c "CGO_ENABLED=0 go build -o /build/cp k8s.io/kubernetes/cluster/images/etcd/cp"; \ + $(BIN_INSTALL) $${migrate_tmp_dir}/cp $(TEMP_DIR); ifeq ($(ARCH),amd64) @@ -140,6 +145,7 @@ endif # Replace BASEIMAGE with the real base image cd $(TEMP_DIR) && sed -i.bak 's|BASEIMAGE|$(BASEIMAGE)|g' Dockerfile + cd $(TEMP_DIR) && sed -i.bak 's|RUNNERIMAGE|$(RUNNERIMAGE)|g' Dockerfile # And build the image docker build --pull -t $(REGISTRY)/etcd-$(ARCH):$(IMAGE_TAG) $(TEMP_DIR) diff --git a/cluster/images/etcd/cp/BUILD b/cluster/images/etcd/cp/BUILD new file mode 100644 index 00000000000..3b3d0c3ee85 --- /dev/null +++ b/cluster/images/etcd/cp/BUILD @@ -0,0 +1,28 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") + +go_library( + name = "go_default_library", + srcs = ["cp.go"], + importpath = "k8s.io/kubernetes/cluster/images/etcd/cp", + visibility = ["//visibility:private"], +) + +go_binary( + name = "cp", + 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"], +) diff --git a/cluster/images/etcd/cp/cp.go b/cluster/images/etcd/cp/cp.go new file mode 100644 index 00000000000..693b4834e75 --- /dev/null +++ b/cluster/images/etcd/cp/cp.go @@ -0,0 +1,62 @@ +/* +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 + +import ( + "io" + "log" + "os" + "path/filepath" +) + +func main() { + if len(os.Args) != 3 { + log.Fatal("Usage: cp SOURCE DEST") + } + + sf, err := os.Open(os.Args[1]) + if err != nil { + log.Fatalf("unable to open source file [%s]: %q", os.Args[1], err) + } + defer sf.Close() + fi, err := sf.Stat() + if err != nil { + log.Fatalf("unable to stat source file [%s]: %q", os.Args[1], err) + } + + dir := filepath.Dir(os.Args[2]) + if err := os.MkdirAll(dir, 0755); err != nil { + log.Fatalf("unable to create directory [%s]: %q", dir, err) + } + df, err := os.Create(os.Args[2]) + if err != nil { + log.Fatalf("unable to create destination file [%s]: %q", os.Args[1], err) + } + defer df.Close() + + _, err = io.Copy(df, sf) + if err != nil { + log.Fatalf("unable to copy [%s] to [%s]: %q", os.Args[1], os.Args[2], err) + } + + if err := df.Close(); err != nil { + log.Fatalf("unable to close destination file: %q", err) + } + if err := os.Chmod(os.Args[2], fi.Mode()); err != nil { + log.Fatalf("unable to close destination file: %q", err) + } +} diff --git a/cluster/images/etcd/migrate-if-needed.sh b/cluster/images/etcd/migrate-if-needed.sh index 501c68c8ee9..24363d77e9a 100755 --- a/cluster/images/etcd/migrate-if-needed.sh +++ b/cluster/images/etcd/migrate-if-needed.sh @@ -45,7 +45,8 @@ set -o nounset # etcd image (to make this script work correctly). BUNDLED_VERSIONS="3.0.17, 3.1.12, 3.2.24, 3.3.17, 3.4.7" -ETCD_NAME="${ETCD_NAME:-etcd-$(hostname)}" +# shellcheck disable=SC2039 +ETCD_NAME="${ETCD_NAME:-etcd-$HOSTNAME}" if [ -z "${DATA_DIRECTORY:-}" ]; then echo "DATA_DIRECTORY variable unset - unexpected failure" exit 1 @@ -87,8 +88,8 @@ ETCD_CREDS="${ETCD_CREDS:-}" # Correctly support upgrade and rollback to non-default version. if [ "${DO_NOT_MOVE_BINARIES:-}" != "true" ]; then - cp "/usr/local/bin/etcd-${TARGET_VERSION}" "/usr/local/bin/etcd" - cp "/usr/local/bin/etcdctl-${TARGET_VERSION}" "/usr/local/bin/etcdctl" + /bin/cp "/usr/local/bin/etcd-${TARGET_VERSION}" "/usr/local/bin/etcd" + /bin/cp "/usr/local/bin/etcdctl-${TARGET_VERSION}" "/usr/local/bin/etcdctl" fi /usr/local/bin/migrate \ diff --git a/cluster/images/etcd/migrate/BUILD b/cluster/images/etcd/migrate/BUILD index 7a47bcd2fc7..9d39ea3b507 100644 --- a/cluster/images/etcd/migrate/BUILD +++ b/cluster/images/etcd/migrate/BUILD @@ -1,16 +1,4 @@ -package(default_visibility = ["//visibility:public"]) - -load( - "@io_bazel_rules_go//go:def.bzl", - "go_binary", - "go_library", - "go_test", -) - -go_binary( - name = "migrate", - embed = [":go_default_library"], -) +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test") go_library( name = "go_default_library", @@ -20,9 +8,12 @@ go_library( "migrate_client.go", "migrate_server.go", "migrator.go", + "util_others.go", + "utils_windows.go", "versions.go", ], importpath = "k8s.io/kubernetes/cluster/images/etcd/migrate", + visibility = ["//visibility:private"], deps = [ "//vendor/github.com/blang/semver:go_default_library", "//vendor/github.com/spf13/cobra:go_default_library", @@ -30,7 +21,59 @@ go_library( "//vendor/go.etcd.io/etcd/clientv3:go_default_library", "//vendor/google.golang.org/grpc:go_default_library", "//vendor/k8s.io/klog/v2:go_default_library", + ] + select({ + "@io_bazel_rules_go//go/platform:android": [ + "//vendor/github.com/mrunalp/fileutils:go_default_library", + ], + "@io_bazel_rules_go//go/platform:darwin": [ + "//vendor/github.com/mrunalp/fileutils:go_default_library", + ], + "@io_bazel_rules_go//go/platform:dragonfly": [ + "//vendor/github.com/mrunalp/fileutils:go_default_library", + ], + "@io_bazel_rules_go//go/platform:freebsd": [ + "//vendor/github.com/mrunalp/fileutils:go_default_library", + ], + "@io_bazel_rules_go//go/platform:ios": [ + "//vendor/github.com/mrunalp/fileutils:go_default_library", + ], + "@io_bazel_rules_go//go/platform:linux": [ + "//vendor/github.com/mrunalp/fileutils:go_default_library", + ], + "@io_bazel_rules_go//go/platform:nacl": [ + "//vendor/github.com/mrunalp/fileutils:go_default_library", + ], + "@io_bazel_rules_go//go/platform:netbsd": [ + "//vendor/github.com/mrunalp/fileutils:go_default_library", + ], + "@io_bazel_rules_go//go/platform:openbsd": [ + "//vendor/github.com/mrunalp/fileutils:go_default_library", + ], + "@io_bazel_rules_go//go/platform:plan9": [ + "//vendor/github.com/mrunalp/fileutils:go_default_library", + ], + "@io_bazel_rules_go//go/platform:solaris": [ + "//vendor/github.com/mrunalp/fileutils:go_default_library", + ], + "//conditions:default": [], + }), +) + +go_binary( + name = "migrate", + embed = [":go_default_library"], + visibility = ["//visibility:public"], +) + +go_test( + name = "go_default_test", + srcs = [ + "data_dir_test.go", + "versions_test.go", ], + data = glob(["testdata/**"]), + embed = [":go_default_library"], + deps = ["//vendor/github.com/blang/semver:go_default_library"], ) filegroup( @@ -44,15 +87,5 @@ filegroup( name = "all-srcs", srcs = [":package-srcs"], tags = ["automanaged"], -) - -go_test( - name = "go_default_test", - srcs = [ - "data_dir_test.go", - "versions_test.go", - ], - data = glob(["testdata/**"]), - embed = [":go_default_library"], - deps = ["//vendor/github.com/blang/semver:go_default_library"], + visibility = ["//visibility:public"], ) diff --git a/cluster/images/etcd/migrate/data_dir.go b/cluster/images/etcd/migrate/data_dir.go index f9fc5069ff4..83bfd628f06 100644 --- a/cluster/images/etcd/migrate/data_dir.go +++ b/cluster/images/etcd/migrate/data_dir.go @@ -21,7 +21,6 @@ import ( "io" "io/ioutil" "os" - "os/exec" "path/filepath" "strings" @@ -88,7 +87,7 @@ func (d *DataDirectory) Backup() error { if err != nil { return err } - err = exec.Command("cp", "-r", d.path, backupDir).Run() + err = copyDirectory(d.path, backupDir) if err != nil { return err } diff --git a/cluster/images/etcd/migrate/data_dir_test.go b/cluster/images/etcd/migrate/data_dir_test.go index 23081ca8a1b..0d8ac4b7f7c 100644 --- a/cluster/images/etcd/migrate/data_dir_test.go +++ b/cluster/images/etcd/migrate/data_dir_test.go @@ -132,6 +132,10 @@ func TestBackup(t *testing.T) { if err != nil { t.Fatalf("Failed to open data dir: %v", err) } + _, err = os.Create(filepath.Join(path, "data-dir", "empty.txt")) + if err != nil { + t.Fatal(err) + } err = d.Backup() if err != nil { t.Fatalf("Failed to backup data directory %s: %v", d.path, err) diff --git a/cluster/images/etcd/migrate/migrator.go b/cluster/images/etcd/migrate/migrator.go index 0a5cf8281b4..ffb0f0d5a3f 100644 --- a/cluster/images/etcd/migrate/migrator.go +++ b/cluster/images/etcd/migrate/migrator.go @@ -19,7 +19,6 @@ package main import ( "fmt" "os" - "os/exec" "time" "github.com/blang/semver" @@ -159,7 +158,7 @@ func (m *Migrator) rollbackEtcd3MinorVersion(current *EtcdVersionPair, target *E if err != nil { return nil, err } - err = exec.Command("mv", m.dataDirectory.path, backupDir).Run() + err = os.Rename(m.dataDirectory.path, backupDir) if err != nil { return nil, err } diff --git a/cluster/images/etcd/migrate/util_others.go b/cluster/images/etcd/migrate/util_others.go new file mode 100644 index 00000000000..a25dc5c2078 --- /dev/null +++ b/cluster/images/etcd/migrate/util_others.go @@ -0,0 +1,27 @@ +// +build !windows + +/* +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 + +import ( + "github.com/mrunalp/fileutils" +) + +func copyDirectory(source string, dest string) error { + return fileutils.CopyDirectory(source, dest) +} diff --git a/cluster/images/etcd/migrate/utils_windows.go b/cluster/images/etcd/migrate/utils_windows.go new file mode 100644 index 00000000000..35ac1ef356e --- /dev/null +++ b/cluster/images/etcd/migrate/utils_windows.go @@ -0,0 +1,25 @@ +// +build windows + +/* +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 + +import "fmt" + +func copyDirectory(source string, dest string) error { + return fmt.Errorf("no support for windows") +} diff --git a/go.mod b/go.mod index 86b4ee9f149..a7c1c0c2d22 100644 --- a/go.mod +++ b/go.mod @@ -70,7 +70,7 @@ require ( github.com/miekg/dns v1.1.4 github.com/moby/ipvs v1.0.1 github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb // indirect - github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618 // indirect + github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 github.com/mvdan/xurls v1.1.0 github.com/onsi/ginkgo v1.11.0