mirror of
https://github.com/apple/container.git
synced 2026-09-24 23:29:51 -05:00
fix(k8s): correct k8s control plane components version using the user specified node image version (#2271)
This commit is contained in:
@@ -68,6 +68,9 @@ public struct K8sCreate: AsyncParsableCommand {
|
||||
}
|
||||
}
|
||||
|
||||
// Fail before provisioning the node VM.
|
||||
_ = try K8sHelper.kubernetesVersion(nodeImage: nodeImage)
|
||||
|
||||
let isTTY = isatty(FileHandle.standardError.fileDescriptor) == 1
|
||||
let progressConfig = try ProgressConfig(
|
||||
showSpinner: isTTY,
|
||||
@@ -110,7 +113,7 @@ public struct K8sCreate: AsyncParsableCommand {
|
||||
progress.set(description: "Running kubeadm init")
|
||||
try await K8sHelper.prepareNode(nodeID: name, client: client, log: log)
|
||||
try await K8sHelper.bootstrapControlPlane(
|
||||
nodeID: name, apiServerSANs: sans, advertiseAddress: vmIP,
|
||||
nodeID: name, nodeImage: nodeImage, apiServerSANs: sans, advertiseAddress: vmIP,
|
||||
schedulable: provisioner.roles.contains(StandardRoles.worker),
|
||||
cniManifestPath: cni,
|
||||
client: client, log: log)
|
||||
|
||||
@@ -34,10 +34,10 @@ extension K8sHelper {
|
||||
}
|
||||
|
||||
static func bootstrapControlPlane(
|
||||
nodeID: String, apiServerSANs: [String], advertiseAddress: String,
|
||||
nodeID: String, nodeImage: String, apiServerSANs: [String], advertiseAddress: String,
|
||||
schedulable: Bool, cniManifestPath: String? = nil, client: ContainerClient, log: Logger
|
||||
) async throws {
|
||||
let configYAML = initConfigYAML(advertiseAddress: advertiseAddress, certSANs: apiServerSANs)
|
||||
let configYAML = try initConfigYAML(nodeImage: nodeImage, advertiseAddress: advertiseAddress, certSANs: apiServerSANs)
|
||||
var r = try await execCapture(
|
||||
containerId: nodeID, executable: "/bin/sh",
|
||||
arguments: ["-c", "cat > /etc/kubernetes/kubeadm-config.yaml <<'EOF'\n\(configYAML)\nEOF"],
|
||||
@@ -144,7 +144,7 @@ extension K8sHelper {
|
||||
"""
|
||||
}
|
||||
|
||||
private static func initConfigYAML(advertiseAddress: String, certSANs: [String]) -> String {
|
||||
private static func initConfigYAML(nodeImage: String, advertiseAddress: String, certSANs: [String]) throws -> String {
|
||||
let sans = certSANs.map { " - \($0)" }.joined(separator: "\n")
|
||||
return """
|
||||
apiVersion: kubeadm.k8s.io/v1beta4
|
||||
@@ -157,7 +157,7 @@ extension K8sHelper {
|
||||
---
|
||||
apiVersion: kubeadm.k8s.io/v1beta4
|
||||
kind: ClusterConfiguration
|
||||
kubernetesVersion: \(kubernetesVersion())
|
||||
kubernetesVersion: \(try kubernetesVersion(nodeImage: nodeImage))
|
||||
networking:
|
||||
podSubnet: \(podSubnet)
|
||||
apiServer:
|
||||
@@ -171,9 +171,14 @@ extension K8sHelper {
|
||||
"""
|
||||
}
|
||||
|
||||
private static func kubernetesVersion() -> String {
|
||||
/// kubeadm needs the exact version, and only the tag carries it.
|
||||
static func kubernetesVersion(nodeImage: String) throws -> String {
|
||||
let nameAndTag = nodeImage.split(separator: "@").first.map(String.init) ?? nodeImage
|
||||
guard let ref = try? Reference.parse(nameAndTag), let tag = ref.tag else { return "v1.35" }
|
||||
guard let ref = try? Reference.parse(nameAndTag), let tag = ref.tag else {
|
||||
throw ContainerizationError(
|
||||
.invalidArgument,
|
||||
message: "node image \(nodeImage) has no tag; use a tagged image such as docker.io/kindest/node:v1.34.11")
|
||||
}
|
||||
return tag
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Copyright © 2026 Apple Inc. and the container project 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
|
||||
//
|
||||
// https://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.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import Testing
|
||||
|
||||
@testable import ContainerK8s
|
||||
|
||||
struct K8sNodeImageVersionTests {
|
||||
@Test
|
||||
func versionComesFromTheGivenImage() throws {
|
||||
#expect(try K8sHelper.kubernetesVersion(nodeImage: "docker.io/kindest/node:v1.34.11") == "v1.34.11")
|
||||
}
|
||||
|
||||
@Test
|
||||
func versionComesFromTagWhenDigestIsPresent() throws {
|
||||
let image = "docker.io/kindest/node:v1.34.11@sha256:0000000000000000000000000000000000000000000000000000000000000000"
|
||||
#expect(try K8sHelper.kubernetesVersion(nodeImage: image) == "v1.34.11")
|
||||
}
|
||||
|
||||
@Test
|
||||
func defaultImageStillResolves() throws {
|
||||
#expect(try K8sHelper.kubernetesVersion(nodeImage: K8sHelper.nodeImage) == "v1.35.5")
|
||||
}
|
||||
|
||||
@Test
|
||||
func untaggedImageThrows() {
|
||||
#expect(throws: (any Error).self) {
|
||||
try K8sHelper.kubernetesVersion(nodeImage: "docker.io/kindest/node")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
func digestOnlyImageThrows() {
|
||||
let image = "docker.io/kindest/node@sha256:0000000000000000000000000000000000000000000000000000000000000000"
|
||||
#expect(throws: (any Error).self) {
|
||||
try K8sHelper.kubernetesVersion(nodeImage: image)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user