Added kubeadm init
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user