github.com/sealerio/sealer@v0.11.1-0.20240507115618-f4f89c5853ae/pkg/runtime/k0s/runtime.go (about) 1 // Copyright © 2022 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 k0s 16 17 import ( 18 "bytes" 19 "context" 20 "fmt" 21 "net" 22 "os" 23 24 "github.com/sealerio/sealer/common" 25 containerruntime "github.com/sealerio/sealer/pkg/container-runtime" 26 "github.com/sealerio/sealer/pkg/infradriver" 27 "github.com/sealerio/sealer/pkg/registry" 28 "github.com/sealerio/sealer/pkg/runtime" 29 utilsnet "github.com/sealerio/sealer/utils/net" 30 31 "github.com/sirupsen/logrus" 32 "golang.org/x/sync/errgroup" 33 corev1 "k8s.io/api/core/v1" 34 apierrors "k8s.io/apimachinery/pkg/api/errors" 35 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 36 runtimeClient "sigs.k8s.io/controller-runtime/pkg/client" 37 ) 38 39 // Runtime struct is the runtime interface for k0s 40 type Runtime struct { 41 infra infradriver.InfraDriver 42 Vlog int 43 containerRuntimeInfo containerruntime.Info 44 registryInfo registry.Info 45 //TODO:now do not support custom APIServerDomain 46 } 47 48 // NewK0sRuntime gen a k0s bootstrap process that leading k0s cluster management 49 func NewK0sRuntime(infra infradriver.InfraDriver, containerRuntimeInfo containerruntime.Info, registryInfo registry.Info) (runtime.Installer, error) { 50 k := &Runtime{ 51 infra: infra, 52 registryInfo: registryInfo, 53 containerRuntimeInfo: containerRuntimeInfo, 54 } 55 56 setDebugLevel(k) 57 return k, nil 58 } 59 60 func (k *Runtime) Install() error { 61 masters := k.infra.GetHostIPListByRole(common.MASTER) 62 workers := k.infra.GetHostIPListByRole(common.NODE) 63 64 if err := k.initKube([]net.IP{masters[0]}); err != nil { 65 return err 66 } 67 // registryInfo like "sea.hub:5000" is needed which used to modify the k0s.yaml private registry repo 68 if err := k.generateConfigOnMaster0(masters[0], k.registryInfo.URL); err != nil { 69 return err 70 } 71 72 if err := k.bootstrapMaster0(masters[0]); err != nil { 73 return err 74 } 75 76 if err := k.generateJoinToken(masters[0]); err != nil { 77 return err 78 } 79 80 if err := k.joinMasters(masters[1:], k.registryInfo.URL); err != nil { 81 return err 82 } 83 84 if err := k.joinNodes(workers); err != nil { 85 return err 86 } 87 88 driver, err := k.GetCurrentRuntimeDriver() 89 if err != nil { 90 return err 91 } 92 93 if err := k.dumpKubeConfigIntoCluster(driver, masters[0]); err != nil { 94 return err 95 } 96 return nil 97 } 98 99 func (k *Runtime) GetCurrentRuntimeDriver() (runtime.Driver, error) { 100 return NewKubeDriver(DefaultAdminConfPath) 101 } 102 103 func (k *Runtime) ScaleUp(newMasters, newWorkers []net.IP) error { 104 if err := k.joinMasters(newMasters, k.registryInfo.URL); err != nil { 105 return err 106 } 107 108 if err := k.joinNodes(newWorkers); err != nil { 109 return err 110 } 111 logrus.Info("cluster scale up succeeded!") 112 return nil 113 } 114 115 func (k *Runtime) ScaleDown(mastersToDelete, workersToDelete []net.IP) error { 116 masters := k.infra.GetHostIPListByRole(common.MASTER) 117 118 remainMasters := utilsnet.RemoveIPs(masters, mastersToDelete) 119 if len(remainMasters) == 0 { 120 return fmt.Errorf("cleaning up all masters is illegal, unless you give the --all flag, which will delete the entire cluster") 121 } 122 123 if len(workersToDelete) > 0 { 124 if err := k.deleteNodes(workersToDelete, remainMasters); err != nil { 125 return err 126 } 127 } 128 129 if len(mastersToDelete) > 0 { 130 if err := k.deleteMasters(mastersToDelete, remainMasters); err != nil { 131 return err 132 } 133 } 134 logrus.Info("cluster scale down succeeded!") 135 return nil 136 } 137 138 func setDebugLevel(k *Runtime) { 139 if logrus.GetLevel() == logrus.DebugLevel { 140 k.Vlog = 6 141 } 142 } 143 144 func (k *Runtime) Upgrade() error { 145 panic("implement me") 146 } 147 148 func (k *Runtime) Reset() error { 149 masters := k.infra.GetHostIPListByRole(common.MASTER) 150 workers := k.infra.GetHostIPListByRole(common.NODE) 151 return k.reset(masters, workers) 152 } 153 154 func (k *Runtime) CopyJoinToken(role string, hosts []net.IP) error { 155 var joinCertPath string 156 switch role { 157 case ControllerRole: 158 joinCertPath = DefaultK0sControllerJoin 159 case WorkerRole: 160 joinCertPath = DefaultK0sWorkerJoin 161 default: 162 joinCertPath = DefaultK0sWorkerJoin 163 } 164 165 eg, _ := errgroup.WithContext(context.Background()) 166 for _, host := range hosts { 167 host := host 168 eg.Go(func() error { 169 return k.infra.Copy(host, joinCertPath, joinCertPath) 170 }) 171 } 172 return nil 173 } 174 175 func (k *Runtime) JoinCommand(role, registryInfo string) []string { 176 cmds := map[string][]string{ 177 ControllerRole: {"mkdir -p /etc/k0s", fmt.Sprintf("k0s config create > %s", DefaultK0sConfigPath), 178 fmt.Sprintf("sed -i '/ images/ a\\ repository: \"%s\"' %s", registryInfo, DefaultK0sConfigPath), 179 fmt.Sprintf("k0s install controller --token-file %s -c %s --cri-socket %s", 180 DefaultK0sControllerJoin, DefaultK0sConfigPath, ExternalCRIAddress), 181 "k0s start", 182 }, 183 WorkerRole: {fmt.Sprintf("k0s install worker --cri-socket %s --token-file %s", ExternalCRIAddress, DefaultK0sWorkerJoin), 184 "k0s start"}, 185 } 186 187 v, ok := cmds[role] 188 if !ok { 189 return nil 190 } 191 return v 192 } 193 194 // dumpKubeConfigIntoCluster save AdminKubeConf to cluster as secret resource. 195 func (k *Runtime) dumpKubeConfigIntoCluster(driver runtime.Driver, master0 net.IP) error { 196 kubeConfigContent, err := os.ReadFile(DefaultAdminConfPath) 197 if err != nil { 198 return err 199 } 200 201 kubeConfigContent = bytes.ReplaceAll(kubeConfigContent, []byte("apiserver.cluster.local"), []byte(master0.String())) 202 203 secret := &corev1.Secret{ 204 ObjectMeta: metav1.ObjectMeta{ 205 Name: "admin.conf", 206 Namespace: metav1.NamespaceSystem, 207 }, 208 Type: corev1.SecretTypeOpaque, 209 Data: map[string][]byte{ 210 "admin.conf": kubeConfigContent, 211 }, 212 } 213 214 if err := driver.Create(context.Background(), secret, &runtimeClient.CreateOptions{}); err != nil { 215 if !apierrors.IsAlreadyExists(err) { 216 return fmt.Errorf("unable to create secret: %v", err) 217 } 218 219 if err := driver.Update(context.Background(), secret, &runtimeClient.UpdateOptions{}); err != nil { 220 return fmt.Errorf("unable to update secret: %v", err) 221 } 222 } 223 224 return nil 225 }