github.com/alibaba/sealer@v0.8.6-0.20220430115802-37a2bdaa8173/pkg/runtime/nodes.go (about)

     1  // Copyright © 2021 Alibaba Group Holding Ltd.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package runtime
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"strings"
    21  
    22  	"github.com/alibaba/sealer/utils"
    23  	"golang.org/x/sync/errgroup"
    24  
    25  	"github.com/pkg/errors"
    26  
    27  	"github.com/alibaba/sealer/logger"
    28  	"github.com/alibaba/sealer/pkg/ipvs"
    29  )
    30  
    31  const (
    32  	RemoteAddIPVS                   = "seautil ipvs --vs %s:6443 %s --health-path /healthz --health-schem https --run-once"
    33  	RemoteStaticPodMkdir            = "mkdir -p /etc/kubernetes/manifests"
    34  	RemoteJoinConfig                = `echo "%s" > %s/etc/kubeadm.yml`
    35  	LvscareDefaultStaticPodFileName = "/etc/kubernetes/manifests/kube-lvscare.yaml"
    36  	RemoteAddIPVSEtcHosts           = "echo %s %s >> /etc/hosts"
    37  	RemoteCheckRoute                = "seautil route check --host %s"
    38  	RemoteAddRoute                  = "seautil route add --host %s --gateway %s"
    39  	RemoteDelRoute                  = "if command -v seautil > /dev/null 2>&1; then seautil route del --host %s --gateway %s; fi"
    40  	LvscareStaticPodCmd             = `echo "%s" > %s`
    41  )
    42  
    43  func (k *KubeadmRuntime) joinNodeConfig(nodeIP string) ([]byte, error) {
    44  	// TODO get join config from config file
    45  	k.setAPIServerEndpoint(fmt.Sprintf("%s:6443", k.getVIP()))
    46  	cGroupDriver, err := k.getCgroupDriverFromShell(nodeIP)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  	k.setCgroupDriver(cGroupDriver)
    51  	return utils.MarshalYamlConfigs(k.JoinConfiguration, k.KubeletConfiguration)
    52  }
    53  
    54  func (k *KubeadmRuntime) joinNodes(nodes []string) error {
    55  	if len(nodes) == 0 {
    56  		return nil
    57  	}
    58  	if err := k.MergeKubeadmConfig(); err != nil {
    59  		return err
    60  	}
    61  	if err := k.WaitSSHReady(6, nodes...); err != nil {
    62  		return errors.Wrap(err, "join nodes wait for ssh ready time out")
    63  	}
    64  	if err := k.sendRegistryCert(nodes); err != nil {
    65  		return err
    66  	}
    67  	if err := k.GetJoinTokenHashAndKey(); err != nil {
    68  		return err
    69  	}
    70  	var masters string
    71  	eg, _ := errgroup.WithContext(context.Background())
    72  	for _, master := range k.GetMasterIPList() {
    73  		masters += fmt.Sprintf(" --rs %s:6443", master)
    74  	}
    75  	ipvsCmd := fmt.Sprintf(RemoteAddIPVS, k.getVIP(), masters)
    76  
    77  	k.setAPIServerEndpoint(fmt.Sprintf("%s:6443", k.getVIP()))
    78  	k.cleanJoinLocalAPIEndPoint()
    79  
    80  	registryHost := k.getRegistryHost()
    81  	addRegistryHostsAndLogin := fmt.Sprintf(RemoteAddEtcHosts, registryHost, registryHost)
    82  	if k.RegConfig.Domain != SeaHub {
    83  		addSeaHubHost := fmt.Sprintf(RemoteAddEtcHosts, k.RegConfig.IP+" "+SeaHub, k.RegConfig.IP+" "+SeaHub)
    84  		addRegistryHostsAndLogin = fmt.Sprintf("%s && %s", addRegistryHostsAndLogin, addSeaHubHost)
    85  	}
    86  	if k.RegConfig.Username != "" && k.RegConfig.Password != "" {
    87  		addRegistryHostsAndLogin = fmt.Sprintf("%s && %s", addRegistryHostsAndLogin, k.GerLoginCommand())
    88  	}
    89  	for _, node := range nodes {
    90  		node := node
    91  		eg.Go(func() error {
    92  			logger.Info("Start to join %s as worker", node)
    93  			err := k.checkMultiNetworkAddVIPRoute(node)
    94  			if err != nil {
    95  				return fmt.Errorf("failed to check multi network: %v", err)
    96  			}
    97  			// send join node config, get cgroup driver on every join nodes
    98  			joinConfig, err := k.joinNodeConfig(node)
    99  			if err != nil {
   100  				return fmt.Errorf("failed to join node %s %v", node, err)
   101  			}
   102  			cmdWriteJoinConfig := fmt.Sprintf(RemoteJoinConfig, string(joinConfig), k.getRootfs())
   103  			cmdHosts := fmt.Sprintf(RemoteAddIPVSEtcHosts, k.getVIP(), k.getAPIServerDomain())
   104  			cmd := k.Command(k.getKubeVersion(), JoinNode)
   105  			lvsImage := k.RegConfig.Repo() + "/fanux/lvscare:latest"
   106  			yaml := ipvs.LvsStaticPodYaml(k.getVIP(), k.GetMasterIPList(), lvsImage)
   107  			lvscareStaticCmd := fmt.Sprintf(LvscareStaticPodCmd, yaml, LvscareDefaultStaticPodFileName)
   108  			ssh, err := k.getHostSSHClient(node)
   109  			if err != nil {
   110  				return fmt.Errorf("failed to join node %s %v", node, err)
   111  			}
   112  			if err := ssh.CmdAsync(node, addRegistryHostsAndLogin, cmdWriteJoinConfig, cmdHosts, ipvsCmd, cmd, RemoteStaticPodMkdir, lvscareStaticCmd); err != nil {
   113  				return fmt.Errorf("failed to join node %s %v", node, err)
   114  			}
   115  			logger.Info("Succeeded in joining %s as worker", node)
   116  			return err
   117  		})
   118  	}
   119  	return eg.Wait()
   120  }
   121  
   122  func (k *KubeadmRuntime) deleteNodes(nodes []string) error {
   123  	if len(nodes) == 0 {
   124  		return nil
   125  	}
   126  	eg, _ := errgroup.WithContext(context.Background())
   127  	for _, node := range nodes {
   128  		node := node
   129  		eg.Go(func() error {
   130  			logger.Info("Start to delete worker %s", node)
   131  			if err := k.deleteNode(node); err != nil {
   132  				return fmt.Errorf("delete node %s failed %v", node, err)
   133  			}
   134  			err := k.deleteVIPRouteIfExist(node)
   135  			if err != nil {
   136  				return fmt.Errorf("failed to delete %s route: %v", node, err)
   137  			}
   138  			logger.Info("Succeeded in deleting worker %s", node)
   139  			return nil
   140  		})
   141  	}
   142  	return eg.Wait()
   143  }
   144  
   145  func (k *KubeadmRuntime) deleteNode(node string) error {
   146  	ssh, err := k.getHostSSHClient(node)
   147  	if err != nil {
   148  		return fmt.Errorf("failed to delete node: %v", err)
   149  	}
   150  	remoteCleanCmds := []string{fmt.Sprintf(RemoteCleanMasterOrNode, vlogToStr(k.Vlog)),
   151  		fmt.Sprintf(RemoteRemoveAPIServerEtcHost, k.RegConfig.Domain),
   152  		fmt.Sprintf(RemoteRemoveAPIServerEtcHost, SeaHub),
   153  		fmt.Sprintf(RemoteRemoveRegistryCerts, k.RegConfig.Domain),
   154  		fmt.Sprintf(RemoteRemoveRegistryCerts, SeaHub),
   155  		fmt.Sprintf(RemoteRemoveAPIServerEtcHost, k.getAPIServerDomain())}
   156  	address, err := utils.GetLocalHostAddresses()
   157  	//if the node to be removed is the execution machine, kubelet, ~./kube and ApiServer host will be added
   158  	if err != nil || !utils.IsLocalIP(node, address) {
   159  		remoteCleanCmds = append(remoteCleanCmds, RemoveKubeConfig)
   160  	} else {
   161  		apiServerHost := getAPIServerHost(k.GetMaster0IP(), k.getAPIServerDomain())
   162  		remoteCleanCmds = append(remoteCleanCmds, fmt.Sprintf(RemoteAddEtcHosts, apiServerHost, apiServerHost))
   163  	}
   164  	if err := ssh.CmdAsync(node, remoteCleanCmds...); err != nil {
   165  		return err
   166  	}
   167  	//remove node
   168  	if len(k.GetMasterIPList()) > 0 {
   169  		hostname, err := k.isHostName(k.GetMaster0IP(), node)
   170  		if err != nil {
   171  			return err
   172  		}
   173  		ssh, err := k.getHostSSHClient(k.GetMaster0IP())
   174  		if err != nil {
   175  			return fmt.Errorf("failed to delete node on master0,%v", err)
   176  		}
   177  		if err := ssh.CmdAsync(k.GetMaster0IP(), fmt.Sprintf(KubeDeleteNode, strings.TrimSpace(hostname))); err != nil {
   178  			return fmt.Errorf("delete node %s failed %v", hostname, err)
   179  		}
   180  	}
   181  
   182  	return nil
   183  }
   184  
   185  func (k *KubeadmRuntime) checkMultiNetworkAddVIPRoute(node string) error {
   186  	sshClient, err := k.getHostSSHClient(node)
   187  	if err != nil {
   188  		return err
   189  	}
   190  	result, err := sshClient.CmdToString(node, fmt.Sprintf(RemoteCheckRoute, node), "")
   191  	if err != nil {
   192  		return err
   193  	}
   194  	if result == utils.RouteOK {
   195  		return nil
   196  	}
   197  	_, err = sshClient.Cmd(node, fmt.Sprintf(RemoteAddRoute, k.getVIP(), node))
   198  	return err
   199  }
   200  
   201  func (k *KubeadmRuntime) deleteVIPRouteIfExist(node string) error {
   202  	sshClient, err := k.getHostSSHClient(node)
   203  	if err != nil {
   204  		return err
   205  	}
   206  	_, err = sshClient.Cmd(node, fmt.Sprintf(RemoteDelRoute, k.getVIP(), node))
   207  	return err
   208  }