diff --git a/Sources/ContainerK8s/Commands/K8sStart.swift b/Sources/ContainerK8s/Commands/K8sStart.swift deleted file mode 100644 index ae792ba4..00000000 --- a/Sources/ContainerK8s/Commands/K8sStart.swift +++ /dev/null @@ -1,74 +0,0 @@ -//===----------------------------------------------------------------------===// -// 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 ArgumentParser -import ContainerAPIClient -import ContainerLog -import ContainerResource -import ContainerizationError -import Foundation -import Logging - -public struct K8sStart: AsyncParsableCommand { - public init() {} - - public static let configuration = CommandConfiguration( - commandName: "start", - abstract: "Start a stopped Kubernetes cluster" - ) - - @Option(name: .long, help: "Cluster name (default: \(K8sHelper.defaultName))") - var name: String = K8sHelper.defaultName - - public func run() async throws { - LoggingSystem.bootstrap { _ in StderrLogHandler() } - let log = Logger(label: K8sHelper.pluginName) - - let client = ContainerClient() - let container = try await client.get(id: name) - - guard container.configuration.labels[ResourceLabelKeys.plugin] == K8sHelper.pluginName else { - log.error("container is not a k8s cluster, refusing start", metadata: ["name": "\(name)"]) - throw ContainerizationError(.invalidArgument, message: "\(name) is not a k8s cluster") - } - - if container.status == .running { - print(name) - return - } - - let io = try ProcessIO.create(tty: false, interactive: false, detach: true) - defer { try? io.close() } - let process = try await client.bootstrap(id: name, stdio: io.stdio) - try await process.start() - try io.closeAfterStart() - - try await K8sHelper.waitForNodeBooted(containerId: name, client: client, log: log) - try await K8sHelper.waitForReady(containerId: name, client: client, log: log) - - do { - let fqdn = await K8sHelper.detectFQDN(name: name) - let rawConfig = try await K8sHelper.fetchConfig(containerId: name, client: client, log: log) - let config = try await K8sHelper.transformConfig(rawConfig, containerId: name, fqdn: fqdn, client: client) - try K8sHelper.mergeConfig(config, containerId: name, log: log) - } catch { - log.warning("failed to write kubeconfig", metadata: ["name": "\(name)", "error": "\(error)"]) - log.info("cluster is running; use 'container k8s write-config --name \(name)' to write the kubeconfig") - } - - print(name) - } -} diff --git a/Sources/Plugins/K8s/K8sCommand.swift b/Sources/Plugins/K8s/K8sCommand.swift index af2e184f..285828c8 100644 --- a/Sources/Plugins/K8s/K8sCommand.swift +++ b/Sources/Plugins/K8s/K8sCommand.swift @@ -52,7 +52,6 @@ public struct K8sCommand: AsyncParsableCommand { K8sDelete.self, K8sList.self, K8sLoadImage.self, - K8sStart.self, K8sWriteConfig.self, ] ) diff --git a/docs/command-reference.md b/docs/command-reference.md index 9361036a..827b18f2 100644 --- a/docs/command-reference.md +++ b/docs/command-reference.md @@ -1649,30 +1649,6 @@ container k8s create --name temp-cluster --rm container k8s create --cni ./my-cni.yaml ``` -### `container k8s start` - -Starts a stopped Kubernetes cluster and refreshes its entry in `~/.kube/config` (the container IP can change between starts). - -**Usage** - -```bash -container k8s start [--name ] [--debug] -``` - -**Options** - -* `--name `: Cluster name (default: `k8s-dev`) - -**Examples** - -```bash -# start the default cluster -container k8s start - -# start a named cluster -container k8s start --name my-cluster -``` - ### `container k8s delete (rm)` Stops and deletes a Kubernetes cluster container and removes its entry from `~/.kube/config`. @@ -1749,7 +1725,7 @@ container k8s load-image --platform linux/amd64 my-app:latest ### `container k8s write-config` -Fetches the current kubeconfig from a running cluster and merges its context into a kubeconfig file. Use this to refresh credentials after a cluster restart or to write to an alternate config file. +Fetches the current kubeconfig from a running cluster and merges its context into a kubeconfig file. Use this to write to an alternate config file. **Usage** diff --git a/docs/kubernetes.md b/docs/kubernetes.md index 9e3e73a8..36fb2b84 100644 --- a/docs/kubernetes.md +++ b/docs/kubernetes.md @@ -199,6 +199,15 @@ To have a cluster automatically remove itself when stopped, create it with `--rm container k8s create --name temp-cluster --rm ``` +### Recovering a stopped cluster + +If a cluster's control plane node stops (for example, after `container stop`), delete and re-create the cluster: + +```bash +container k8s delete --name my-cluster +container k8s create --name my-cluster +``` + ## Common workflows ### Test a deployment locally before production