github.com/sealerio/sealer@v0.11.1-0.20240507115618-f4f89c5853ae/pkg/runtime/kubernetes/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 kubernetes
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"fmt"
    21  	"net"
    22  	"os"
    23  	"path"
    24  	"path/filepath"
    25  
    26  	"github.com/sirupsen/logrus"
    27  	corev1 "k8s.io/api/core/v1"
    28  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    29  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  	k8snet "k8s.io/utils/net"
    31  	runtimeClient "sigs.k8s.io/controller-runtime/pkg/client"
    32  
    33  	"github.com/sealerio/sealer/common"
    34  	containerruntime "github.com/sealerio/sealer/pkg/container-runtime"
    35  	"github.com/sealerio/sealer/pkg/infradriver"
    36  	"github.com/sealerio/sealer/pkg/registry"
    37  	"github.com/sealerio/sealer/pkg/runtime"
    38  	"github.com/sealerio/sealer/pkg/runtime/kubernetes/kubeadm"
    39  	"github.com/sealerio/sealer/utils"
    40  	utilsnet "github.com/sealerio/sealer/utils/net"
    41  )
    42  
    43  type Config struct {
    44  	Vlog                         int
    45  	VIP                          string
    46  	RegistryInfo                 registry.Info
    47  	containerRuntimeInfo         containerruntime.Info
    48  	KubeadmConfigFromClusterFile kubeadm.KubeadmConfig
    49  	APIServerDomain              string
    50  }
    51  
    52  // Runtime struct is the runtime interface for kubernetes
    53  type Runtime struct {
    54  	infra  infradriver.InfraDriver
    55  	Config *Config
    56  }
    57  
    58  func NewKubeadmRuntime(clusterFileKubeConfig kubeadm.KubeadmConfig, infra infradriver.InfraDriver, containerRuntimeInfo containerruntime.Info, registryInfo registry.Info) (runtime.Installer, error) {
    59  	k := &Runtime{
    60  		infra: infra,
    61  		Config: &Config{
    62  			KubeadmConfigFromClusterFile: clusterFileKubeConfig,
    63  			APIServerDomain:              common.DefaultAPIserverDomain,
    64  			VIP:                          common.DefaultVIP,
    65  			RegistryInfo:                 registryInfo,
    66  			containerRuntimeInfo:         containerRuntimeInfo,
    67  		},
    68  	}
    69  
    70  	if hosts := infra.GetHostIPList(); len(hosts) > 0 && k8snet.IsIPv6(hosts[0]) {
    71  		k.Config.VIP = common.DefaultVIPForIPv6
    72  	}
    73  
    74  	if ipv4, ok := infra.GetClusterEnv()[common.EnvIPvsVIPForIPv4]; ok {
    75  		k.Config.VIP = ipv4
    76  	}
    77  
    78  	if ipv6, ok := infra.GetClusterEnv()[common.EnvIPvsVIPForIPv6]; ok {
    79  		k.Config.VIP = ipv6
    80  	}
    81  
    82  	if logrus.GetLevel() == logrus.DebugLevel {
    83  		k.Config.Vlog = 6
    84  	}
    85  
    86  	return k, nil
    87  }
    88  
    89  func (k *Runtime) Install() error {
    90  	masters := k.infra.GetHostIPListByRole(common.MASTER)
    91  	workers := k.infra.GetHostIPListByRole(common.NODE)
    92  
    93  	kubeadmConf, err := k.initKubeadmConfig(masters)
    94  	if err != nil {
    95  		return err
    96  	}
    97  
    98  	if err = k.generateCert(kubeadmConf, masters[0]); err != nil {
    99  		return err
   100  	}
   101  
   102  	if err = k.createKubeConfig(masters[0]); err != nil {
   103  		return err
   104  	}
   105  
   106  	if err = k.copyStaticFiles(masters[0:1]); err != nil {
   107  		return err
   108  	}
   109  
   110  	token, certKey, err := k.initMaster0(masters[0])
   111  	if err != nil {
   112  		return err
   113  	}
   114  
   115  	if err = k.joinMasters(masters[1:], masters[0], kubeadmConf, token, certKey); err != nil {
   116  		return err
   117  	}
   118  
   119  	if err = k.joinNodes(workers, masters, kubeadmConf, token); err != nil {
   120  		return err
   121  	}
   122  
   123  	driver, err := k.GetCurrentRuntimeDriver()
   124  	if err != nil {
   125  		return err
   126  	}
   127  
   128  	if err := k.dumpKubeConfigIntoCluster(driver, masters[0]); err != nil {
   129  		return err
   130  	}
   131  
   132  	logrus.Info("succeeded in creating a new cluster.")
   133  	return nil
   134  }
   135  
   136  func (k *Runtime) GetCurrentRuntimeDriver() (runtime.Driver, error) {
   137  	return NewKubeDriver(AdminKubeConfPath)
   138  }
   139  
   140  func (k *Runtime) Upgrade() error {
   141  	panic("now not support upgrade")
   142  }
   143  
   144  func (k *Runtime) Reset() error {
   145  	masters := k.infra.GetHostIPListByRole(common.MASTER)
   146  	workers := k.infra.GetHostIPListByRole(common.NODE)
   147  	return k.reset(masters, workers)
   148  }
   149  
   150  func (k *Runtime) ScaleUp(newMasters, newWorkers []net.IP) error {
   151  	masters := k.infra.GetHostIPListByRole(common.MASTER)
   152  	workers := k.infra.GetHostIPListByRole(common.NODE)
   153  
   154  	kubeadmConfig, err := kubeadm.LoadKubeadmConfigs(path.Join(k.infra.GetClusterRootfsPath(), "kubeadm.yaml"), utils.DecodeCRDFromFile)
   155  	if err != nil {
   156  		return err
   157  	}
   158  
   159  	token, certKey, err := k.getJoinTokenHashAndKey(masters[0])
   160  	if err != nil {
   161  		return err
   162  	}
   163  
   164  	if err = k.joinMasters(newMasters, masters[0], kubeadmConfig, token, certKey); err != nil {
   165  		return err
   166  	}
   167  
   168  	if len(newMasters) > 0 {
   169  		oldWorkers := utilsnet.RemoveIPs(workers, newWorkers)
   170  		if err := k.configureLvs(masters, oldWorkers); err != nil {
   171  			return err
   172  		}
   173  	}
   174  
   175  	if err = k.joinNodes(newWorkers, masters, kubeadmConfig, token); err != nil {
   176  		return err
   177  	}
   178  
   179  	logrus.Info("cluster scale up succeeded!")
   180  	return nil
   181  }
   182  
   183  func (k *Runtime) ScaleDown(mastersToDelete, workersToDelete []net.IP) error {
   184  	masters := k.infra.GetHostIPListByRole(common.MASTER)
   185  	workers := k.infra.GetHostIPListByRole(common.NODE)
   186  
   187  	remainMasters := utilsnet.RemoveIPs(masters, mastersToDelete)
   188  	if len(remainMasters) == 0 {
   189  		return fmt.Errorf("cleaning up all masters is illegal, unless you give the --all flag, which will delete the entire cluster")
   190  	}
   191  
   192  	if len(workersToDelete) > 0 {
   193  		if err := k.deleteNodes(workersToDelete, remainMasters); err != nil {
   194  			return err
   195  		}
   196  	}
   197  
   198  	if len(mastersToDelete) > 0 {
   199  		remainWorkers := utilsnet.RemoveIPs(workers, workersToDelete)
   200  		if err := k.deleteMasters(mastersToDelete, remainMasters); err != nil {
   201  			return err
   202  		}
   203  		if err := k.configureLvs(remainMasters, remainWorkers); err != nil {
   204  			return err
   205  		}
   206  	}
   207  
   208  	logrus.Info("cluster scale down succeeded!")
   209  	return nil
   210  }
   211  
   212  // dumpKubeConfigIntoCluster save AdminKubeConf to cluster as secret resource.
   213  func (k *Runtime) dumpKubeConfigIntoCluster(driver runtime.Driver, master0 net.IP) error {
   214  	kubeConfigContent, err := os.ReadFile(AdminKubeConfPath)
   215  	if err != nil {
   216  		return err
   217  	}
   218  
   219  	kubeConfigContent = bytes.ReplaceAll(kubeConfigContent, []byte("apiserver.cluster.local"), []byte(master0.String()))
   220  
   221  	secret := &corev1.Secret{
   222  		ObjectMeta: metav1.ObjectMeta{
   223  			Name:      "admin.conf",
   224  			Namespace: metav1.NamespaceSystem,
   225  		},
   226  		Type: corev1.SecretTypeOpaque,
   227  		Data: map[string][]byte{
   228  			"admin.conf": kubeConfigContent,
   229  		},
   230  	}
   231  
   232  	if err := driver.Create(context.Background(), secret, &runtimeClient.CreateOptions{}); err != nil {
   233  		if !apierrors.IsAlreadyExists(err) {
   234  			return fmt.Errorf("unable to create secret: %v", err)
   235  		}
   236  
   237  		if err := driver.Update(context.Background(), secret, &runtimeClient.UpdateOptions{}); err != nil {
   238  			return fmt.Errorf("unable to update secret: %v", err)
   239  		}
   240  	}
   241  
   242  	return nil
   243  }
   244  
   245  // /var/lib/sealer/data/my-cluster/pki
   246  func (k *Runtime) getPKIPath() string {
   247  	return filepath.Join(k.infra.GetClusterRootfsPath(), "pki")
   248  }
   249  
   250  // /var/lib/sealer/data/my-cluster/pki/etcd
   251  func (k *Runtime) getEtcdCertPath() string {
   252  	return filepath.Join(k.getPKIPath(), "etcd")
   253  }
   254  
   255  // /var/lib/sealer/data/my-cluster/rootfs/statics
   256  func (k *Runtime) getStaticFileDir() string {
   257  	return filepath.Join(k.infra.GetClusterRootfsPath(), "statics")
   258  }
   259  
   260  // /var/lib/sealer/data/my-cluster/mount/etc/kubeadm.yml
   261  func (k *Runtime) getDefaultKubeadmConfig() string {
   262  	return filepath.Join(k.infra.GetClusterRootfsPath(), "etc", "kubeadm.yml")
   263  }
   264  
   265  func (k *Runtime) getAPIServerDomain() string {
   266  	return k.Config.APIServerDomain
   267  }
   268  
   269  func (k *Runtime) getAPIServerVIP() net.IP {
   270  	return net.ParseIP(k.Config.VIP)
   271  }