Added kubeadm init

This commit is contained in:
2026-03-30 01:31:38 +08:00
parent 5fbc2846a1
commit 210fabdcc6
7 changed files with 419 additions and 102 deletions

View File

@@ -1,6 +1,7 @@
package node
import (
"bytes"
"context"
"errors"
"fmt"
@@ -9,16 +10,20 @@ import (
"strings"
"time"
"gopkg.in/yaml.v3"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/discovery"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/klog/v2"
system "undecided.project/monok8s/pkg/system"
)
const (
adminKubeconfigPath = "/etc/kubernetes/admin.conf"
kubeletKubeconfigPath = "/etc/kubernetes/kubelet.conf"
tmpKubeadmInitConf = "/tmp/kubeadm-init.yaml"
)
func DetectLocalClusterState(ctx context.Context, nctx *NodeContext) error {
@@ -64,11 +69,16 @@ func DetectLocalClusterState(ctx context.Context, nctx *NodeContext) error {
}
func WaitForExistingClusterIfNeeded(ctx context.Context, nctx *NodeContext) error {
if nctx.LocalClusterState == nil {
return errors.New("LocalClusterState is nil, please run dependency step first")
}
switch nctx.LocalClusterState.MembershipKind {
case LocalMembershipFresh:
klog.V(4).Infof("Nothing to to do LocalMembershipFresh")
return nil
case LocalMembershipExistingWorker:
klog.V(4).Infof("Starting Kubelet in LocalMembershipExistingWorker")
if err := StartKubelet(ctx, nctx); err != nil {
return fmt.Errorf("start kubelet: %w", err)
}
@@ -79,6 +89,7 @@ func WaitForExistingClusterIfNeeded(ctx context.Context, nctx *NodeContext) erro
return fmt.Errorf("start kubelet: %w", err)
}
klog.V(4).Infof("Waiting for local apiserver in LocalMembershipExistingControlPlane")
// Existing local control-plane state: wait for local apiserver if this
// machine is meant to be a control-plane node.
if strings.TrimSpace(nctx.Config.Spec.ClusterRole) == "control-plane" {
@@ -92,7 +103,6 @@ func WaitForExistingClusterIfNeeded(ctx context.Context, nctx *NodeContext) erro
return nil
case LocalMembershipPartial:
// Be strict here. Partial state is suspicious.
return fmt.Errorf("partial local cluster state detected: admin=%t kubelet=%t",
nctx.LocalClusterState.HasAdminKubeconfig,
nctx.LocalClusterState.HasKubeletKubeconfig,
@@ -543,20 +553,224 @@ func normalizeKubeVersion(v string) string {
return v
}
func GenerateKubeadmConfig(context.Context, *NodeContext) error {
klog.Info("generate_kubeadm_config: TODO render kubeadm v1beta4 config from MonoKSConfig")
func GenerateKubeadmConfig(_ context.Context, nctx *NodeContext) error {
if nctx == nil {
return fmt.Errorf("node context is nil")
}
spec := nctx.Config.Spec
advertiseAddress := strings.TrimSpace(spec.APIServerAdvertiseAddress)
if advertiseAddress == "" {
return fmt.Errorf("api server advertise address is required")
}
nodeName := strings.TrimSpace(spec.NodeName)
if nodeName == "" {
return fmt.Errorf("node name is required")
}
criSocket := strings.TrimSpace(spec.ContainerRuntimeEndpoint)
if criSocket == "" {
return fmt.Errorf("container runtime endpoint is required")
}
clusterName := strings.TrimSpace(spec.ClusterName)
if clusterName == "" {
return fmt.Errorf("cluster name is required")
}
kubernetesVersion := strings.TrimSpace(spec.KubernetesVersion)
if kubernetesVersion == "" {
return fmt.Errorf("kubernetes version is required")
}
podSubnet := strings.TrimSpace(spec.PodSubnet)
if podSubnet == "" {
return fmt.Errorf("pod subnet is required")
}
serviceSubnet := strings.TrimSpace(spec.ServiceSubnet)
if serviceSubnet == "" {
return fmt.Errorf("service subnet is required")
}
clusterDomain := strings.TrimSpace(spec.ClusterDomain)
if clusterDomain == "" {
return fmt.Errorf("cluster domain is required")
}
certSANs := []string{advertiseAddress}
seen := map[string]struct{}{
advertiseAddress: {},
}
for _, raw := range spec.SubjectAltNames {
san := strings.TrimSpace(raw)
if san == "" {
continue
}
if _, ok := seen[san]; ok {
continue
}
seen[san] = struct{}{}
certSANs = append(certSANs, san)
}
type kubeadmInitConfiguration struct {
APIVersion string `yaml:"apiVersion"`
Kind string `yaml:"kind"`
LocalAPIEndpoint struct {
AdvertiseAddress string `yaml:"advertiseAddress"`
BindPort int `yaml:"bindPort"`
} `yaml:"localAPIEndpoint"`
NodeRegistration struct {
Name string `yaml:"name"`
CRISocket string `yaml:"criSocket"`
ImagePullPolicy string `yaml:"imagePullPolicy"`
KubeletExtraArgs []struct {
Name string `yaml:"name"`
Value string `yaml:"value"`
} `yaml:"kubeletExtraArgs"`
} `yaml:"nodeRegistration"`
}
type kubeadmClusterConfiguration struct {
APIVersion string `yaml:"apiVersion"`
Kind string `yaml:"kind"`
ClusterName string `yaml:"clusterName"`
KubernetesVersion string `yaml:"kubernetesVersion"`
Networking struct {
PodSubnet string `yaml:"podSubnet"`
ServiceSubnet string `yaml:"serviceSubnet"`
DNSDomain string `yaml:"dnsDomain"`
} `yaml:"networking"`
APIServer struct {
CertSANs []string `yaml:"certSANs"`
} `yaml:"apiServer"`
}
type kubeletConfiguration struct {
APIVersion string `yaml:"apiVersion"`
Kind string `yaml:"kind"`
CgroupDriver string `yaml:"cgroupDriver"`
ContainerRuntimeEndpoint string `yaml:"containerRuntimeEndpoint"`
}
initCfg := kubeadmInitConfiguration{
APIVersion: "kubeadm.k8s.io/v1beta4",
Kind: "InitConfiguration",
}
initCfg.LocalAPIEndpoint.AdvertiseAddress = advertiseAddress
initCfg.LocalAPIEndpoint.BindPort = 6443
initCfg.NodeRegistration.Name = nodeName
initCfg.NodeRegistration.CRISocket = criSocket
initCfg.NodeRegistration.ImagePullPolicy = "IfNotPresent"
initCfg.NodeRegistration.KubeletExtraArgs = []struct {
Name string `yaml:"name"`
Value string `yaml:"value"`
}{
{Name: "hostname-override", Value: nodeName},
{Name: "node-ip", Value: advertiseAddress},
{Name: "pod-manifest-path", Value: "/etc/kubernetes/manifests"},
}
clusterCfg := kubeadmClusterConfiguration{
APIVersion: "kubeadm.k8s.io/v1beta4",
Kind: "ClusterConfiguration",
ClusterName: clusterName,
KubernetesVersion: kubernetesVersion,
}
clusterCfg.Networking.PodSubnet = podSubnet
clusterCfg.Networking.ServiceSubnet = serviceSubnet
clusterCfg.Networking.DNSDomain = clusterDomain
clusterCfg.APIServer.CertSANs = certSANs
kubeletCfg := kubeletConfiguration{
APIVersion: "kubelet.config.k8s.io/v1beta1",
Kind: "KubeletConfiguration",
CgroupDriver: "cgroupfs",
ContainerRuntimeEndpoint: criSocket,
}
var docs [][]byte
for _, doc := range []any{initCfg, clusterCfg, kubeletCfg} {
b, err := yaml.Marshal(doc)
if err != nil {
return fmt.Errorf("marshal kubeadm config document: %w", err)
}
docs = append(docs, bytes.TrimSpace(b))
}
var buf bytes.Buffer
for i, doc := range docs {
if i > 0 {
buf.WriteString("\n---\n")
}
buf.Write(doc)
buf.WriteByte('\n')
}
rendered := buf.String()
if err := os.WriteFile(tmpKubeadmInitConf, []byte(rendered), 0o600); err != nil {
return fmt.Errorf("write kubeadm config to %s: %w", tmpKubeadmInitConf, err)
}
klog.V(4).Infof("generated kubeadm config at %s:\n%s", tmpKubeadmInitConf, rendered)
return nil
}
func RunKubeadmInit(context.Context, *NodeContext) error {
klog.Info("run_kubeadm_init: TODO implement kubeadm init --config <file>")
return nil
func RunKubeadmInit(ctx context.Context, nctx *NodeContext) error {
if err := GenerateKubeadmConfig(ctx, nctx); err != nil {
return err
}
_, err := nctx.SystemRunner.RunWithOptions(
ctx,
"kubeadm",
[]string{"init", "--config", tmpKubeadmInitConf},
system.RunOptions{
Timeout: 10 * time.Minute,
OnStdoutLine: func(line string) { klog.Infof("[kubeadm] %s", line) },
OnStderrLine: func(line string) { klog.Infof("[kubeadm] %s", line) },
},
)
return err
}
func RunKubeadmUpgradeApply(context.Context, *NodeContext) error {
klog.Info("run_kubeadm_upgrade_apply: TODO implement kubeadm upgrade apply")
return nil
}
func RunKubeadmJoin(context.Context, *NodeContext) error {
klog.Info("run_kubeadm_join: TODO implement kubeadm join")
/*
run_kubeadm_join() {
log "running kubeadm join..."
case "$JOIN_KIND" in
worker)
kubeadm join "${API_SERVER_ENDPOINT}" \
--token "${BOOTSTRAP_TOKEN}" \
--discovery-token-ca-cert-hash "${DISCOVERY_TOKEN_CA_CERT_HASH}" \
--node-name "${NODE_NAME}" \
--cri-socket "${CONTAINER_RUNTIME_ENDPOINT}"
;;
control-plane)
kubeadm join "${API_SERVER_ENDPOINT}" \
--token "${BOOTSTRAP_TOKEN}" \
--discovery-token-ca-cert-hash "${DISCOVERY_TOKEN_CA_CERT_HASH}" \
--control-plane \
--certificate-key "${CONTROL_PLANE_CERT_KEY}" \
--apiserver-advertise-address "${APISERVER_ADVERTISE_ADDRESS}" \
--node-name "${NODE_NAME}" \
--cri-socket "${CONTAINER_RUNTIME_ENDPOINT}"
;;
esac
}
*/
return nil
}
func RunKubeadmUpgradeNode(context.Context, *NodeContext) error {