commit 0aa4065c264719c5cc3cff547bac43e6ee52342305236cb2126f053bbf0e541b
| author | 斟酌 鵬兄 <tgckpg@gmail.com> |
| date | 2026-03-30T09:40:27Z |
| subject | Added join step |
commit 0aa4065c264719c5cc3cff547bac43e6ee52342305236cb2126f053bbf0e541b
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date: 2026-03-30T09:40:27Z
Added join step
---
clitools/README | 33 ++++
clitools/pkg/bootstrap/registry.go | 2 +-
clitools/pkg/bootstrap/runner.go | 15 +-
clitools/pkg/node/context.go | 14 +-
clitools/pkg/node/kubeadm.go | 366 ++++++++++++++++++++++--------------
clitools/pkg/node/kubeadm_types.go | 81 ++++++++
clitools/pkg/templates/templates.go | 4 +-
7 files changed, 363 insertions(+), 152 deletions(-)
diff --git a/clitools/README b/clitools/README
index 5e1e863..6928473 100644
--- a/clitools/README
+++ b/clitools/README
@@ -26,3 +26,36 @@ And use it like this
```bash
./send.sh start_crio
```
+
+
+Create join token from control plane
+```
+kubeadm token create --print-join-command
+```
+
+Export the token inside the device
+```
+export DEBUG=1
+export HOSTNAME=monok8s-master-1
+export BOOTSTRAP_TOKEN=
+export TOKEN_CACERT_HASH=
+```
+
+Generate using kubectl
+```
+TOKEN_NAME=bootstrap-token-iwotl0
+
+API_SERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}' | sed 's|https://||') && \
+TOKEN=$(kubectl -n kube-system get secret ${TOKEN_NAME} -o jsonpath='{.data.token-id}' | base64 -d).$(kubectl -n kube-system get secret ${TOKEN_NAME} -o jsonpath='{.data.token-secret}' | base64 -d) && \
+HASH=$(kubectl -n kube-public get configmap cluster-info -o jsonpath='{.data.kubeconfig}' \
+| grep 'certificate-authority-data' \
+| awk '{print $2}' \
+| base64 -d \
+| openssl x509 -pubkey -noout \
+| openssl rsa -pubin -outform der 2>/dev/null \
+| openssl dgst -sha256 -hex \
+| awk '{print "sha256:" $2}')
+echo "export API_SERVER_ENDPOINT=${API_SERVER}"
+echo "export BOOTSTRAP_TOKEN=${TOKEN}"
+echo "export TOKEN_CACERT_HASH=${HASH}"
+```
diff --git a/clitools/pkg/bootstrap/registry.go b/clitools/pkg/bootstrap/registry.go
index 560b17e..ff84686 100644
--- a/clitools/pkg/bootstrap/registry.go
+++ b/clitools/pkg/bootstrap/registry.go
@@ -24,6 +24,7 @@ func NewRegistry(ctx *node.NodeContext) *Registry {
steps: map[string]node.Step{
"AllowSingleNodeScheduling": node.AllowSingleNodeScheduling,
"ApplyLocalNodeMetadataIfPossible": node.ApplyLocalNodeMetadataIfPossible,
+ "CheckForVersionSkew": node.CheckForVersionSkew,
"CheckUpgradePrereqs": node.CheckUpgradePrereqs,
"ClassifyBootstrapAction": node.ClassifyBootstrapAction,
"ConfigureDNS": node.ConfigureDNS(netCfg),
@@ -32,7 +33,6 @@ func NewRegistry(ctx *node.NodeContext) *Registry {
"ConfigureMgmtInterface": node.ConfigureMgmtInterface(netCfg),
"DetectLocalClusterState": node.DetectLocalClusterState,
"EnsureIPForward": node.EnsureIPForward,
- "GenerateKubeadmConfig": node.GenerateKubeadmConfig,
"PrintSummary": node.PrintSummary,
"ReconcileControlPlane": node.ReconcileControlPlane,
"ReconcileNode": node.ReconcileNode,
diff --git a/clitools/pkg/bootstrap/runner.go b/clitools/pkg/bootstrap/runner.go
index ae13886..9f3d0c7 100644
--- a/clitools/pkg/bootstrap/runner.go
+++ b/clitools/pkg/bootstrap/runner.go
@@ -86,6 +86,16 @@ func NewRunner(cfg *monov1alpha1.MonoKSConfig) *Runner {
Name: "Classify bootstrap action",
Desc: "Decide whether to init, join, upgrade, or reconcile based on local state and desired version",
},
+ {
+ RegKey: "CheckForVersionSkew",
+ Name: "Check for version skew",
+ Desc: "Validate wether version satisfy the requirements againts current cluster if any",
+ },
+ {
+ RegKey: "RunKubeadmInit",
+ Name: "Run kubeadm init",
+ Desc: "Initialize a new Kubernetes control plane using kubeadm",
+ },
{
RegKey: "WaitForExistingClusterIfNeeded",
Name: "Wait for existing cluster",
@@ -106,11 +116,6 @@ func NewRunner(cfg *monov1alpha1.MonoKSConfig) *Runner {
Name: "Run kubeadm upgrade apply",
Desc: "Upgrade control plane components using kubeadm",
},
- {
- RegKey: "RunKubeadmInit",
- Name: "Run kubeadm init",
- Desc: "Initialize a new Kubernetes control plane using kubeadm",
- },
{
RegKey: "RunKubeadmJoin",
Name: "Run kubeadm join",
diff --git a/clitools/pkg/node/context.go b/clitools/pkg/node/context.go
index ba01c63..0b523d0 100644
--- a/clitools/pkg/node/context.go
+++ b/clitools/pkg/node/context.go
@@ -34,13 +34,17 @@ type LocalClusterState struct {
type BootstrapAction string
const (
- BootstrapActionInitControlPlane BootstrapAction = "init-control-plane"
- BootstrapActionJoinWorker BootstrapAction = "join-worker"
- BootstrapActionJoinControlPlane BootstrapAction = "join-control-plane"
- BootstrapActionReconcileWorker BootstrapAction = "reconcile-worker"
+ BootstrapActionInitControlPlane BootstrapAction = "init-control-plane"
+ BootstrapActionJoinControlPlane BootstrapAction = "join-control-plane"
+ BootstrapActionManageControlPlane BootstrapAction = "manage-control-plane"
+
+ BootstrapActionJoinWorker BootstrapAction = "join-worker"
+ BootstrapActionManageWorker BootstrapAction = "manage-worker"
+
BootstrapActionReconcileControlPlane BootstrapAction = "reconcile-control-plane"
- BootstrapActionUpgradeWorker BootstrapAction = "upgrade-worker"
BootstrapActionUpgradeControlPlane BootstrapAction = "upgrade-control-plane"
+ BootstrapActionReconcileWorker BootstrapAction = "reconcile-worker"
+ BootstrapActionUpgradeWorker BootstrapAction = "upgrade-worker"
)
type BootstrapState struct {
diff --git a/clitools/pkg/node/kubeadm.go b/clitools/pkg/node/kubeadm.go
index f3fb5f7..fd943ce 100644
--- a/clitools/pkg/node/kubeadm.go
+++ b/clitools/pkg/node/kubeadm.go
@@ -17,6 +17,7 @@ import (
"k8s.io/client-go/tools/clientcmd"
"k8s.io/klog/v2"
+ types "undecided.project/monok8s/pkg/apis/monok8s/v1alpha1"
system "undecided.project/monok8s/pkg/system"
)
@@ -114,6 +115,10 @@ func WaitForExistingClusterIfNeeded(ctx context.Context, nctx *NodeContext) erro
}
func CheckForVersionSkew(ctx context.Context, nctx *NodeContext) error {
+ if nctx.BootstrapState == nil {
+ return errors.New("BootstrapState is nil, call ClassifyBootstrapAction() first")
+ }
+
role := strings.TrimSpace(nctx.Config.Spec.ClusterRole)
wantVersion := normalizeKubeVersion(strings.TrimSpace(nctx.Config.Spec.KubernetesVersion))
if wantVersion == "" {
@@ -122,7 +127,7 @@ func CheckForVersionSkew(ctx context.Context, nctx *NodeContext) error {
switch nctx.LocalClusterState.MembershipKind {
case LocalMembershipFresh:
- // Fresh node has no existing cluster membership to compare against.
+ // Nothing to compare for fresh nodes.
return nil
case LocalMembershipPartial:
return fmt.Errorf("cannot check version skew with partial local cluster state")
@@ -142,6 +147,10 @@ func CheckForVersionSkew(ctx context.Context, nctx *NodeContext) error {
// Worker path stays permissive.
nctx.BootstrapState.UnsupportedWorkerVersionSkew = true
nctx.BootstrapState.VersionSkewReason = "cluster version could not be determined"
+
+ if nctx.BootstrapState.Action == BootstrapActionManageWorker {
+ nctx.BootstrapState.Action = BootstrapActionReconcileWorker
+ }
return nil
}
@@ -156,6 +165,14 @@ func CheckForVersionSkew(ctx context.Context, nctx *NodeContext) error {
)
}
+ if nctx.BootstrapState.Action == BootstrapActionManageControlPlane {
+ if versionEq(currentVersion, wantVersion) {
+ nctx.BootstrapState.Action = BootstrapActionReconcileControlPlane
+ } else {
+ nctx.BootstrapState.Action = BootstrapActionUpgradeControlPlane
+ }
+ }
+
case "worker":
if !isSupportedWorkerSkew(currentVersion, wantVersion) {
nctx.BootstrapState.UnsupportedWorkerVersionSkew = true
@@ -165,6 +182,14 @@ func CheckForVersionSkew(ctx context.Context, nctx *NodeContext) error {
)
}
+ if nctx.BootstrapState.Action == BootstrapActionManageWorker {
+ if versionEq(currentVersion, wantVersion) {
+ nctx.BootstrapState.Action = BootstrapActionReconcileWorker
+ } else {
+ nctx.BootstrapState.Action = BootstrapActionUpgradeWorker
+ }
+ }
+
default:
return fmt.Errorf("unsupported cluster role %q", role)
}
@@ -187,10 +212,8 @@ func ClassifyBootstrapAction(ctx context.Context, nctx *NodeContext) error {
}
state := &BootstrapState{}
-
- // Preserve already-detected info if earlier steps populated it.
if nctx.BootstrapState != nil {
- state.DetectedClusterVersion = nctx.BootstrapState.DetectedClusterVersion
+ *state = *nctx.BootstrapState
}
switch role {
@@ -200,13 +223,7 @@ func ClassifyBootstrapAction(ctx context.Context, nctx *NodeContext) error {
state.Action = BootstrapActionJoinWorker
case LocalMembershipExistingWorker:
- if state.DetectedClusterVersion == "" {
- state.Action = BootstrapActionReconcileWorker
- } else if versionEq(state.DetectedClusterVersion, wantVersion) {
- state.Action = BootstrapActionReconcileWorker
- } else {
- state.Action = BootstrapActionUpgradeWorker
- }
+ state.Action = BootstrapActionManageWorker
case LocalMembershipExistingControlPlane, LocalMembershipPartial:
return fmt.Errorf("local state %q is invalid for worker role", nctx.LocalClusterState.MembershipKind)
@@ -225,15 +242,7 @@ func ClassifyBootstrapAction(ctx context.Context, nctx *NodeContext) error {
}
case LocalMembershipExistingControlPlane:
- if state.DetectedClusterVersion == "" {
- return errors.New("existing control-plane state found, but detected cluster version is empty")
- }
-
- if versionEq(state.DetectedClusterVersion, wantVersion) {
- state.Action = BootstrapActionReconcileControlPlane
- } else {
- state.Action = BootstrapActionUpgradeControlPlane
- }
+ state.Action = BootstrapActionManageControlPlane
case LocalMembershipExistingWorker:
return fmt.Errorf("local state %q is invalid for control-plane role", nctx.LocalClusterState.MembershipKind)
@@ -250,7 +259,7 @@ func ClassifyBootstrapAction(ctx context.Context, nctx *NodeContext) error {
}
nctx.BootstrapState = state
- klog.V(4).Infof("Bootstrap action: %+v", *state)
+ klog.V(4).Infof("Bootstrap action classified: %+v", *state)
return nil
}
@@ -521,7 +530,10 @@ func checkImagePresent(ctx context.Context, n *NodeContext, image string) error
}
// crictl inspecti exits non-zero when the image is absent.
- _, err := n.SystemRunner.Run(ctx, "crictl", "inspecti", image)
+ _, err := n.SystemRunner.RunRetry(ctx, system.RetryOptions{
+ Attempts: 3,
+ Delay: 1 * system.DefaultSecond,
+ }, "crictl", "inspecti", image)
if err != nil {
return fmt.Errorf("image %q not present: %w", image, err)
}
@@ -553,7 +565,43 @@ func normalizeKubeVersion(v string) string {
return v
}
-func GenerateKubeadmConfig(_ context.Context, nctx *NodeContext) error {
+func buildNodeRegistration(spec types.MonoKSConfigSpec) NodeRegistrationOptions {
+ nodeName := strings.TrimSpace(spec.NodeName)
+ criSocket := strings.TrimSpace(spec.ContainerRuntimeEndpoint)
+ advertiseAddress := strings.TrimSpace(spec.APIServerAdvertiseAddress)
+
+ nr := NodeRegistrationOptions{
+ Name: nodeName,
+ CRISocket: criSocket,
+ ImagePullPolicy: "IfNotPresent",
+ KubeletExtraArgs: []KubeadmArg{
+ {Name: "hostname-override", Value: nodeName},
+ {Name: "pod-manifest-path", Value: "/etc/kubernetes/manifests"},
+ },
+ }
+
+ if advertiseAddress != "" {
+ nr.KubeletExtraArgs = append(nr.KubeletExtraArgs,
+ KubeadmArg{Name: "node-ip", Value: advertiseAddress},
+ )
+ }
+
+ return nr
+}
+
+func maybeAddBootstrapTaint(nr *NodeRegistrationOptions, role string) {
+ if strings.TrimSpace(role) != "worker" {
+ return
+ }
+ nr.Taints = []KubeadmTaint{
+ {
+ Key: "monok8s/bootstrap",
+ Effect: "NoSchedule",
+ },
+ }
+}
+
+func GenerateKubeadmInitConfig(_ context.Context, nctx *NodeContext) error {
if nctx == nil {
return fmt.Errorf("node context is nil")
}
@@ -564,47 +612,29 @@ func GenerateKubeadmConfig(_ context.Context, nctx *NodeContext) error {
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: {},
- }
-
+ seen := map[string]struct{}{advertiseAddress: {}}
for _, raw := range spec.SubjectAltNames {
san := strings.TrimSpace(raw)
if san == "" {
@@ -617,94 +647,129 @@ func GenerateKubeadmConfig(_ context.Context, nctx *NodeContext) error {
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{
+ nodeReg := buildNodeRegistration(spec)
+ if spec.ClusterRole == "worker" {
+ maybeAddBootstrapTaint(&nodeReg, spec.ClusterRole)
+ }
+
+ initCfg := InitConfiguration{
APIVersion: "kubeadm.k8s.io/v1beta4",
Kind: "InitConfiguration",
+ LocalAPIEndpoint: LocalAPIEndpoint{
+ AdvertiseAddress: advertiseAddress,
+ BindPort: 6443,
+ },
+ NodeRegistration: nodeReg,
}
- 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{
+
+ clusterCfg := ClusterConfiguration{
APIVersion: "kubeadm.k8s.io/v1beta4",
Kind: "ClusterConfiguration",
ClusterName: clusterName,
KubernetesVersion: kubernetesVersion,
+ Networking: Networking{
+ PodSubnet: podSubnet,
+ ServiceSubnet: serviceSubnet,
+ DNSDomain: clusterDomain,
+ },
+ APIServer: APIServer{
+ CertSANs: certSANs,
+ },
}
- clusterCfg.Networking.PodSubnet = podSubnet
- clusterCfg.Networking.ServiceSubnet = serviceSubnet
- clusterCfg.Networking.DNSDomain = clusterDomain
- clusterCfg.APIServer.CertSANs = certSANs
- kubeletCfg := kubeletConfiguration{
+ kubeletCfg := KubeletConfiguration{
APIVersion: "kubelet.config.k8s.io/v1beta1",
Kind: "KubeletConfiguration",
CgroupDriver: "cgroupfs",
- ContainerRuntimeEndpoint: criSocket,
+ ContainerRuntimeEndpoint: strings.TrimSpace(spec.ContainerRuntimeEndpoint),
}
- var docs [][]byte
+ return writeKubeadmYAML(tmpKubeadmInitConf, initCfg, clusterCfg, kubeletCfg)
+}
- for _, doc := range []any{initCfg, clusterCfg, kubeletCfg} {
+func GenerateKubeadmJoinConfig(_ context.Context, nctx *NodeContext) error {
+ if nctx == nil {
+ return fmt.Errorf("node context is nil")
+ }
+
+ spec := nctx.Config.Spec
+
+ apiServerEndpoint := strings.TrimSpace(spec.APIServerEndpoint)
+ if apiServerEndpoint == "" {
+ return fmt.Errorf("spec.apiServerEndpoint is required")
+ }
+
+ bootstrapToken := strings.TrimSpace(spec.BootstrapToken)
+ if bootstrapToken == "" {
+ return fmt.Errorf("spec.bootstrapToken is required")
+ }
+
+ discoveryTokenCACertHash := strings.TrimSpace(spec.DiscoveryTokenCACertHash)
+ if discoveryTokenCACertHash == "" {
+ return fmt.Errorf("spec.discoveryTokenCACertHash is required")
+ }
+
+ nodeReg := buildNodeRegistration(spec)
+ if nctx.BootstrapState != nil && nctx.BootstrapState.Action == BootstrapActionJoinWorker {
+ maybeAddBootstrapTaint(&nodeReg, spec.ClusterRole)
+ }
+
+ joinCfg := JoinConfiguration{
+ APIVersion: "kubeadm.k8s.io/v1beta4",
+ Kind: "JoinConfiguration",
+ NodeRegistration: nodeReg,
+ Discovery: Discovery{
+ BootstrapToken: BootstrapTokenDiscovery{
+ APIServerEndpoint: apiServerEndpoint,
+ Token: bootstrapToken,
+ CACertHashes: []string{discoveryTokenCACertHash},
+ },
+ },
+ }
+
+ if nctx.BootstrapState != nil && nctx.BootstrapState.Action == BootstrapActionJoinControlPlane {
+ certKey := strings.TrimSpace(spec.ControlPlaneCertKey)
+ if certKey == "" {
+ return fmt.Errorf("spec.controlPlaneCertKey is required for control-plane join")
+ }
+
+ advertiseAddress := strings.TrimSpace(spec.APIServerAdvertiseAddress)
+ if advertiseAddress == "" {
+ return fmt.Errorf("spec.apiServerAdvertiseAddress is required for control-plane join")
+ }
+
+ joinCfg.ControlPlane = &JoinControlPlane{
+ CertificateKey: certKey,
+ }
+ joinCfg.LocalAPIEndpoint = &LocalAPIEndpoint{
+ AdvertiseAddress: advertiseAddress,
+ BindPort: 6443,
+ }
+ }
+
+ kubeletCfg := KubeletConfiguration{
+ APIVersion: "kubelet.config.k8s.io/v1beta1",
+ Kind: "KubeletConfiguration",
+ CgroupDriver: "cgroupfs",
+ ContainerRuntimeEndpoint: strings.TrimSpace(spec.ContainerRuntimeEndpoint),
+ }
+
+ return writeKubeadmYAML(tmpKubeadmInitConf, joinCfg, kubeletCfg)
+}
+
+func writeKubeadmYAML(path string, docs ...any) error {
+ var renderedDocs [][]byte
+
+ for _, doc := range docs {
b, err := yaml.Marshal(doc)
if err != nil {
return fmt.Errorf("marshal kubeadm config document: %w", err)
}
- docs = append(docs, bytes.TrimSpace(b))
+ renderedDocs = append(renderedDocs, bytes.TrimSpace(b))
}
var buf bytes.Buffer
- for i, doc := range docs {
+ for i, doc := range renderedDocs {
if i > 0 {
buf.WriteString("\n---\n")
}
@@ -714,16 +779,25 @@ func GenerateKubeadmConfig(_ context.Context, nctx *NodeContext) error {
rendered := buf.String()
- if err := os.WriteFile(tmpKubeadmInitConf, []byte(rendered), 0o600); err != nil {
- return fmt.Errorf("write kubeadm config to %s: %w", tmpKubeadmInitConf, err)
+ if err := os.WriteFile(path, []byte(rendered), 0o600); err != nil {
+ return fmt.Errorf("write kubeadm config to %s: %w", path, err)
}
- klog.V(4).Infof("generated kubeadm config at %s:\n%s", tmpKubeadmInitConf, rendered)
+ klog.V(4).Infof("generated kubeadm config at %s:\n%s", path, rendered)
return nil
}
func RunKubeadmInit(ctx context.Context, nctx *NodeContext) error {
- if err := GenerateKubeadmConfig(ctx, nctx); err != nil {
+ if nctx.BootstrapState == nil {
+ return errors.New("BootstrapState is nil. Please run earlier steps first")
+ }
+
+ if nctx.BootstrapState.Action != BootstrapActionInitControlPlane {
+ klog.V(4).Infof("skipped for %s", nctx.BootstrapState.Action)
+ return nil
+ }
+
+ if err := GenerateKubeadmInitConfig(ctx, nctx); err != nil {
return err
}
@@ -740,39 +814,51 @@ func RunKubeadmInit(ctx context.Context, nctx *NodeContext) error {
return err
}
-func RunKubeadmUpgradeApply(context.Context, *NodeContext) error {
- klog.Info("run_kubeadm_upgrade_apply: TODO implement kubeadm upgrade apply")
+func RunKubeadmJoin(ctx context.Context, nctx *NodeContext) error {
+ if nctx.BootstrapState == nil {
+ return errors.New("BootstrapState is nil. Please run earlier steps first")
+ }
+
+ switch nctx.BootstrapState.Action {
+ case BootstrapActionJoinWorker, BootstrapActionJoinControlPlane:
+ // continue
+ default:
+ klog.V(4).Infof("RunKubeadmJoin skipped for action %q", nctx.BootstrapState.Action)
+ return nil
+ }
+
+ if err := GenerateKubeadmJoinConfig(ctx, nctx); err != nil {
+ return err
+ }
+
+ klog.Infof("running kubeadm join for action %q", nctx.BootstrapState.Action)
+
+ _, err := nctx.SystemRunner.RunWithOptions(
+ ctx,
+ "kubeadm",
+ []string{"join", "--config", tmpKubeadmInitConf},
+ system.RunOptions{
+ Timeout: 5 * time.Minute,
+ OnStdoutLine: func(line string) {
+ klog.Infof("[kubeadm] %s", line)
+ },
+ OnStderrLine: func(line string) {
+ klog.Infof("[kubeadm] %s", line)
+ },
+ },
+ )
+ if err != nil {
+ return fmt.Errorf("run kubeadm join: %w", err)
+ }
+
return nil
}
-func RunKubeadmJoin(context.Context, *NodeContext) error {
- /*
- 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
- }
- */
+func RunKubeadmUpgradeApply(context.Context, *NodeContext) error {
+ klog.Info("run_kubeadm_upgrade_apply: TODO implement kubeadm upgrade apply")
return nil
}
+
func RunKubeadmUpgradeNode(context.Context, *NodeContext) error {
klog.Info("run_kubeadm_upgrade_node: TODO implement kubeadm upgrade node")
return nil
diff --git a/clitools/pkg/node/kubeadm_types.go b/clitools/pkg/node/kubeadm_types.go
new file mode 100644
index 0000000..f9f7e61
--- /dev/null
+++ b/clitools/pkg/node/kubeadm_types.go
@@ -0,0 +1,81 @@
+package node
+
+type KubeadmArg struct {
+ Name string `yaml:"name"`
+ Value string `yaml:"value"`
+}
+
+type KubeadmTaint struct {
+ Key string `yaml:"key"`
+ Value string `yaml:"value,omitempty"`
+ Effect string `yaml:"effect"`
+}
+
+type LocalAPIEndpoint struct {
+ AdvertiseAddress string `yaml:"advertiseAddress"`
+ BindPort int `yaml:"bindPort"`
+}
+
+type NodeRegistrationOptions struct {
+ Name string `yaml:"name"`
+ CRISocket string `yaml:"criSocket"`
+ ImagePullPolicy string `yaml:"imagePullPolicy,omitempty"`
+ Taints []KubeadmTaint `yaml:"taints,omitempty"`
+ KubeletExtraArgs []KubeadmArg `yaml:"kubeletExtraArgs,omitempty"`
+}
+
+type Networking struct {
+ PodSubnet string `yaml:"podSubnet,omitempty"`
+ ServiceSubnet string `yaml:"serviceSubnet,omitempty"`
+ DNSDomain string `yaml:"dnsDomain,omitempty"`
+}
+
+type APIServer struct {
+ CertSANs []string `yaml:"certSANs,omitempty"`
+}
+
+type InitConfiguration struct {
+ APIVersion string `yaml:"apiVersion"`
+ Kind string `yaml:"kind"`
+ LocalAPIEndpoint LocalAPIEndpoint `yaml:"localAPIEndpoint"`
+ NodeRegistration NodeRegistrationOptions `yaml:"nodeRegistration"`
+}
+
+type ClusterConfiguration struct {
+ APIVersion string `yaml:"apiVersion"`
+ Kind string `yaml:"kind"`
+ ClusterName string `yaml:"clusterName"`
+ KubernetesVersion string `yaml:"kubernetesVersion"`
+ Networking Networking `yaml:"networking"`
+ APIServer APIServer `yaml:"apiServer"`
+}
+
+type BootstrapTokenDiscovery struct {
+ APIServerEndpoint string `yaml:"apiServerEndpoint"`
+ Token string `yaml:"token"`
+ CACertHashes []string `yaml:"caCertHashes"`
+}
+
+type Discovery struct {
+ BootstrapToken BootstrapTokenDiscovery `yaml:"bootstrapToken"`
+}
+
+type JoinControlPlane struct {
+ CertificateKey string `yaml:"certificateKey"`
+}
+
+type JoinConfiguration struct {
+ APIVersion string `yaml:"apiVersion"`
+ Kind string `yaml:"kind"`
+ NodeRegistration NodeRegistrationOptions `yaml:"nodeRegistration"`
+ Discovery Discovery `yaml:"discovery"`
+ ControlPlane *JoinControlPlane `yaml:"controlPlane,omitempty"`
+ LocalAPIEndpoint *LocalAPIEndpoint `yaml:"localAPIEndpoint,omitempty"`
+}
+
+type KubeletConfiguration struct {
+ APIVersion string `yaml:"apiVersion"`
+ Kind string `yaml:"kind"`
+ CgroupDriver string `yaml:"cgroupDriver"`
+ ContainerRuntimeEndpoint string `yaml:"containerRuntimeEndpoint"`
+}
diff --git a/clitools/pkg/templates/templates.go b/clitools/pkg/templates/templates.go
index 93af46e..e68a96e 100644
--- a/clitools/pkg/templates/templates.go
+++ b/clitools/pkg/templates/templates.go
@@ -8,6 +8,7 @@ import (
buildinfo "undecided.project/monok8s/pkg/buildinfo"
)
+var ValAPIServerEndPoint string = "10.0.0.10:6443"
var ValHostname string = "monoks-master-1"
var ValBootstrapToken string = "abcd12.ef3456789abcdef0"
var ValDiscoveryTokenCACertHash string = "sha256:9f1c2b3a4d5e6f7890abc1234567890abcdef1234567890abcdef1234567890ab"
@@ -16,6 +17,7 @@ func init() {
ValBootstrapToken = os.Getenv("HOSTNAME")
ValBootstrapToken = os.Getenv("BOOTSTRAP_TOKEN")
ValDiscoveryTokenCACertHash = os.Getenv("TOKEN_CACERT_HASH")
+ ValAPIServerEndPoint = os.Getenv("API_SERVER_ENDPOINT")
}
func DefaultMonoKSConfig() types.MonoKSConfig {
@@ -42,7 +44,7 @@ func DefaultMonoKSConfig() types.MonoKSConfig {
ServiceSubnet: "10.96.0.0/12",
APIServerAdvertiseAddress: "10.0.0.10",
- APIServerEndpoint: "10.0.0.10:6443",
+ APIServerEndpoint: ValAPIServerEndPoint,
// Fake token and hash for placeholder purpose
BootstrapToken: ValBootstrapToken,