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 }