Repository: kubernetes/minikube
Pull request #16132 (2023-03-22 18:48:44)

CI: Auto update metrics-server addon
Added a GitHub Action that runs on a cron, it checks for an update to the metrics-server addon image.



Patch:
diff --git a/.github/workflows/update-metrics-server-version.yml b/.github/workflows/update-metrics-server-version.yml
new file mode 100644
index 000000000..c7a3279ac
--- /dev/null
+++ b/.github/workflows/update-metrics-server-version.yml
@@ -0,0 +1,47 @@
+name: "update-metrics-server-version"
+on:
+  workflow_dispatch:
+  schedule:
+    # every Monday at around 3 am pacific/10 am UTC
+    - cron: "0 10 * * 1"
+env:
+  GOPROXY: https://proxy.golang.org
+  GO_VERSION: '1.20.2'
+permissions:
+  contents: read
+
+jobs:
+  bump-metrics-server-version:
+    runs-on: ubuntu-20.04
+    steps:
+      - uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f
+      - uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9
+        with:
+          go-version: ${{env.GO_VERSION}}
+          cache-dependency-path: ./go.sum
+      - name: Bump metrics-server version
+        id: bumpMetricsServer
+        run: |
+          make update-metrics-server-version
+          # The following is to support multiline with GITHUB_OUTPUT, see https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings
+          echo "changes<<EOF" >> $GITHUB_OUTPUT
+          echo "$(git status --porcelain)" >> $GITHUB_OUTPUT
+          echo "EOF" >> $GITHUB_OUTPUT
+      - name: Create PR
+        if: ${{ steps.bumpMetricsServer.outputs.changes != '' }}
+        uses: peter-evans/create-pull-request@38e0b6e68b4c852a5500a94740f0e535e0d7ba54
+        with:
+          token: ${{ secrets.MINIKUBE_BOT_PAT }}
+          commit-message: bump metrics-server version
+          committer: minikube-bot <minikube-bot@google.com>
+          author: minikube-bot <minikube-bot@google.com>
+          branch: auto_bump_metrics_server_version
+          push-to-fork: minikube-bot/minikube
+          base: master
+          delete-branch: true
+          title: 'bump metrics-server version'
+          labels: ok-to-test
+          body: |
+            metrics-server project released a [new version](https://github.com/kubernetes-sigs/metrics-server),
+
+            This PR was auto-generated by `make update-metrics-server-version` using [update-metrics-server-version.yml](https://github.com/kubernetes/minikube/tree/master/.github/workflows/update-metrics-server-version.yml) CI Workflow.
diff --git a/Makefile b/Makefile
index c96e23583..3716b236c 100644
--- a/Makefile
+++ b/Makefile
@@ -1092,6 +1092,11 @@ update-cri-o-version:
 	(cd hack/update/cri-o_version && \
 	 go run update_cri-o_version.go)
 
+.PHONY: update-metrics-server-version
+update-metrics-server-version:
+	(cd hack/update/metrics_server_version && \
+	 go run update_metrics_server_version.go)
+
 .PHONY: generate-licenses
 generate-licenses:
 	./hack/generate_licenses.sh
diff --git a/go.mod b/go.mod
index 1d9e60f42..7c36f4267 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,7 @@ module k8s.io/minikube
 go 1.20
 
 require (
-	cloud.google.com/go/storage v1.30.1
+	cloud.google.com/go/storage v1.30.0
 	contrib.go.opencensus.io/exporter/stackdriver v0.13.14
 	github.com/Delta456/box-cli-maker/v2 v2.3.0
 	github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v1.12.0
@@ -36,7 +36,7 @@ require (
 	github.com/klauspost/cpuid v1.2.0
 	github.com/machine-drivers/docker-machine-driver-vmware v0.1.5
 	github.com/mattbaird/jsonpatch v0.0.0-20200820163806-098863c1fc24
-	github.com/mattn/go-isatty v0.0.18
+	github.com/mattn/go-isatty v0.0.17
 	github.com/mitchellh/go-ps v1.0.0
 	github.com/moby/hyperkit v0.0.0-20210108224842-2f061e447e14
 	github.com/moby/sys/mount v0.2.0 // indirect
@@ -228,7 +228,7 @@ require (
 	golang.org/x/tools v0.6.0 // indirect
 	golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
-	google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 // indirect
+	google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect
 	google.golang.org/grpc v1.53.0 // indirect
 	google.golang.org/protobuf v1.29.1 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
diff --git a/go.sum b/go.sum
index 3a00c686c..21eb9c74c 100644
--- a/go.sum
+++ b/go.sum
@@ -182,8 +182,8 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f
 cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
 cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc=
 cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s=
-cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM=
-cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E=
+cloud.google.com/go/storage v1.30.0 h1:g1yrbxAWOrvg/594228pETWkOi00MLTrOWfh56veU5o=
+cloud.google.com/go/storage v1.30.0/go.mod h1:xAVretHSROm1BQX4IIsoVgJqw0LqOyX+I/O2GzRAzdE=
 cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw=
 cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g=
 cloud.google.com/go/trace v1.8.0 h1:GFPLxbp5/FzdgTzor3nlNYNxMd6hLmzkE7sA9F0qQcA=
@@ -1160,8 +1160,8 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA
 github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
 github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
-github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
+github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
 github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
 github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
 github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
@@ -2342,8 +2342,8 @@ google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqw
 google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
 google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
 google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s=
-google.golang.org/genproto v0.0.0-20230320184635-7606e756e683 h1:khxVcsk/FhnzxMKOyD+TDGwjbEOpcPuIpmafPGFmhMA=
-google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
+google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA=
+google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s=
 google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
diff --git a/hack/update/golang_version/update_golang_version.go b/hack/update/golang_version/update_golang_version.go
index 1b791c300..0a489f8e0 100644
--- a/hack/update/golang_version/update_golang_version.go
+++ b/hack/update/golang_version/update_golang_version.go
@@ -145,6 +145,11 @@ var (
 				`GO_VERSION: .*`: `GO_VERSION: '{{.StableVersion}}'`,
 			},
 		},
+		".github/workflows/update-metrics-server-version.yml": {
+			Replace: map[string]string{
+				`GO_VERSION: .*`: `GO_VERSION: '{{.StableVersion}}'`,
+			},
+		},
 		".github/workflows/sync-minikube.yml": {
 			Replace: map[string]string{
 				`GO_VERSION: .*`: `GO_VERSION: '{{.StableVersion}}'`,
diff --git a/hack/update/metrics_server_version/update_metrics_server_version.go b/hack/update/metrics_server_version/update_metrics_server_version.go
new file mode 100644
index 000000000..0883e371c
--- /dev/null
+++ b/hack/update/metrics_server_version/update_metrics_server_version.go
@@ -0,0 +1,61 @@
+/*
+Copyright 2023 The Kubernetes Authors All rights reserved.
+
+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 (
+	"context"
+	"fmt"
+	"time"
+
+	"k8s.io/klog/v2"
+
+	"k8s.io/minikube/hack/update"
+)
+
+const cxTimeout = 5 * time.Minute
+
+var schema = map[string]update.Item{
+	"pkg/minikube/assets/addons.go": {
+		Replace: map[string]string{
+			`metrics-server/metrics-server:.*`: `metrics-server/metrics-server:{{.Version}}@{{.SHA}}",`,
+		},
+	},
+}
+
+type Data struct {
+	Version string
+	SHA     string
+}
+
+func main() {
+	ctx, cancel := context.WithTimeout(context.Background(), cxTimeout)
+	defer cancel()
+
+	stable, err := update.StableVersion(ctx, "kubernetes-sigs", "metrics-server")
+	if err != nil {
+		klog.Fatalf("Unable to get metrics-server stable version: %v", err)
+	}
+	sha, err := update.GetImageSHA(fmt.Sprintf("registry.k8s.io/metrics-server/metrics-server:%s", stable))
+	if err != nil {
+		klog.Fatalf("failed to get image SHA: %v", err)
+	}
+
+	data := Data{Version: stable, SHA: sha}
+	klog.Infof("metrics-server stable version: %s", data.Version)
+
+	update.Apply(schema, data)
+}
diff --git a/pkg/minikube/cruntime/containerd.go b/pkg/minikube/cruntime/containerd.go
index 58633d8f4..4763e3759 100644
--- a/pkg/minikube/cruntime/containerd.go
+++ b/pkg/minikube/cruntime/containerd.go
@@ -462,13 +462,11 @@ func (r *Containerd) CGroupDriver() (string, error) {
 
 // KubeletOptions returns kubelet options for a containerd
 func (r *Containerd) KubeletOptions() map[string]string {
-	opts := map[string]string{
+	return map[string]string{
+		"container-runtime":          "remote",
 		"container-runtime-endpoint": fmt.Sprintf("unix://%s", r.SocketPath()),
+		"image-service-endpoint":     fmt.Sprintf("unix://%s", r.SocketPath()),
 	}
-	if r.KubernetesVersion.LT(semver.MustParse("1.24.0-alpha.0")) {
-		opts["container-runtime"] = "remote"
-	}
-	return opts
 }
 
 // ListContainers returns a list of managed by this container runtime
diff --git a/pkg/minikube/cruntime/cri.go b/pkg/minikube/cruntime/cri.go
index 448099e5d..bfa4964f2 100644
--- a/pkg/minikube/cruntime/cri.go
+++ b/pkg/minikube/cruntime/cri.go
@@ -247,7 +247,9 @@ func stopCRIContainers(cr CommandRunner, ids []string) error {
 // populateCRIConfig sets up /etc/crictl.yaml
 func populateCRIConfig(cr CommandRunner, socket string) error {
 	cPath := "/etc/crictl.yaml"
-	tmpl := "runtime-endpoint: unix://{{.Socket}}\n"
+	tmpl := `runtime-endpoint: unix://{{.Socket}}
+image-endpoint: unix://{{.Socket}}
+`
 	t, err := template.New("crictl").Parse(tmpl)
 	if err != nil {
 		return err
diff --git a/pkg/minikube/cruntime/crio.go b/pkg/minikube/cruntime/crio.go
index 930aae5eb..0b38b200c 100644
--- a/pkg/minikube/cruntime/crio.go
+++ b/pkg/minikube/cruntime/crio.go
@@ -358,13 +358,11 @@ func (r *CRIO) CGroupDriver() (string, error) {
 
 // KubeletOptions returns kubelet options for a runtime.
 func (r *CRIO) KubeletOptions() map[string]string {
-	opts := map[string]string{
-		"container-runtime-endpoint": fmt.Sprintf("unix://%s", r.SocketPath()),
+	return map[string]string{
+		"container-runtime":          "remote",
+		"container-runtime-endpoint": r.SocketPath(),
+		"image-service-endpoint":     r.SocketPath(),
 	}
-	if r.KubernetesVersion.LT(semver.MustParse("1.24.0-alpha.0")) {
-		opts["container-runtime"] = "remote"
-	}
-	return opts
 }
 
 // ListContainers returns a list of managed by this container runtime
diff --git a/pkg/minikube/cruntime/docker.go b/pkg/minikube/cruntime/docker.go
index dd2e1fadc..17c8be302 100644
--- a/pkg/minikube/cruntime/docker.go
+++ b/pkg/minikube/cruntime/docker.go
@@ -389,13 +389,11 @@ func (r *Docker) CGroupDriver() (string, error) {
 // KubeletOptions returns kubelet options for a runtime.
 func (r *Docker) KubeletOptions() map[string]string {
 	if r.UseCRI {
-		opts := map[string]string{
-			"container-runtime-endpoint": fmt.Sprintf("unix://%s", r.SocketPath()),
+		return map[string]string{
+			"container-runtime":          "remote",
+			"container-runtime-endpoint": r.SocketPath(),
+			"image-service-endpoint":     r.SocketPath(),
 		}
-		if r.KubernetesVersion.LT(semver.MustParse("1.24.0-alpha.0")) {
-			opts["container-runtime"] = "remote"
-		}
-		return opts
 	}
 	return map[string]string{
 		"container-runtime": "docker",


Test patch:
diff --git a/pkg/minikube/cruntime/cruntime_test.go b/pkg/minikube/cruntime/cruntime_test.go
index 60e068732..56aa1cbe1 100644
--- a/pkg/minikube/cruntime/cruntime_test.go
+++ b/pkg/minikube/cruntime/cruntime_test.go
@@ -148,35 +148,30 @@ func TestCGroupDriver(t *testing.T) {
 func TestKubeletOptions(t *testing.T) {
 	var tests = []struct {
 		runtime string
-		version string
 		want    map[string]string
 	}{
-		{"docker", "1.23.0", map[string]string{"container-runtime": "docker"}},
-		{"docker", "1.24.0", map[string]string{
-			"container-runtime-endpoint": "unix:///var/run/cri-dockerd.sock",
-		}},
-		{"crio", "1.25.0", map[string]string{
-			"container-runtime-endpoint": "unix:///var/run/crio/crio.sock",
-		}},
-		{"containerd", "1.23.0", map[string]string{
+		{"docker", map[string]string{"container-runtime": "docker"}},
+		{"crio", map[string]string{
 			"container-runtime":          "remote",
-			"container-runtime-endpoint": "unix:///run/containerd/containerd.sock",
+			"container-runtime-endpoint": "/var/run/crio/crio.sock",
+			"image-service-endpoint":     "/var/run/crio/crio.sock",
 		}},
-		{"containerd", "1.24.0", map[string]string{
+		{"containerd", map[string]string{
+			"container-runtime":          "remote",
 			"container-runtime-endpoint": "unix:///run/containerd/containerd.sock",
+			"image-service-endpoint":     "unix:///run/containerd/containerd.sock",
 		}},
 	}
 	for _, tc := range tests {
 		t.Run(tc.runtime, func(t *testing.T) {
-			kv := semver.MustParse(tc.version)
-			r, err := New(Config{Type: tc.runtime, KubernetesVersion: kv})
+			r, err := New(Config{Type: tc.runtime})
 			if err != nil {
-				t.Fatalf("New(%s, %s): %v", tc.runtime, tc.version, err)
+				t.Fatalf("New(%s): %v", tc.runtime, err)
 			}
 
 			got := r.KubeletOptions()
 			if diff := cmp.Diff(tc.want, got); diff != "" {
-				t.Errorf("KubeletOptions(%s, %s) returned diff (-want +got):\n%s", tc.runtime, tc.version, diff)
+				t.Errorf("KubeletOptions(%s) returned diff (-want +got):\n%s", tc.runtime, diff)
 			}
 		})
 	}
diff --git a/test/integration/multinode_test.go b/test/integration/multinode_test.go
index 679b5027c..df9793a5c 100644
--- a/test/integration/multinode_test.go
+++ b/test/integration/multinode_test.go
@@ -28,11 +28,9 @@ import (
 	"path/filepath"
 	"strings"
 	"testing"
-	"time"
 
 	"k8s.io/minikube/cmd/minikube/cmd"
 	"k8s.io/minikube/pkg/minikube/config"
-	"k8s.io/minikube/pkg/util/retry"
 )
 
 // TestMultiNode tests all multi node cluster functionality
@@ -489,31 +487,20 @@ func validateDeployAppToMultiNode(ctx context.Context, t *testing.T, profile str
 	}
 
 	// resolve Pod IPs
-	resolvePodIPs := func() error {
-		rr, err := Run(t, exec.CommandContext(ctx, Target(), "kubectl", "-p", profile, "--", "get", "pods", "-o", "jsonpath='{.items[*].status.podIP}'"))
-		if err != nil {
-			err := fmt.Errorf("failed to retrieve Pod IPs (may be temporary): %v", err)
-			t.Logf(err.Error())
-			return err
-		}
-		podIPs := strings.Split(strings.Trim(rr.Stdout.String(), "'"), " ")
-		if len(podIPs) != 2 {
-			err := fmt.Errorf("expected 2 Pod IPs but got %d (may be temporary), output: %q", len(podIPs), rr.Output())
-			t.Logf(err.Error())
-			return err
-		} else if podIPs[0] == podIPs[1] {
-			err := fmt.Errorf("expected 2 different pod IPs but got %s and %s (may be temporary), output: %q", podIPs[0], podIPs[1], rr.Output())
-			t.Logf(err.Error())
-			return err
-		}
-		return nil
+	rr, err := Run(t, exec.CommandContext(ctx, Target(), "kubectl", "-p", profile, "--", "get", "pods", "-o", "jsonpath='{.items[*].status.podIP}'"))
+	if err != nil {
+		t.Errorf("failed to retrieve Pod IPs")
 	}
-	if err := retry.Expo(resolvePodIPs, 1*time.Second, Seconds(120)); err != nil {
-		t.Errorf("failed to resolve pod IPs: %v", err)
+	podIPs := strings.Split(strings.Trim(rr.Stdout.String(), "'"), " ")
+	if len(podIPs) != 2 {
+		t.Errorf("expected 2 Pod IPs but got %d, output: %q", len(podIPs), rr.Output())
+	} else if podIPs[0] == podIPs[1] {
+		t.Errorf("expected 2 different pod IPs but got %s and %s. output: %q", podIPs[0], podIPs[1], rr.Output())
+
 	}
 
 	// get Pod names
-	rr, err := Run(t, exec.CommandContext(ctx, Target(), "kubectl", "-p", profile, "--", "get", "pods", "-o", "jsonpath='{.items[*].metadata.name}'"))
+	rr, err = Run(t, exec.CommandContext(ctx, Target(), "kubectl", "-p", profile, "--", "get", "pods", "-o", "jsonpath='{.items[*].metadata.name}'"))
 	if err != nil {
 		t.Errorf("failed get Pod names")
 	}