Change:
<!-- Please only use this template for submitting enhancement requests --What would you like to be modified: image to be based on anything other than Docker Hub sourced Why is this needed: With Docker Hub rate-limit policy in-place, we probably should consider removing this dependency to stay in sync with other base images in Kubernetes project. Folks building their own binaries (i.e. with ) might run into this as well. Notes: Prior discussion happened on An idea from is to use the should probably be renamed to avoid confusion with k/release (h/t Currently, is set to , so migrating to may not be a drop-in move However, , so maybe we don't have to start from scratch /sig testing /area conformance /sig release (cc'ing because builds conformance image, though my quick search seem to show there isn't any build pipelines referencing )
/assign
do we still want to do this? I read somewhere that the images built in Google Cloud are being mirrored from Docker Hub, right? This would mean that the API rate limiting will not hit us any more.
Womp yeah I think DockerHub rate limit is not really the big motivator at this point. However, I think I still want to consider using distroless / go-runner to build and produce conformance image to reduce the noise from CVE scanning done in downstream places. What do you think?
Yeah I think this seems a valuable addition. Are you planning to work on this issue? :)
I will, though probably won't start until next week. If you have ideas and would like to start early feel free to go for it! Otherwise, I'd be happy to work on and deliver this.
Thank you Wilson! Feel free to ping again if you need any assistance. /assign
/triage accepted
one thing I need a little help with is to find a reference for using go-runner image that's used everywhere -- the one that I've found is inside conformance directory which seems to be different from what everyone else is using
We maintain a go-runner in k/release:
oops, I forgot to get back on this last week -- I meant to say that I need a reference for image which I can use as , so something like on Dockerfile. Is that a possible thing to do?
after searching around, I found this -- going to try and use and see how it works :smile:
Started a PR -- plenty of things I'd like to be discussed but we should probably have the discussions there
Issues go stale after 90d of inactivity. Mark the issue as fresh with . Stale issues rot after an additional 30d of inactivity and eventually close. If this issue is safe to close now please do so with . Send feedback to sig-contributor-experience at . /lifecycle stale
/remove-lifecycle stale there is work in progress

Discussion:
# limitations under the License. ARG BASEIMAGE <ins> ARG RUNNERIMAGE </ins> <del> FROM ${BASEIMAGE} </del> <ins> FROM ${BASEIMAGE} as debbase FROM ${RUNNERIMAGE} # This is a dependency for `kubectl diff` tests COPY --from=debbase /usr/bin/diff /usr/local/bin/ COPY cluster /kubernetes/cluster </ins> COPY ginkgo /usr/local/bin/ COPY e2e.test /usr/local/bin/ COPY kubectl /usr/local/bin/ <del> COPY run_e2e.sh /run_e2e.sh </del> <ins> COPY gorunner /usr/local/bin/kubeconformance # Legacy executables -- deprecated COPY gorunner /run_e2e.sh </ins> COPY gorunner /gorunner <del> COPY cluster /kubernetes/cluster WORKDIR /usr/local/bin </del> ENV E2E_FOCUS="[Conformance]" ENV E2E_SKIP=""

ENV RESULTS_DIR="/tmp/results" ENV KUBECONFIG="" <del> CMD [ "/bin/bash", "-c", "/run_e2e.sh" ] </del> <ins> ENTRYPOINT [ "kubeconformance" ] </ins>

CLUSTER_DIR?=$(shell pwd)/../../../cluster/ <del> BASEIMAGE=debian:stable-slim TEMP_DIR:=$(shell mktemp -d -t conformanceXXXXXX) </del> <ins> # This is defined in root Makefile, but some build contexts do not refer to them KUBE_BASE_IMAGE_REGISTRY?=k8s.gcr.io ifeq ($(ARCH),amd64) BASEIMAGE?=${KUBE_BASE_IMAGE_REGISTRY}/build-image/debian-base:v2.1.3 else BASEIMAGE?=${KUBE_BASE_IMAGE_REGISTRY}/build-image/debian-base-${ARCH}:v2.1.3 endif RUNNERIMAGE?=gcr.io/distroless/base:latest TEMP_DIR:=$(shell mktemp -d -t conformance-XXXXXX) </ins> all: build

--pull  -t ${REGISTRY}/conformance-${ARCH}:${VERSION}  --build-arg BASEIMAGE=$(BASEIMAGE)  <ins> --build-arg RUNNERIMAGE=$(RUNNERIMAGE)  </ins> ${TEMP_DIR} rm -rf "${TEMP_DIR}"

<del> /* Copyright 2019 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" "io/ioutil" "log" "os" "os/signal" "path/filepath" "github.com/pkg/errors" ) func main() { env := envWithDefaults(map[string]string{ resultsDirEnvKey: defaultResultsDir, skipEnvKey:       defaultSkip, focusEnvKey:      defaultFocus, providerEnvKey:   defaultProvider, parallelEnvKey:   defaultParallel, ginkgoEnvKey:     defaultGinkgoBinary, testBinEnvKey:    defaultTestBinary, }) if err := configureAndRunWithEnv(env); err != nil { log.Fatal(err) } } // configureAndRunWithEnv uses the given environment to configure and then start the test run. // It will handle TERM signals gracefully and kill the test process and will // save the logs/results to the location specified via the RESULTS_DIR environment // variable. func configureAndRunWithEnv(env Getenver) error { // Ensure we save results regardless of other errors. This helps any // consumer who may be polling for the results. resultsDir := env.Getenv(resultsDirEnvKey) defer saveResults(resultsDir) // Print the output to stdout and a logfile which will be returned // as part of the results tarball. logFilePath := filepath.Join(resultsDir, logFileName) logFile, err := os.Create(logFilePath) if err != nil { return errors.Wrapf(err, "failed to create log file %v", logFilePath) } mw := io.MultiWriter(os.Stdout, logFile) cmd := getCmd(env, mw) log.Printf("Running command:n%vn", cmdInfo(cmd)) err = cmd.Start() if err != nil { return errors.Wrap(err, "starting command") } // Handle signals and shutdown process gracefully. go setupSigHandler(cmd.Process.Pid) return errors.Wrap(cmd.Wait(), "running command") } // setupSigHandler will kill the process identified by the given PID if it // gets a TERM signal. func setupSigHandler(pid int) { c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) // Block until a signal is received. log.Println("Now listening for interrupts") s := <-c log.Printf("Got signal: %v. Shutting down test process (PID: %v)n", s, pid) p, err := os.FindProcess(pid) if err != nil { log.Printf("Could not find process %v to shut down.n", pid) return } if err := p.Signal(s); err != nil { log.Printf("Failed to signal test process to terminate: %vn", err) return } log.Printf("Signalled process %v to terminate successfully.n", pid) } // saveResults will tar the results directory and write the resulting tarball path // into the donefile. func saveResults(resultsDir string) error { log.Printf("Saving results at %vn", resultsDir) err := tarDir(resultsDir, filepath.Join(resultsDir, resultsTarballName)) if err != nil { return errors.Wrapf(err, "tar directory %v", resultsDir) } doneFile := filepath.Join(resultsDir, doneFileName) resultsTarball := filepath.Join(resultsDir, resultsTarballName) resultsTarball, err = filepath.Abs(resultsTarball) if err != nil { return errors.Wrapf(err, "failed to find absolute path for %v", resultsTarball) } return errors.Wrap( ioutil.WriteFile(doneFile, []byte(resultsTarball), os.FileMode(0777)), "writing donefile", ) } </del>

<ins> /* Copyright 2019 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" "io/ioutil" "log" "os" "os/signal" "path/filepath" "strings" "github.com/pkg/errors" ) func main() { if strings.Contains(os.Args[0], "run_e2e.sh") || strings.Contains(os.Args[0], "gorunner") { log.Print("warn: calling test with e2e.test is deprecated and will be removed in 1.25, please rely on container manifest to invoke executable") } env := envWithDefaults(map[string]string{ resultsDirEnvKey: defaultResultsDir, skipEnvKey:       defaultSkip, focusEnvKey:      defaultFocus, providerEnvKey:   defaultProvider, parallelEnvKey:   defaultParallel, ginkgoEnvKey:     defaultGinkgoBinary, testBinEnvKey:    defaultTestBinary, }) if err := configureAndRunWithEnv(env); err != nil { log.Fatal(err) } } // configureAndRunWithEnv uses the given environment to configure and then start the test run. // It will handle TERM signals gracefully and kill the test process and will // save the logs/results to the location specified via the RESULTS_DIR environment // variable. func configureAndRunWithEnv(env Getenver) error { // Ensure we save results regardless of other errors. This helps any // consumer who may be polling for the results. resultsDir := env.Getenv(resultsDirEnvKey) defer saveResults(resultsDir) // Print the output to stdout and a logfile which will be returned // as part of the results tarball. logFilePath := filepath.Join(resultsDir, logFileName) logFile, err := os.Create(logFilePath) if err != nil { return errors.Wrapf(err, "failed to create log file %v", logFilePath) } mw := io.MultiWriter(os.Stdout, logFile) cmd := getCmd(env, mw) log.Printf("Running command:n%vn", cmdInfo(cmd)) err = cmd.Start() if err != nil { return errors.Wrap(err, "starting command") } // Handle signals and shutdown process gracefully. go setupSigHandler(cmd.Process.Pid) return errors.Wrap(cmd.Wait(), "running command") } // setupSigHandler will kill the process identified by the given PID if it // gets a TERM signal. func setupSigHandler(pid int) { c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) // Block until a signal is received. log.Println("Now listening for interrupts") s := <-c log.Printf("Got signal: %v. Shutting down test process (PID: %v)n", s, pid) p, err := os.FindProcess(pid) if err != nil { log.Printf("Could not find process %v to shut down.n", pid) return } if err := p.Signal(s); err != nil { log.Printf("Failed to signal test process to terminate: %vn", err) return } log.Printf("Signalled process %v to terminate successfully.n", pid) } // saveResults will tar the results directory and write the resulting tarball path // into the donefile. func saveResults(resultsDir string) error { log.Printf("Saving results at %vn", resultsDir) err := tarDir(resultsDir, filepath.Join(resultsDir, resultsTarballName)) if err != nil { return errors.Wrapf(err, "tar directory %v", resultsDir) } doneFile := filepath.Join(resultsDir, doneFileName) resultsTarball := filepath.Join(resultsDir, resultsTarballName) resultsTarball, err = filepath.Abs(resultsTarball) if err != nil { return errors.Wrapf(err, "failed to find absolute path for %v", resultsTarball) } return errors.Wrap( ioutil.WriteFile(doneFile, []byte(resultsTarball), os.FileMode(0777)), "writing donefile", ) } </ins>