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  }