Merge pull request #17144 from rifelpet/warmpool-containerproxy

Normalize the hardcoded images used for warmpool pre-pulling
This commit is contained in:
Kubernetes Prow Robot 2025-07-16 04:22:26 -07:00 committed by GitHub
commit 6ac7fcc2fa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 132 additions and 173 deletions

View File

@ -144,7 +144,7 @@ func (a *AssetBuilder) RemapManifest(data []byte) ([]byte, error) {
} }
// RemapImage normalizes a containers location if a user sets the AssetsLocation ContainerRegistry location. // RemapImage normalizes a containers location if a user sets the AssetsLocation ContainerRegistry location.
func (a *AssetBuilder) RemapImage(image string) (string, error) { func (a *AssetBuilder) RemapImage(image string) string {
asset := &ImageAsset{ asset := &ImageAsset{
DownloadLocation: image, DownloadLocation: image,
CanonicalLocation: image, CanonicalLocation: image,
@ -179,66 +179,27 @@ func (a *AssetBuilder) RemapImage(image string) (string, error) {
} }
} }
if a.AssetsLocation != nil && a.AssetsLocation.ContainerProxy != nil { normalized := NormalizeImage(a, image)
containerProxy := strings.TrimSuffix(*a.AssetsLocation.ContainerProxy, "/") image = normalized
normalized := image asset.DownloadLocation = normalized
// If the image name contains only a single / we need to determine if the image is located on docker-hub or if it's using a convenient URL,
// like registry.k8s.io/<image-name> or registry.k8s.io/<image-name>
// In case of a hub image it should be sufficient to just prepend the proxy url, producing eg docker-proxy.example.com/weaveworks/weave-kube
if strings.Count(normalized, "/") <= 1 && !strings.ContainsAny(strings.Split(normalized, "/")[0], ".:") {
normalized = containerProxy + "/" + normalized
} else {
re := regexp.MustCompile(`^[^/]+`)
normalized = re.ReplaceAllString(normalized, containerProxy)
}
asset.DownloadLocation = normalized
// Run the new image
image = asset.DownloadLocation
}
if a.AssetsLocation != nil && a.AssetsLocation.ContainerRegistry != nil {
registryMirror := *a.AssetsLocation.ContainerRegistry
normalized := image
// Remove the 'standard' kubernetes image prefixes, just for sanity
normalized = strings.TrimPrefix(normalized, "registry.k8s.io/")
// When assembling the cluster spec, kops may call the option more then once until the config converges
// This means that this function may me called more than once on the same image
// It this is pass is the second one, the image will already have been normalized with the containerRegistry settings
// If this is the case, passing though the process again will re-prepend the container registry again
// and again, causing the spec to never converge and the config build to fail.
if !strings.HasPrefix(normalized, registryMirror+"/") {
// We can't nest arbitrarily
// Some risk of collisions, but also -- and __ in the names appear to be blocked by docker hub
normalized = strings.Replace(normalized, "/", "-", -1)
asset.DownloadLocation = registryMirror + "/" + normalized
}
// Run the new image
image = asset.DownloadLocation
}
a.ImageAssets = append(a.ImageAssets, asset) a.ImageAssets = append(a.ImageAssets, asset)
if !featureflag.ImageDigest.Enabled() || os.Getenv("KOPS_BASE_URL") != "" { if !featureflag.ImageDigest.Enabled() || os.Getenv("KOPS_BASE_URL") != "" {
return image, nil return image
} }
if strings.Contains(image, "@") { if strings.Contains(image, "@") {
return image, nil return image
} }
digest, err := crane.Digest(image, crane.WithAuthFromKeychain(authn.DefaultKeychain)) digest, err := crane.Digest(image, crane.WithAuthFromKeychain(authn.DefaultKeychain))
if err != nil { if err != nil {
klog.Warningf("failed to digest image %q: %s", image, err) klog.Warningf("failed to digest image %q: %s", image, err)
return image, nil return image
} }
return image + "@" + digest, nil return image + "@" + digest
} }
// RemapFile returns a remapped URL for the file, if AssetsLocation is defined. // RemapFile returns a remapped URL for the file, if AssetsLocation is defined.
@ -378,3 +339,46 @@ func (a *AssetBuilder) remapURL(canonicalURL *url.URL) (*url.URL, error) {
return fileRepo, nil return fileRepo, nil
} }
func NormalizeImage(a *AssetBuilder, image string) string {
if a.AssetsLocation != nil && a.AssetsLocation.ContainerProxy != nil {
containerProxy := strings.TrimSuffix(*a.AssetsLocation.ContainerProxy, "/")
normalized := image
// If the image name contains only a single / we need to determine if the image is located on docker-hub or if it's using a convenient URL,
// like registry.k8s.io/<image-name> or registry.k8s.io/<image-name>
// In case of a hub image it should be sufficient to just prepend the proxy url, producing eg docker-proxy.example.com/weaveworks/weave-kube
if strings.Count(normalized, "/") <= 1 && !strings.ContainsAny(strings.Split(normalized, "/")[0], ".:") {
normalized = containerProxy + "/" + normalized
} else {
re := regexp.MustCompile(`^[^/]+`)
normalized = re.ReplaceAllString(normalized, containerProxy)
}
// Run the new image
image = normalized
}
if a.AssetsLocation != nil && a.AssetsLocation.ContainerRegistry != nil {
registryMirror := *a.AssetsLocation.ContainerRegistry
normalized := image
// Remove the 'standard' kubernetes image prefixes, just for sanity
normalized = strings.TrimPrefix(normalized, "registry.k8s.io/")
// When assembling the cluster spec, kops may call the option more then once until the config converges
// This means that this function may me called more than once on the same image
// It this is pass is the second one, the image will already have been normalized with the containerRegistry settings
// If this is the case, passing though the process again will re-prepend the container registry again
// and again, causing the spec to never converge and the config build to fail.
if !strings.HasPrefix(normalized, registryMirror+"/") {
// We can't nest arbitrarily
// Some risk of collisions, but also -- and __ in the names appear to be blocked by docker hub
normalized = strings.Replace(normalized, "/", "-", -1)
normalized = registryMirror + "/" + normalized
}
image = normalized
}
// Run the new image
return image
}

View File

@ -42,11 +42,7 @@ func TestValidate_RemapImage_ContainerProxy_AppliesToDockerHub(t *testing.T) {
builder.AssetsLocation.ContainerProxy = &proxyURL builder.AssetsLocation.ContainerProxy = &proxyURL
remapped, err := builder.RemapImage(image) remapped := builder.RemapImage(image)
if err != nil {
t.Error("Error remapping image", err)
}
if remapped != expected { if remapped != expected {
t.Errorf("Error remapping image (Expecting: %s, got %s)", expected, remapped) t.Errorf("Error remapping image (Expecting: %s, got %s)", expected, remapped)
} }
@ -61,11 +57,7 @@ func TestValidate_RemapImage_ContainerProxy_AppliesToSimplifiedDockerHub(t *test
builder.AssetsLocation.ContainerProxy = &proxyURL builder.AssetsLocation.ContainerProxy = &proxyURL
remapped, err := builder.RemapImage(image) remapped := builder.RemapImage(image)
if err != nil {
t.Error("Error remapping image", err)
}
if remapped != expected { if remapped != expected {
t.Errorf("Error remapping image (Expecting: %s, got %s)", expected, remapped) t.Errorf("Error remapping image (Expecting: %s, got %s)", expected, remapped)
} }
@ -80,11 +72,7 @@ func TestValidate_RemapImage_ContainerProxy_AppliesToSimplifiedKubernetesURL(t *
builder.AssetsLocation.ContainerProxy = &proxyURL builder.AssetsLocation.ContainerProxy = &proxyURL
remapped, err := builder.RemapImage(image) remapped := builder.RemapImage(image)
if err != nil {
t.Error("Error remapping image", err)
}
if remapped != expected { if remapped != expected {
t.Errorf("Error remapping image (Expecting: %s, got %s)", expected, remapped) t.Errorf("Error remapping image (Expecting: %s, got %s)", expected, remapped)
} }
@ -99,11 +87,7 @@ func TestValidate_RemapImage_ContainerProxy_AppliesToLegacyKubernetesURL(t *test
builder.AssetsLocation.ContainerProxy = &proxyURL builder.AssetsLocation.ContainerProxy = &proxyURL
remapped, err := builder.RemapImage(image) remapped := builder.RemapImage(image)
if err != nil {
t.Error("Error remapping image", err)
}
if remapped != expected { if remapped != expected {
t.Errorf("Error remapping image (Expecting: %s, got %s)", expected, remapped) t.Errorf("Error remapping image (Expecting: %s, got %s)", expected, remapped)
} }
@ -118,11 +102,7 @@ func TestValidate_RemapImage_ContainerProxy_AppliesToImagesWithTags(t *testing.T
builder.AssetsLocation.ContainerProxy = &proxyURL builder.AssetsLocation.ContainerProxy = &proxyURL
remapped, err := builder.RemapImage(image) remapped := builder.RemapImage(image)
if err != nil {
t.Error("Error remapping image", err)
}
if remapped != expected { if remapped != expected {
t.Errorf("Error remapping image (Expecting: %s, got %s)", expected, remapped) t.Errorf("Error remapping image (Expecting: %s, got %s)", expected, remapped)
} }
@ -140,11 +120,7 @@ func TestValidate_RemapImage_ContainerRegistry_MappingMultipleTimesConverges(t *
remapped := image remapped := image
iterations := make([]map[int]int, 2) iterations := make([]map[int]int, 2)
for i := range iterations { for i := range iterations {
remapped, err := builder.RemapImage(remapped) remapped := builder.RemapImage(remapped)
if err != nil {
t.Errorf("Error remapping image (iteration %d): %s", i, err)
}
if remapped != expected { if remapped != expected {
t.Errorf("Error remapping image (Expecting: %s, got %s, iteration: %d)", expected, remapped, i) t.Errorf("Error remapping image (Expecting: %s, got %s, iteration: %d)", expected, remapped, i)
} }

View File

@ -17,13 +17,12 @@ limitations under the License.
package kubemanifest package kubemanifest
import ( import (
"fmt"
"strings" "strings"
"k8s.io/klog/v2" "k8s.io/klog/v2"
) )
type ImageRemapFunction func(image string) (string, error) type ImageRemapFunction func(image string) string
func (m *Object) RemapImages(mapper ImageRemapFunction) error { func (m *Object) RemapImages(mapper ImageRemapFunction) error {
visitor := &imageRemapVisitor{ visitor := &imageRemapVisitor{
@ -57,10 +56,7 @@ func (m *imageRemapVisitor) VisitString(path []string, v string, mutator func(st
image := v image := v
klog.V(4).Infof("Consider image for re-mapping: %q", image) klog.V(4).Infof("Consider image for re-mapping: %q", image)
remapped, err := m.mapper(v) remapped := m.mapper(v)
if err != nil {
return fmt.Errorf("error remapping image %q: %v", image, err)
}
if remapped != image { if remapped != image {
mutator(remapped) mutator(remapped)
} }

View File

@ -150,11 +150,7 @@ func Image(component string, clusterSpec *kops.ClusterSpec, assetsBuilder *asset
if !kopsmodel.IsBaseURL(clusterSpec.KubernetesVersion) { if !kopsmodel.IsBaseURL(clusterSpec.KubernetesVersion) {
image := "registry.k8s.io/" + imageName + ":" + "v" + kubernetesVersion.String() image := "registry.k8s.io/" + imageName + ":" + "v" + kubernetesVersion.String()
image, err := assetsBuilder.RemapImage(image) return assetsBuilder.RemapImage(image), nil
if err != nil {
return "", fmt.Errorf("unable to remap container %q: %v", image, err)
}
return image, nil
} }
// The simple name is valid when pulling. But if we // The simple name is valid when pulling. But if we

View File

@ -314,11 +314,7 @@ func (b *EtcdManagerBuilder) buildPod(etcdCluster kops.EtcdClusterSpec, instance
// Remap image via AssetBuilder // Remap image via AssetBuilder
for i := range pod.Spec.InitContainers { for i := range pod.Spec.InitContainers {
initContainer := &pod.Spec.InitContainers[i] initContainer := &pod.Spec.InitContainers[i]
remapped, err := b.AssetBuilder.RemapImage(initContainer.Image) initContainer.Image = b.AssetBuilder.RemapImage(initContainer.Image)
if err != nil {
return nil, fmt.Errorf("unable to remap init container image %q: %w", container.Image, err)
}
initContainer.Image = remapped
} }
} }
@ -334,11 +330,7 @@ func (b *EtcdManagerBuilder) buildPod(etcdCluster kops.EtcdClusterSpec, instance
} }
// Remap image via AssetBuilder // Remap image via AssetBuilder
remapped, err := b.AssetBuilder.RemapImage(container.Image) container.Image = b.AssetBuilder.RemapImage(container.Image)
if err != nil {
return nil, fmt.Errorf("unable to remap container image %q: %w", container.Image, err)
}
container.Image = remapped
} }
var clientHost string var clientHost string

View File

@ -138,13 +138,7 @@ func (b *KubeApiserverBuilder) buildHealthcheckSidecar() (*corev1.Pod, error) {
} }
// Remap image via AssetBuilder // Remap image via AssetBuilder
{ container.Image = b.AssetBuilder.RemapImage(container.Image)
remapped, err := b.AssetBuilder.RemapImage(container.Image)
if err != nil {
return nil, fmt.Errorf("unable to remap container image %q: %v", container.Image, err)
}
container.Image = remapped
}
return pod, nil return pod, nil
} }

View File

@ -166,11 +166,7 @@ func (b *KubeletOptionsBuilder) configureKubelet(cluster *kops.Cluster, kubelet
// Prevent image GC from pruning the pause image // Prevent image GC from pruning the pause image
// https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2040-kubelet-cri#pinned-images // https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2040-kubelet-cri#pinned-images
image := "registry.k8s.io/pause:3.9" image := "registry.k8s.io/pause:3.9"
var err error kubelet.PodInfraContainerImage = b.AssetBuilder.RemapImage(image)
if image, err = b.AssetBuilder.RemapImage(image); err != nil {
return err
}
kubelet.PodInfraContainerImage = image
if kubelet.FeatureGates == nil { if kubelet.FeatureGates == nil {
kubelet.FeatureGates = make(map[string]string) kubelet.FeatureGates = make(map[string]string)

View File

@ -509,7 +509,8 @@ func (n *nodeUpConfigBuilder) buildWarmPoolImages(ig *kops.InstanceGroup) []stri
if assetBuilder != nil { if assetBuilder != nil {
for _, image := range assetBuilder.ImageAssets { for _, image := range assetBuilder.ImageAssets {
for _, prefix := range desiredImagePrefixes { for _, prefix := range desiredImagePrefixes {
if strings.HasPrefix(image.DownloadLocation, prefix) { remappedPrefix := assets.NormalizeImage(assetBuilder, prefix)
if strings.HasPrefix(image.DownloadLocation, remappedPrefix) {
images[image.DownloadLocation] = true images[image.DownloadLocation] = true
} }
} }

View File

@ -130,7 +130,7 @@ ClusterName: minimal-warmpool.example.com
ConfigBase: memfs://clusters.example.com/minimal-warmpool.example.com ConfigBase: memfs://clusters.example.com/minimal-warmpool.example.com
InstanceGroupName: master-us-test-1a InstanceGroupName: master-us-test-1a
InstanceGroupRole: ControlPlane InstanceGroupRole: ControlPlane
NodeupConfigHash: BGYFM1S3GrCIH6JqycbfBr9wcltsONEgcz10QbL/9DE= NodeupConfigHash: MVBHdgdOuzS5NjzLCOVaRI+r8Yycu79zVfQIUF7qGc0=
__EOF_KUBE_ENV __EOF_KUBE_ENV

View File

@ -153,7 +153,7 @@ ConfigServer:
- https://kops-controller.internal.minimal-warmpool.example.com:3988/ - https://kops-controller.internal.minimal-warmpool.example.com:3988/
InstanceGroupName: nodes InstanceGroupName: nodes
InstanceGroupRole: Node InstanceGroupRole: Node
NodeupConfigHash: qx6ZYYfv4IWM31VjEaj+OnvW1dLilS7uvTY9PVeLP0c= NodeupConfigHash: LyRFWE+TmVjqI8Y5S+8LBIcnd15CBZ0EyvXGvEBRZcY=
__EOF_KUBE_ENV __EOF_KUBE_ENV

View File

@ -6,6 +6,8 @@ metadata:
spec: spec:
api: api:
dns: {} dns: {}
assets:
containerProxy: kops.k8s.io/remapped-image
authorization: authorization:
alwaysAllow: {} alwaysAllow: {}
channel: stable channel: stable
@ -79,7 +81,7 @@ spec:
- https://127.0.0.1:4001 - https://127.0.0.1:4001
etcdServersOverrides: etcdServersOverrides:
- /events#https://127.0.0.1:4002 - /events#https://127.0.0.1:4002
image: registry.k8s.io/kube-apiserver:v1.32.0 image: kops.k8s.io/remapped-image/kube-apiserver:v1.32.0
kubeletPreferredAddressTypes: kubeletPreferredAddressTypes:
- InternalIP - InternalIP
- Hostname - Hostname
@ -105,7 +107,7 @@ spec:
clusterCIDR: 100.96.0.0/11 clusterCIDR: 100.96.0.0/11
clusterName: minimal-warmpool.example.com clusterName: minimal-warmpool.example.com
configureCloudRoutes: false configureCloudRoutes: false
image: registry.k8s.io/kube-controller-manager:v1.32.0 image: kops.k8s.io/remapped-image/kube-controller-manager:v1.32.0
leaderElection: leaderElection:
leaderElect: true leaderElect: true
logLevel: 2 logLevel: 2
@ -127,10 +129,10 @@ spec:
kubeProxy: kubeProxy:
clusterCIDR: 100.96.0.0/11 clusterCIDR: 100.96.0.0/11
cpuRequest: 100m cpuRequest: 100m
image: registry.k8s.io/kube-proxy:v1.32.0 image: kops.k8s.io/remapped-image/kube-proxy:v1.32.0
logLevel: 2 logLevel: 2
kubeScheduler: kubeScheduler:
image: registry.k8s.io/kube-scheduler:v1.32.0 image: kops.k8s.io/remapped-image/kube-scheduler:v1.32.0
leaderElection: leaderElection:
leaderElect: true leaderElect: true
logLevel: 2 logLevel: 2
@ -145,7 +147,7 @@ spec:
evictionHard: memory.available<100Mi,nodefs.available<10%,nodefs.inodesFree<5%,imagefs.available<10%,imagefs.inodesFree<5% evictionHard: memory.available<100Mi,nodefs.available<10%,nodefs.inodesFree<5%,imagefs.available<10%,imagefs.inodesFree<5%
kubeconfigPath: /var/lib/kubelet/kubeconfig kubeconfigPath: /var/lib/kubelet/kubeconfig
logLevel: 2 logLevel: 2
podInfraContainerImage: registry.k8s.io/pause:3.9 podInfraContainerImage: kops.k8s.io/remapped-image/pause:3.9
podManifestPath: /etc/kubernetes/manifests podManifestPath: /etc/kubernetes/manifests
protectKernelDefaults: true protectKernelDefaults: true
registerSchedulable: true registerSchedulable: true
@ -165,7 +167,7 @@ spec:
evictionHard: memory.available<100Mi,nodefs.available<10%,nodefs.inodesFree<5%,imagefs.available<10%,imagefs.inodesFree<5% evictionHard: memory.available<100Mi,nodefs.available<10%,nodefs.inodesFree<5%,imagefs.available<10%,imagefs.inodesFree<5%
kubeconfigPath: /var/lib/kubelet/kubeconfig kubeconfigPath: /var/lib/kubelet/kubeconfig
logLevel: 2 logLevel: 2
podInfraContainerImage: registry.k8s.io/pause:3.9 podInfraContainerImage: kops.k8s.io/remapped-image/pause:3.9
podManifestPath: /etc/kubernetes/manifests podManifestPath: /etc/kubernetes/manifests
protectKernelDefaults: true protectKernelDefaults: true
registerSchedulable: true registerSchedulable: true

View File

@ -22,7 +22,7 @@ spec:
env: env:
- name: ETCD_MANAGER_DAILY_BACKUPS_RETENTION - name: ETCD_MANAGER_DAILY_BACKUPS_RETENTION
value: 90d value: 90d
image: registry.k8s.io/etcd-manager/etcd-manager-slim:v3.0.20250704 image: kops.k8s.io/remapped-image/etcd-manager/etcd-manager-slim:v3.0.20250704
name: etcd-manager name: etcd-manager
resources: resources:
requests: requests:
@ -49,7 +49,7 @@ spec:
- --src=/ko-app/kops-utils-cp - --src=/ko-app/kops-utils-cp
command: command:
- /ko-app/kops-utils-cp - /ko-app/kops-utils-cp
image: registry.k8s.io/kops/kops-utils-cp:1.33.0-beta.1 image: kops.k8s.io/remapped-image/kops/kops-utils-cp:1.33.0-beta.1
name: kops-utils-cp name: kops-utils-cp
resources: {} resources: {}
volumeMounts: volumeMounts:
@ -61,7 +61,7 @@ spec:
- --src=/usr/local/bin/etcdctl - --src=/usr/local/bin/etcdctl
command: command:
- /opt/kops-utils/kops-utils-cp - /opt/kops-utils/kops-utils-cp
image: registry.k8s.io/etcd:3.4.13-0 image: kops.k8s.io/remapped-image/etcd:3.4.13-0
name: init-etcd-3-4-13 name: init-etcd-3-4-13
resources: {} resources: {}
volumeMounts: volumeMounts:
@ -73,7 +73,7 @@ spec:
- --src=/usr/local/bin/etcdctl - --src=/usr/local/bin/etcdctl
command: command:
- /opt/kops-utils/kops-utils-cp - /opt/kops-utils/kops-utils-cp
image: registry.k8s.io/etcd:3.5.21-0 image: kops.k8s.io/remapped-image/etcd:3.5.21-0
name: init-etcd-3-5-21 name: init-etcd-3-5-21
resources: {} resources: {}
volumeMounts: volumeMounts:
@ -86,7 +86,7 @@ spec:
- --src=/opt/etcd-v3.4.13/etcdctl - --src=/opt/etcd-v3.4.13/etcdctl
command: command:
- /opt/kops-utils/kops-utils-cp - /opt/kops-utils/kops-utils-cp
image: registry.k8s.io/kops/kops-utils-cp:1.33.0-beta.1 image: kops.k8s.io/remapped-image/kops/kops-utils-cp:1.33.0-beta.1
name: init-etcd-symlinks-3-4-13 name: init-etcd-symlinks-3-4-13
resources: {} resources: {}
volumeMounts: volumeMounts:
@ -107,7 +107,7 @@ spec:
- --src=/opt/etcd-v3.5.21/etcdctl - --src=/opt/etcd-v3.5.21/etcdctl
command: command:
- /opt/kops-utils/kops-utils-cp - /opt/kops-utils/kops-utils-cp
image: registry.k8s.io/kops/kops-utils-cp:1.33.0-beta.1 image: kops.k8s.io/remapped-image/kops/kops-utils-cp:1.33.0-beta.1
name: init-etcd-symlinks-3-5-21 name: init-etcd-symlinks-3-5-21
resources: {} resources: {}
volumeMounts: volumeMounts:

View File

@ -22,7 +22,7 @@ spec:
env: env:
- name: ETCD_MANAGER_DAILY_BACKUPS_RETENTION - name: ETCD_MANAGER_DAILY_BACKUPS_RETENTION
value: 90d value: 90d
image: registry.k8s.io/etcd-manager/etcd-manager-slim:v3.0.20250704 image: kops.k8s.io/remapped-image/etcd-manager/etcd-manager-slim:v3.0.20250704
name: etcd-manager name: etcd-manager
resources: resources:
requests: requests:
@ -49,7 +49,7 @@ spec:
- --src=/ko-app/kops-utils-cp - --src=/ko-app/kops-utils-cp
command: command:
- /ko-app/kops-utils-cp - /ko-app/kops-utils-cp
image: registry.k8s.io/kops/kops-utils-cp:1.33.0-beta.1 image: kops.k8s.io/remapped-image/kops/kops-utils-cp:1.33.0-beta.1
name: kops-utils-cp name: kops-utils-cp
resources: {} resources: {}
volumeMounts: volumeMounts:
@ -61,7 +61,7 @@ spec:
- --src=/usr/local/bin/etcdctl - --src=/usr/local/bin/etcdctl
command: command:
- /opt/kops-utils/kops-utils-cp - /opt/kops-utils/kops-utils-cp
image: registry.k8s.io/etcd:3.4.13-0 image: kops.k8s.io/remapped-image/etcd:3.4.13-0
name: init-etcd-3-4-13 name: init-etcd-3-4-13
resources: {} resources: {}
volumeMounts: volumeMounts:
@ -73,7 +73,7 @@ spec:
- --src=/usr/local/bin/etcdctl - --src=/usr/local/bin/etcdctl
command: command:
- /opt/kops-utils/kops-utils-cp - /opt/kops-utils/kops-utils-cp
image: registry.k8s.io/etcd:3.5.21-0 image: kops.k8s.io/remapped-image/etcd:3.5.21-0
name: init-etcd-3-5-21 name: init-etcd-3-5-21
resources: {} resources: {}
volumeMounts: volumeMounts:
@ -86,7 +86,7 @@ spec:
- --src=/opt/etcd-v3.4.13/etcdctl - --src=/opt/etcd-v3.4.13/etcdctl
command: command:
- /opt/kops-utils/kops-utils-cp - /opt/kops-utils/kops-utils-cp
image: registry.k8s.io/kops/kops-utils-cp:1.33.0-beta.1 image: kops.k8s.io/remapped-image/kops/kops-utils-cp:1.33.0-beta.1
name: init-etcd-symlinks-3-4-13 name: init-etcd-symlinks-3-4-13
resources: {} resources: {}
volumeMounts: volumeMounts:
@ -107,7 +107,7 @@ spec:
- --src=/opt/etcd-v3.5.21/etcdctl - --src=/opt/etcd-v3.5.21/etcdctl
command: command:
- /opt/kops-utils/kops-utils-cp - /opt/kops-utils/kops-utils-cp
image: registry.k8s.io/kops/kops-utils-cp:1.33.0-beta.1 image: kops.k8s.io/remapped-image/kops/kops-utils-cp:1.33.0-beta.1
name: init-etcd-symlinks-3-5-21 name: init-etcd-symlinks-3-5-21
resources: {} resources: {}
volumeMounts: volumeMounts:

View File

@ -8,7 +8,7 @@ spec:
- --ca-cert=/secrets/ca.crt - --ca-cert=/secrets/ca.crt
- --client-cert=/secrets/client.crt - --client-cert=/secrets/client.crt
- --client-key=/secrets/client.key - --client-key=/secrets/client.key
image: registry.k8s.io/kops/kube-apiserver-healthcheck:1.33.0-beta.1 image: kops.k8s.io/remapped-image/kops/kube-apiserver-healthcheck:1.33.0-beta.1
livenessProbe: livenessProbe:
httpGet: httpGet:
host: 127.0.0.1 host: 127.0.0.1

View File

@ -44,7 +44,7 @@ spec:
env: env:
- name: KUBERNETES_SERVICE_HOST - name: KUBERNETES_SERVICE_HOST
value: 127.0.0.1 value: 127.0.0.1
image: registry.k8s.io/provider-aws/cloud-controller-manager:v1.31.0 image: kops.k8s.io/remapped-image/provider-aws/cloud-controller-manager:v1.31.0
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
name: aws-cloud-controller-manager name: aws-cloud-controller-manager
resources: resources:

View File

@ -664,7 +664,7 @@ spec:
valueFrom: valueFrom:
fieldRef: fieldRef:
fieldPath: spec.nodeName fieldPath: spec.nodeName
image: public.ecr.aws/ebs-csi-driver/aws-ebs-csi-driver:v1.38.1 image: kops.k8s.io/remapped-image/ebs-csi-driver/aws-ebs-csi-driver:v1.38.1
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
lifecycle: lifecycle:
preStop: preStop:
@ -711,7 +711,7 @@ spec:
value: /csi/csi.sock value: /csi/csi.sock
- name: DRIVER_REG_SOCK_PATH - name: DRIVER_REG_SOCK_PATH
value: /var/lib/kubelet/plugins/ebs.csi.aws.com/csi.sock value: /var/lib/kubelet/plugins/ebs.csi.aws.com/csi.sock
image: public.ecr.aws/eks-distro/kubernetes-csi/node-driver-registrar:v2.12.0-eks-1-32-1 image: kops.k8s.io/remapped-image/eks-distro/kubernetes-csi/node-driver-registrar:v2.12.0-eks-1-32-1
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
livenessProbe: livenessProbe:
exec: exec:
@ -741,7 +741,7 @@ spec:
name: probe-dir name: probe-dir
- args: - args:
- --csi-address=/csi/csi.sock - --csi-address=/csi/csi.sock
image: public.ecr.aws/eks-distro/kubernetes-csi/livenessprobe:v2.14.0-eks-1-32-1 image: kops.k8s.io/remapped-image/eks-distro/kubernetes-csi/livenessprobe:v2.14.0-eks-1-32-1
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
name: liveness-probe name: liveness-probe
resources: resources:
@ -908,7 +908,7 @@ spec:
key: endpoint key: endpoint
name: aws-meta name: aws-meta
optional: true optional: true
image: public.ecr.aws/ebs-csi-driver/aws-ebs-csi-driver:v1.38.1 image: kops.k8s.io/remapped-image/ebs-csi-driver/aws-ebs-csi-driver:v1.38.1
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
livenessProbe: livenessProbe:
failureThreshold: 5 failureThreshold: 5
@ -963,7 +963,7 @@ spec:
env: env:
- name: ADDRESS - name: ADDRESS
value: /var/lib/csi/sockets/pluginproxy/csi.sock value: /var/lib/csi/sockets/pluginproxy/csi.sock
image: public.ecr.aws/eks-distro/kubernetes-csi/external-provisioner:v5.1.0-eks-1-32-1 image: kops.k8s.io/remapped-image/eks-distro/kubernetes-csi/external-provisioner:v5.1.0-eks-1-32-1
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
name: csi-provisioner name: csi-provisioner
resources: resources:
@ -992,7 +992,7 @@ spec:
env: env:
- name: ADDRESS - name: ADDRESS
value: /var/lib/csi/sockets/pluginproxy/csi.sock value: /var/lib/csi/sockets/pluginproxy/csi.sock
image: public.ecr.aws/eks-distro/kubernetes-csi/external-attacher:v4.7.0-eks-1-32-1 image: kops.k8s.io/remapped-image/eks-distro/kubernetes-csi/external-attacher:v4.7.0-eks-1-32-1
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
name: csi-attacher name: csi-attacher
resources: resources:
@ -1025,7 +1025,7 @@ spec:
valueFrom: valueFrom:
fieldRef: fieldRef:
fieldPath: metadata.namespace fieldPath: metadata.namespace
image: public.ecr.aws/ebs-csi-driver/volume-modifier-for-k8s:v0.5.0 image: kops.k8s.io/remapped-image/ebs-csi-driver/volume-modifier-for-k8s:v0.5.0
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
name: volumemodifier name: volumemodifier
resources: resources:
@ -1055,7 +1055,7 @@ spec:
env: env:
- name: ADDRESS - name: ADDRESS
value: /var/lib/csi/sockets/pluginproxy/csi.sock value: /var/lib/csi/sockets/pluginproxy/csi.sock
image: public.ecr.aws/eks-distro/kubernetes-csi/external-resizer:v1.12.0-eks-1-32-1 image: kops.k8s.io/remapped-image/eks-distro/kubernetes-csi/external-resizer:v1.12.0-eks-1-32-1
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
name: csi-resizer name: csi-resizer
resources: resources:
@ -1074,7 +1074,7 @@ spec:
name: socket-dir name: socket-dir
- args: - args:
- --csi-address=/csi/csi.sock - --csi-address=/csi/csi.sock
image: public.ecr.aws/eks-distro/kubernetes-csi/livenessprobe:v2.14.0-eks-1-32-1 image: kops.k8s.io/remapped-image/eks-distro/kubernetes-csi/livenessprobe:v2.14.0-eks-1-32-1
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
name: liveness-probe name: liveness-probe
resources: resources:

View File

@ -6,7 +6,7 @@ spec:
addons: addons:
- id: k8s-1.16 - id: k8s-1.16
manifest: kops-controller.addons.k8s.io/k8s-1.16.yaml manifest: kops-controller.addons.k8s.io/k8s-1.16.yaml
manifestHash: a40918765aa1eeb196410ffe8ecfc58411a1c0d74bed59e319b2fab2d30d8a7a manifestHash: 2efbf847a3b360c0a3d98d95ae119e0172220e5242aa69b717e695081697edd4
name: kops-controller.addons.k8s.io name: kops-controller.addons.k8s.io
needsRollingUpdate: control-plane needsRollingUpdate: control-plane
selector: selector:
@ -14,7 +14,7 @@ spec:
version: 9.99.0 version: 9.99.0
- id: k8s-1.12 - id: k8s-1.12
manifest: coredns.addons.k8s.io/k8s-1.12.yaml manifest: coredns.addons.k8s.io/k8s-1.12.yaml
manifestHash: 5cf27d74240a028d347903ee2a81d068e221660f19a9c71b4e8438b8f3c8de81 manifestHash: 3757415a5c6b632d01e9e1e3b9305df47f5577cfc4515cc6c898dc78a3f76411
name: coredns.addons.k8s.io name: coredns.addons.k8s.io
selector: selector:
k8s-addon: coredns.addons.k8s.io k8s-addon: coredns.addons.k8s.io
@ -34,14 +34,14 @@ spec:
version: 9.99.0 version: 9.99.0
- id: k8s-1.12 - id: k8s-1.12
manifest: dns-controller.addons.k8s.io/k8s-1.12.yaml manifest: dns-controller.addons.k8s.io/k8s-1.12.yaml
manifestHash: 203be4477fb38ebbe6d2abafc6b3b9b4d0109e7575b62033a9c06ecb9266563f manifestHash: e702b8f49ae654fd672926522b4dd9b7f9e262878ddaff0484e4fadf9a902dfd
name: dns-controller.addons.k8s.io name: dns-controller.addons.k8s.io
selector: selector:
k8s-addon: dns-controller.addons.k8s.io k8s-addon: dns-controller.addons.k8s.io
version: 9.99.0 version: 9.99.0
- id: k8s-1.11 - id: k8s-1.11
manifest: node-termination-handler.aws/k8s-1.11.yaml manifest: node-termination-handler.aws/k8s-1.11.yaml
manifestHash: 7f8d3b5a7136ef69863c7fe3d460fbfe0c49f1d2d22d9a1452f7d668c931f8a6 manifestHash: 914ec10249ab5a10103648a398f553126a86ec4d50e38fbde71da9c2d0fbd0c0
name: node-termination-handler.aws name: node-termination-handler.aws
prune: prune:
kinds: kinds:
@ -99,7 +99,7 @@ spec:
version: 9.99.0 version: 9.99.0
- id: k8s-1.16 - id: k8s-1.16
manifest: networking.cilium.io/k8s-1.16-v1.15.yaml manifest: networking.cilium.io/k8s-1.16-v1.15.yaml
manifestHash: 64fd2b1964ff070f391c6125e4a230dfbf34940c8941dfe982bb3b9acd56ac3c manifestHash: d9cf37239f73ec224904209dfcfdbd79330c202bab99fe823d7bf3bf91988212
name: networking.cilium.io name: networking.cilium.io
needsRollingUpdate: all needsRollingUpdate: all
selector: selector:
@ -107,14 +107,14 @@ spec:
version: 9.99.0 version: 9.99.0
- id: k8s-1.18 - id: k8s-1.18
manifest: aws-cloud-controller.addons.k8s.io/k8s-1.18.yaml manifest: aws-cloud-controller.addons.k8s.io/k8s-1.18.yaml
manifestHash: b44967f0bd287a1edb4f4ba8a53d04c0b7a495a19870dec87dfde5b8dc69d950 manifestHash: 45dcc7428d3d0ab236563461b561848afda8e2992ef92227877db57309dbfd04
name: aws-cloud-controller.addons.k8s.io name: aws-cloud-controller.addons.k8s.io
selector: selector:
k8s-addon: aws-cloud-controller.addons.k8s.io k8s-addon: aws-cloud-controller.addons.k8s.io
version: 9.99.0 version: 9.99.0
- id: k8s-1.17 - id: k8s-1.17
manifest: aws-ebs-csi-driver.addons.k8s.io/k8s-1.17.yaml manifest: aws-ebs-csi-driver.addons.k8s.io/k8s-1.17.yaml
manifestHash: 8489703d5ee8668212c585909e538bc3193cd7f981395da8811266c7938c59cf manifestHash: 3b9770b697dd4a28c65e2d0b59b594959f3bc8ff8998d402cf023e5c21bf7af9
name: aws-ebs-csi-driver.addons.k8s.io name: aws-ebs-csi-driver.addons.k8s.io
selector: selector:
k8s-addon: aws-ebs-csi-driver.addons.k8s.io k8s-addon: aws-ebs-csi-driver.addons.k8s.io

View File

@ -135,7 +135,7 @@ spec:
- args: - args:
- -conf - -conf
- /etc/coredns/Corefile - /etc/coredns/Corefile
image: registry.k8s.io/coredns/coredns:v1.11.4 image: kops.k8s.io/remapped-image/coredns/coredns:v1.11.4
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
livenessProbe: livenessProbe:
failureThreshold: 5 failureThreshold: 5
@ -368,7 +368,7 @@ spec:
- --default-params={"linear":{"coresPerReplica":256,"nodesPerReplica":16,"preventSinglePointFailure":true}} - --default-params={"linear":{"coresPerReplica":256,"nodesPerReplica":16,"preventSinglePointFailure":true}}
- --logtostderr=true - --logtostderr=true
- --v=2 - --v=2
image: registry.k8s.io/cpa/cluster-proportional-autoscaler:v1.9.0 image: kops.k8s.io/remapped-image/cpa/cluster-proportional-autoscaler:v1.9.0
name: autoscaler name: autoscaler
resources: resources:
requests: requests:

View File

@ -48,7 +48,7 @@ spec:
env: env:
- name: KUBERNETES_SERVICE_HOST - name: KUBERNETES_SERVICE_HOST
value: 127.0.0.1 value: 127.0.0.1
image: registry.k8s.io/kops/dns-controller:1.33.0-beta.1 image: kops.k8s.io/remapped-image/kops/dns-controller:1.33.0-beta.1
name: dns-controller name: dns-controller
resources: resources:
requests: requests:

View File

@ -65,7 +65,7 @@ spec:
value: 127.0.0.1 value: 127.0.0.1
- name: KOPS_RUN_TOO_NEW_VERSION - name: KOPS_RUN_TOO_NEW_VERSION
value: "1" value: "1"
image: registry.k8s.io/kops/kops-controller:1.33.0-beta.1 image: kops.k8s.io/remapped-image/kops/kops-controller:1.33.0-beta.1
name: kops-controller name: kops-controller
resources: resources:
requests: requests:

View File

@ -583,7 +583,7 @@ spec:
value: api.internal.minimal-warmpool.example.com value: api.internal.minimal-warmpool.example.com
- name: KUBERNETES_SERVICE_PORT - name: KUBERNETES_SERVICE_PORT
value: "443" value: "443"
image: quay.io/cilium/cilium:v1.16.7 image: kops.k8s.io/remapped-image/cilium/cilium:v1.16.7
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
lifecycle: lifecycle:
preStop: preStop:
@ -698,7 +698,7 @@ spec:
value: api.internal.minimal-warmpool.example.com value: api.internal.minimal-warmpool.example.com
- name: KUBERNETES_SERVICE_PORT - name: KUBERNETES_SERVICE_PORT
value: "443" value: "443"
image: quay.io/cilium/cilium:v1.16.7 image: kops.k8s.io/remapped-image/cilium/cilium:v1.16.7
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
name: config name: config
terminationMessagePolicy: FallbackToLogsOnError terminationMessagePolicy: FallbackToLogsOnError
@ -717,7 +717,7 @@ spec:
value: /run/cilium/cgroupv2 value: /run/cilium/cgroupv2
- name: BIN_PATH - name: BIN_PATH
value: /opt/cni/bin value: /opt/cni/bin
image: quay.io/cilium/cilium:v1.16.7 image: kops.k8s.io/remapped-image/cilium/cilium:v1.16.7
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
name: mount-cgroup name: mount-cgroup
securityContext: securityContext:
@ -744,7 +744,7 @@ spec:
env: env:
- name: BIN_PATH - name: BIN_PATH
value: /opt/cni/bin value: /opt/cni/bin
image: quay.io/cilium/cilium:v1.16.7 image: kops.k8s.io/remapped-image/cilium/cilium:v1.16.7
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
name: apply-sysctl-overwrites name: apply-sysctl-overwrites
securityContext: securityContext:
@ -768,7 +768,7 @@ spec:
- /bin/bash - /bin/bash
- -c - -c
- -- - --
image: quay.io/cilium/cilium:v1.16.7 image: kops.k8s.io/remapped-image/cilium/cilium:v1.16.7
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
name: mount-bpf-fs name: mount-bpf-fs
securityContext: securityContext:
@ -803,7 +803,7 @@ spec:
value: api.internal.minimal-warmpool.example.com value: api.internal.minimal-warmpool.example.com
- name: KUBERNETES_SERVICE_PORT - name: KUBERNETES_SERVICE_PORT
value: "443" value: "443"
image: quay.io/cilium/cilium:v1.16.7 image: kops.k8s.io/remapped-image/cilium/cilium:v1.16.7
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
name: clean-cilium-state name: clean-cilium-state
securityContext: securityContext:
@ -828,7 +828,7 @@ spec:
name: cilium-run name: cilium-run
- command: - command:
- /install-plugin.sh - /install-plugin.sh
image: quay.io/cilium/cilium:v1.16.7 image: kops.k8s.io/remapped-image/cilium/cilium:v1.16.7
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
name: install-cni-binaries name: install-cni-binaries
resources: resources:
@ -988,7 +988,7 @@ spec:
value: api.internal.minimal-warmpool.example.com value: api.internal.minimal-warmpool.example.com
- name: KUBERNETES_SERVICE_PORT - name: KUBERNETES_SERVICE_PORT
value: "443" value: "443"
image: quay.io/cilium/operator:v1.16.7 image: kops.k8s.io/remapped-image/cilium/operator:v1.16.7
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
livenessProbe: livenessProbe:
httpGet: httpGet:

View File

@ -207,7 +207,7 @@ spec:
value: "false" value: "false"
- name: WORKERS - name: WORKERS
value: "10" value: "10"
image: public.ecr.aws/aws-ec2/aws-node-termination-handler:v1.22.0 image: kops.k8s.io/remapped-image/aws-ec2/aws-node-termination-handler:v1.22.0
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
livenessProbe: livenessProbe:
httpGet: httpGet:

View File

@ -28,7 +28,7 @@ APIServerConfig:
- https://127.0.0.1:4001 - https://127.0.0.1:4001
etcdServersOverrides: etcdServersOverrides:
- /events#https://127.0.0.1:4002 - /events#https://127.0.0.1:4002
image: registry.k8s.io/kube-apiserver:v1.32.0 image: kops.k8s.io/remapped-image/kube-apiserver:v1.32.0
kubeletPreferredAddressTypes: kubeletPreferredAddressTypes:
- InternalIP - InternalIP
- Hostname - Hostname
@ -238,13 +238,13 @@ ControlPlaneConfig:
clusterCIDR: 100.96.0.0/11 clusterCIDR: 100.96.0.0/11
clusterName: minimal-warmpool.example.com clusterName: minimal-warmpool.example.com
configureCloudRoutes: false configureCloudRoutes: false
image: registry.k8s.io/kube-controller-manager:v1.32.0 image: kops.k8s.io/remapped-image/kube-controller-manager:v1.32.0
leaderElection: leaderElection:
leaderElect: true leaderElect: true
logLevel: 2 logLevel: 2
useServiceAccountCredentials: true useServiceAccountCredentials: true
KubeScheduler: KubeScheduler:
image: registry.k8s.io/kube-scheduler:v1.32.0 image: kops.k8s.io/remapped-image/kube-scheduler:v1.32.0
leaderElection: leaderElection:
leaderElect: true leaderElect: true
logLevel: 2 logLevel: 2
@ -274,7 +274,7 @@ KeypairIDs:
KubeProxy: KubeProxy:
clusterCIDR: 100.96.0.0/11 clusterCIDR: 100.96.0.0/11
cpuRequest: 100m cpuRequest: 100m
image: registry.k8s.io/kube-proxy:v1.32.0 image: kops.k8s.io/remapped-image/kube-proxy:v1.32.0
logLevel: 2 logLevel: 2
KubeletConfig: KubeletConfig:
anonymousAuth: false anonymousAuth: false
@ -291,7 +291,7 @@ KubeletConfig:
kops.k8s.io/kops-controller-pki: "" kops.k8s.io/kops-controller-pki: ""
node-role.kubernetes.io/control-plane: "" node-role.kubernetes.io/control-plane: ""
node.kubernetes.io/exclude-from-external-load-balancers: "" node.kubernetes.io/exclude-from-external-load-balancers: ""
podInfraContainerImage: registry.k8s.io/pause:3.9 podInfraContainerImage: kops.k8s.io/remapped-image/pause:3.9
podManifestPath: /etc/kubernetes/manifests podManifestPath: /etc/kubernetes/manifests
protectKernelDefaults: true protectKernelDefaults: true
registerSchedulable: true registerSchedulable: true

View File

@ -26,7 +26,7 @@ KeypairIDs:
KubeProxy: KubeProxy:
clusterCIDR: 100.96.0.0/11 clusterCIDR: 100.96.0.0/11
cpuRequest: 100m cpuRequest: 100m
image: registry.k8s.io/kube-proxy:v1.32.0 image: kops.k8s.io/remapped-image/kube-proxy:v1.32.0
logLevel: 2 logLevel: 2
KubeletConfig: KubeletConfig:
anonymousAuth: false anonymousAuth: false
@ -41,7 +41,7 @@ KubeletConfig:
logLevel: 2 logLevel: 2
nodeLabels: nodeLabels:
node-role.kubernetes.io/node: "" node-role.kubernetes.io/node: ""
podInfraContainerImage: registry.k8s.io/pause:3.9 podInfraContainerImage: kops.k8s.io/remapped-image/pause:3.9
podManifestPath: /etc/kubernetes/manifests podManifestPath: /etc/kubernetes/manifests
protectKernelDefaults: true protectKernelDefaults: true
registerSchedulable: true registerSchedulable: true
@ -61,7 +61,7 @@ containerdConfig:
usesLegacyGossip: false usesLegacyGossip: false
usesNoneDNS: false usesNoneDNS: false
warmPoolImages: warmPoolImages:
- quay.io/cilium/cilium:v1.16.7 - kops.k8s.io/remapped-image/cilium/cilium:v1.16.7
- quay.io/cilium/operator:v1.16.7 - kops.k8s.io/remapped-image/cilium/operator:v1.16.7
- registry.k8s.io/kube-proxy:v1.32.0 - kops.k8s.io/remapped-image/kube-proxy:v1.32.0
- registry.k8s.io/provider-aws/cloud-controller-manager:v1.31.0 - kops.k8s.io/remapped-image/provider-aws/cloud-controller-manager:v1.31.0

View File

@ -4,6 +4,8 @@ metadata:
creationTimestamp: "2016-12-10T22:42:27Z" creationTimestamp: "2016-12-10T22:42:27Z"
name: minimal-warmpool.example.com name: minimal-warmpool.example.com
spec: spec:
assets:
containerProxy: kops.k8s.io/remapped-image
kubernetesApiAccess: kubernetesApiAccess:
- 0.0.0.0/0 - 0.0.0.0/0
channel: stable channel: stable