github.com/alibaba/sealer@v0.8.6-0.20220430115802-37a2bdaa8173/pkg/runtime/kubeadm_runtime.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 21 "github.com/alibaba/sealer/utils/platform" 22 23 "path/filepath" 24 "strings" 25 "time" 26 27 "golang.org/x/sync/errgroup" 28 29 "github.com/alibaba/sealer/pkg/runtime/kubeadm_types/v1beta2" 30 31 "github.com/alibaba/sealer/utils" 32 33 "github.com/alibaba/sealer/common" 34 "github.com/alibaba/sealer/logger" 35 v2 "github.com/alibaba/sealer/types/api/v2" 36 "github.com/alibaba/sealer/utils/ssh" 37 ) 38 39 type Config struct { 40 Vlog int 41 VIP string 42 RegConfig *RegistryConfig 43 // Clusterfile: the absolute path, we need to read kubeadm config from Clusterfile 44 ClusterFileKubeConfig *KubeadmConfig 45 APIServerDomain string 46 } 47 48 func newKubeadmRuntime(cluster *v2.Cluster, clusterFileKubeConfig *KubeadmConfig) (Interface, error) { 49 k := &KubeadmRuntime{ 50 Cluster: cluster, 51 Config: &Config{ 52 ClusterFileKubeConfig: clusterFileKubeConfig, 53 APIServerDomain: DefaultAPIserverDomain, 54 }, 55 KubeadmConfig: &KubeadmConfig{}, 56 } 57 k.Config.RegConfig = GetRegistryConfig(k.getImageMountDir(), k.GetMaster0IP()) 58 k.setCertSANS(append([]string{"127.0.0.1", k.getAPIServerDomain(), k.getVIP()}, k.GetMasterIPList()...)) 59 // TODO args pre checks 60 if err := k.checkList(); err != nil { 61 return nil, err 62 } 63 64 if logger.IsDebugModel() { 65 k.Vlog = 6 66 } 67 return k, nil 68 } 69 70 func (k *KubeadmRuntime) checkList() error { 71 if len(k.Spec.Hosts) == 0 { 72 return fmt.Errorf("master hosts cannot be empty") 73 } 74 if k.GetMaster0IP() == "" { 75 return fmt.Errorf("master hosts ip cannot be empty") 76 } 77 return nil 78 } 79 80 func (k *KubeadmRuntime) getClusterName() string { 81 return k.Cluster.Name 82 } 83 84 func (k *KubeadmRuntime) getClusterMetadata() (*Metadata, error) { 85 metadata := &Metadata{} 86 if k.getKubeVersion() == "" { 87 if err := k.MergeKubeadmConfig(); err != nil { 88 return nil, err 89 } 90 } 91 metadata.Version = k.getKubeVersion() 92 return metadata, nil 93 } 94 95 func (k *KubeadmRuntime) getHostSSHClient(hostIP string) (ssh.Interface, error) { 96 return ssh.NewStdoutSSHClient(hostIP, k.Cluster) 97 } 98 99 // /var/lib/sealer/data/my-cluster 100 func (k *KubeadmRuntime) getBasePath() string { 101 return common.DefaultClusterBaseDir(k.getClusterName()) 102 } 103 104 // /var/lib/sealer/data/my-cluster/rootfs 105 func (k *KubeadmRuntime) getRootfs() string { 106 return common.DefaultTheClusterRootfsDir(k.getClusterName()) 107 } 108 109 // /var/lib/sealer/data/my-cluster/mount 110 func (k *KubeadmRuntime) getImageMountDir() string { 111 return platform.DefaultMountCloudImageDir(k.getClusterName()) 112 } 113 114 // /var/lib/sealer/data/my-cluster/certs 115 func (k *KubeadmRuntime) getCertsDir() string { 116 return common.TheDefaultClusterCertDir(k.getClusterName()) 117 } 118 119 // /var/lib/sealer/data/my-cluster/pki 120 func (k *KubeadmRuntime) getPKIPath() string { 121 return common.TheDefaultClusterPKIDir(k.getClusterName()) 122 } 123 124 // /var/lib/sealer/data/my-cluster/mount/etc/kubeadm.yml 125 func (k *KubeadmRuntime) getDefaultKubeadmConfig() string { 126 return filepath.Join(k.getImageMountDir(), "etc", "kubeadm.yml") 127 } 128 129 // /var/lib/sealer/data/my-cluster/pki/etcd 130 func (k *KubeadmRuntime) getEtcdCertPath() string { 131 return filepath.Join(k.getPKIPath(), "etcd") 132 } 133 134 // /var/lib/sealer/data/my-cluster/rootfs/statics 135 func (k *KubeadmRuntime) getStaticFileDir() string { 136 return filepath.Join(k.getRootfs(), "statics") 137 } 138 139 func (k *KubeadmRuntime) getSvcCIDR() string { 140 return k.ClusterConfiguration.Networking.ServiceSubnet 141 } 142 143 func (k *KubeadmRuntime) setCertSANS(certSANS []string) { 144 k.ClusterConfiguration.APIServer.CertSANs = utils.RemoveDuplicate(append(k.getCertSANS(), certSANS...)) 145 } 146 147 func (k *KubeadmRuntime) getCertSANS() []string { 148 return k.ClusterConfiguration.APIServer.CertSANs 149 } 150 151 func (k *KubeadmRuntime) getDNSDomain() string { 152 if k.ClusterConfiguration.Networking.DNSDomain == "" { 153 k.ClusterConfiguration.Networking.DNSDomain = "cluster.local" 154 } 155 return k.ClusterConfiguration.Networking.DNSDomain 156 } 157 158 func (k *KubeadmRuntime) getAPIServerDomain() string { 159 return k.Config.APIServerDomain 160 } 161 162 func (k *KubeadmRuntime) getKubeVersion() string { 163 return k.KubernetesVersion 164 } 165 166 func (k *KubeadmRuntime) getVIP() string { 167 return DefaultVIP 168 } 169 170 func (k *KubeadmRuntime) getJoinToken() string { 171 if k.Discovery.BootstrapToken == nil { 172 return "" 173 } 174 return k.JoinConfiguration.Discovery.BootstrapToken.Token 175 } 176 177 func (k *KubeadmRuntime) setJoinToken(token string) { 178 if k.Discovery.BootstrapToken == nil { 179 k.Discovery.BootstrapToken = &v1beta2.BootstrapTokenDiscovery{} 180 } 181 k.Discovery.BootstrapToken.Token = token 182 } 183 184 func (k *KubeadmRuntime) getTokenCaCertHash() string { 185 if k.Discovery.BootstrapToken == nil || len(k.Discovery.BootstrapToken.CACertHashes) == 0 { 186 return "" 187 } 188 return k.Discovery.BootstrapToken.CACertHashes[0] 189 } 190 191 func (k *KubeadmRuntime) setTokenCaCertHash(tokenCaCertHash []string) { 192 if k.Discovery.BootstrapToken == nil { 193 k.Discovery.BootstrapToken = &v1beta2.BootstrapTokenDiscovery{} 194 } 195 k.Discovery.BootstrapToken.CACertHashes = tokenCaCertHash 196 } 197 198 func (k *KubeadmRuntime) getCertificateKey() string { 199 if k.JoinConfiguration.ControlPlane == nil { 200 return "" 201 } 202 return k.JoinConfiguration.ControlPlane.CertificateKey 203 } 204 205 func (k *KubeadmRuntime) setInitCertificateKey(certificateKey string) { 206 k.CertificateKey = certificateKey 207 } 208 209 func (k *KubeadmRuntime) setAPIServerEndpoint(endpoint string) { 210 k.JoinConfiguration.Discovery.BootstrapToken.APIServerEndpoint = endpoint 211 } 212 213 func (k *KubeadmRuntime) setInitAdvertiseAddress(advertiseAddress string) { 214 k.InitConfiguration.LocalAPIEndpoint.AdvertiseAddress = advertiseAddress 215 } 216 217 func (k *KubeadmRuntime) setJoinAdvertiseAddress(advertiseAddress string) { 218 if k.JoinConfiguration.ControlPlane == nil { 219 k.JoinConfiguration.ControlPlane = &v1beta2.JoinControlPlane{} 220 } 221 k.JoinConfiguration.ControlPlane.LocalAPIEndpoint.AdvertiseAddress = advertiseAddress 222 } 223 224 func (k *KubeadmRuntime) cleanJoinLocalAPIEndPoint() { 225 k.JoinConfiguration.ControlPlane = nil 226 } 227 228 func (k *KubeadmRuntime) setControlPlaneEndpoint(endpoint string) { 229 k.ControlPlaneEndpoint = endpoint 230 } 231 232 func (k *KubeadmRuntime) setCgroupDriver(cGroup string) { 233 k.KubeletConfiguration.CgroupDriver = cGroup 234 } 235 236 func (k *KubeadmRuntime) setAPIVersion(apiVersion string) { 237 k.InitConfiguration.APIVersion = apiVersion 238 k.ClusterConfiguration.APIVersion = apiVersion 239 k.JoinConfiguration.APIVersion = apiVersion 240 } 241 func getEtcdEndpointsWithHTTPSPrefix(masters []string) string { 242 var tmpSlice []string 243 for _, ip := range masters { 244 tmpSlice = append(tmpSlice, fmt.Sprintf("https://%s:2379", utils.GetHostIP(ip))) 245 } 246 return strings.Join(tmpSlice, ",") 247 } 248 249 func (k *KubeadmRuntime) WaitSSHReady(tryTimes int, hosts ...string) error { 250 eg, _ := errgroup.WithContext(context.Background()) 251 for _, h := range hosts { 252 host := h 253 eg.Go(func() error { 254 for i := 0; i < tryTimes; i++ { 255 sshClient, err := k.getHostSSHClient(host) 256 if err != nil { 257 return err 258 } 259 err = sshClient.Ping(host) 260 if err == nil { 261 return nil 262 } 263 time.Sleep(time.Duration(i) * time.Second) 264 } 265 return fmt.Errorf("wait for [%s] ssh ready timeout, ensure that the IP address or password is correct", host) 266 }) 267 } 268 return eg.Wait() 269 }