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 <davanum@gmail.com>
This commit is contained in:
Davanum Srinivas 2020-05-16 20:17:23 -04:00
parent 0f23eef0c8
commit c225d13abc
No known key found for this signature in database
GPG Key ID: 80D83A796103BF59
13 changed files with 232 additions and 35 deletions

View File

@ -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",
],

View File

@ -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/

View File

@ -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 "<etcd-version>-<revision>".
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)

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 = ["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"],
)

View File

@ -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)
}
}

View File

@ -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 \

View File

@ -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"],
)

View File

@ -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
}

View File

@ -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)

View File

@ -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
}

View File

@ -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)
}

View File

@ -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")
}

2
go.mod
View File

@ -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