github.com/sealerio/sealer@v0.11.1-0.20240507115618-f4f89c5853ae/pkg/runtime/kubernetes/utils.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  	"context"
    19  	"fmt"
    20  	"net"
    21  	"path"
    22  	"sort"
    23  	"strconv"
    24  	"strings"
    25  	"time"
    26  
    27  	"golang.org/x/sync/errgroup"
    28  	corev1 "k8s.io/api/core/v1"
    29  	"k8s.io/apimachinery/pkg/util/wait"
    30  	"k8s.io/client-go/tools/clientcmd"
    31  	runtimeClient "sigs.k8s.io/controller-runtime/pkg/client"
    32  
    33  	"github.com/sealerio/sealer/common"
    34  	"github.com/sealerio/sealer/pkg/ipvs"
    35  	"github.com/sealerio/sealer/pkg/runtime"
    36  	netutils "github.com/sealerio/sealer/utils/net"
    37  	"github.com/sealerio/sealer/utils/shellcommand"
    38  )
    39  
    40  const (
    41  	AuditPolicyYml = "audit-policy.yml"
    42  	KubeadmFileYml = "/etc/kubernetes/kubeadm.yaml"
    43  	AdminConf      = "admin.conf"
    44  	ControllerConf = "controller-manager.conf"
    45  	SchedulerConf  = "scheduler.conf"
    46  	KubeletConf    = "kubelet.conf"
    47  
    48  	// kube file
    49  	KUBECONTROLLERCONFIGFILE = "/etc/kubernetes/controller-manager.conf"
    50  	KUBESCHEDULERCONFIGFILE  = "/etc/kubernetes/scheduler.conf"
    51  	AdminKubeConfPath        = "/etc/kubernetes/admin.conf"
    52  	LvscarePodFileName       = "kube-lvscare.yaml"
    53  )
    54  
    55  const (
    56  	GetCustomizeCRISocket         = "cat /etc/sealerio/cri/socket-path"
    57  	RemoteCleanCustomizeCRISocket = "rm -f /etc/sealerio/cri/socket-path"
    58  	RemoteAddEtcHosts             = "cat /etc/hosts |grep '%s' || echo '%s' >> /etc/hosts"
    59  	RemoteReplaceKubeConfig       = `grep -qF "apiserver.cluster.local" %s  && sed -i 's/apiserver.cluster.local/%s/' %s && sed -i 's/apiserver.cluster.local/%s/' %s`
    60  	RemoveKubeConfig              = "rm -rf /usr/bin/kube* && rm -rf ~/.kube/"
    61  	RemoteCleanK8sOnHost          = `systemctl restart docker kubelet; if which kubeadm > /dev/null 2>&1;then kubeadm reset -f %s;fi && \
    62  rm -rf /etc/kubernetes/ && \
    63  rm -rf /etc/systemd/system/kubelet.service.d && rm -rf /etc/systemd/system/kubelet.service && \
    64  rm -rf /usr/bin/kubeadm && rm -rf /usr/bin/kubelet-pre-start.sh && \
    65  rm -rf /usr/bin/kubelet && rm -rf /usr/bin/kubectl && \
    66  rm -rf /var/lib/kubelet/* && rm -rf /etc/sysctl.d/k8s.conf && \
    67  rm -rf /etc/cni && rm -rf /opt/cni && \
    68  rm -rf /var/lib/etcd/* && rm -rf /var/etcd/* && rm -rf /root/.kube/config
    69  `
    70  	RemoteRemoveAPIServerEtcHost = "echo \"$(sed \"/%s/d\" /etc/hosts)\" > /etc/hosts"
    71  	KubeDeleteNode               = "kubectl delete node %s"
    72  
    73  	RemoteCheckRoute = "seautil route check --host %s"
    74  	RemoteAddRoute   = "seautil route add --host %s --gateway %s"
    75  	RemoteDelRoute   = "if command -v seautil > /dev/null 2>&1; then seautil route del --host %s --gateway %s; fi"
    76  )
    77  
    78  // StaticFile :static file should not be template, will never be changed while initialization.
    79  type StaticFile struct {
    80  	DestinationDir string
    81  	Name           string
    82  }
    83  
    84  // MasterStaticFiles Put static files here, can be moved to all master nodes before kubeadm execution
    85  var MasterStaticFiles = []*StaticFile{
    86  	{
    87  		DestinationDir: "/etc/kubernetes",
    88  		Name:           AuditPolicyYml,
    89  	},
    90  }
    91  
    92  // return node name from k8s cluster, if not found, return "" and error is nil
    93  func (k *Runtime) getNodeNameByCmd(host net.IP) (string, error) {
    94  	cli, err := k.GetCurrentRuntimeDriver()
    95  	if err != nil {
    96  		return "", err
    97  	}
    98  	nodes := &corev1.NodeList{}
    99  	if err := cli.List(context.Background(), nodes); err != nil {
   100  		return "", err
   101  	}
   102  
   103  	for _, nodeInfo := range nodes.Items {
   104  		for _, addr := range nodeInfo.Status.Addresses {
   105  			if addr.Type == corev1.NodeInternalIP && host.String() == addr.Address {
   106  				return nodeInfo.Name, nil
   107  			}
   108  		}
   109  	}
   110  
   111  	return "", fmt.Errorf("failed to find node name for %s", host.String())
   112  }
   113  
   114  func vlogToStr(vlog int) string {
   115  	str := strconv.Itoa(vlog)
   116  	return " -v " + str
   117  }
   118  
   119  type CommandType string
   120  
   121  const InitMaster CommandType = "initMaster"
   122  const JoinMaster CommandType = "joinMaster"
   123  const JoinNode CommandType = "joinNode"
   124  
   125  func (k *Runtime) Command(name CommandType, nodeNameOverride string) (string, error) {
   126  	//cmds := make(map[CommandType]string)
   127  	// Please convert your v1beta1 configuration files to v1beta2 using the
   128  	// "kubeadm config migrate" command of kubeadm v1.15.x, so v1.14 not support multi network interface.
   129  	cmds := map[CommandType]string{
   130  		InitMaster: fmt.Sprintf("kubeadm init --config=%s --upload-certs", KubeadmFileYml),
   131  		JoinMaster: fmt.Sprintf("kubeadm join --config=%s", KubeadmFileYml),
   132  		JoinNode:   fmt.Sprintf("kubeadm join --config=%s", KubeadmFileYml),
   133  	}
   134  
   135  	v, ok := cmds[name]
   136  	if !ok {
   137  		return "", fmt.Errorf("failed to get kubeadm command: %v", cmds)
   138  	}
   139  	if nodeNameOverride != "" {
   140  		v = fmt.Sprintf("%s --node-name %s", v, nodeNameOverride)
   141  	}
   142  
   143  	if runtime.IsInContainer() {
   144  		return fmt.Sprintf("%s%s%s", v, vlogToStr(k.Config.Vlog), " --ignore-preflight-errors=all"), nil
   145  	}
   146  	if name == InitMaster || name == JoinMaster {
   147  		return fmt.Sprintf("%s%s%s", v, vlogToStr(k.Config.Vlog), " --ignore-preflight-errors=SystemVerification,Port-10250,DirAvailable--etc-kubernetes-manifests"), nil
   148  	}
   149  
   150  	return fmt.Sprintf("%s%s%s", v, vlogToStr(k.Config.Vlog), " --ignore-preflight-errors=Port-10250,DirAvailable--etc-kubernetes-manifests"), nil
   151  }
   152  
   153  func (k *Runtime) getNodeNameOverride(ip net.IP) string {
   154  	if v, ok := k.infra.GetClusterEnv()[common.EnvUseIPasNodeName]; ok && v == "true" {
   155  		return ip.String()
   156  	}
   157  
   158  	return ""
   159  }
   160  
   161  func GetClientFromConfig(adminConfPath string) (runtimeClient.Client, error) {
   162  	adminConfig, err := clientcmd.BuildConfigFromFlags("", adminConfPath)
   163  	if nil != err {
   164  		return nil, err
   165  	}
   166  
   167  	var ret runtimeClient.Client
   168  
   169  	timeout := time.Second * 30
   170  	err = wait.PollImmediate(time.Second*10, timeout, func() (done bool, err error) {
   171  		cli, err := runtimeClient.New(adminConfig, runtimeClient.Options{})
   172  		if nil != err {
   173  			return false, err
   174  		}
   175  
   176  		ns := corev1.Namespace{}
   177  		if err := cli.Get(context.Background(), runtimeClient.ObjectKey{Name: "default"}, &ns); nil != err {
   178  			return false, err
   179  		}
   180  
   181  		ret = cli
   182  
   183  		return true, nil
   184  	})
   185  
   186  	return ret, err
   187  }
   188  
   189  func (k *Runtime) configureLvs(masterHosts, clientHosts []net.IP) error {
   190  	lvsImageURL := path.Join(k.Config.RegistryInfo.URL, common.LvsCareRepoAndTag)
   191  
   192  	var rs []string
   193  	var realEndpoints []string
   194  
   195  	masters := netutils.IPsToIPStrs(masterHosts)
   196  	sort.Strings(masters)
   197  	for _, m := range masters {
   198  		rep := net.JoinHostPort(m, "6443")
   199  		rs = append(rs, fmt.Sprintf("--rs %s", rep))
   200  		realEndpoints = append(realEndpoints, rep)
   201  	}
   202  	vs := net.JoinHostPort(k.getAPIServerVIP().String(), "6443")
   203  	ipvsCmd := fmt.Sprintf("seautil ipvs --vs %s %s --health-path /healthz --health-schem https --run-once", vs, strings.Join(rs, " "))
   204  	y, err := ipvs.LvsStaticPodYaml(common.KubeLvsCareStaticPodName, vs, realEndpoints, lvsImageURL,
   205  		"/healthz", "https")
   206  	if err != nil {
   207  		return err
   208  	}
   209  	lvscareStaticCmd := ipvs.GetCreateLvscareStaticPodCmd(y, LvscarePodFileName)
   210  
   211  	eg, _ := errgroup.WithContext(context.Background())
   212  
   213  	// flush all cluster nodes as latest ipvs policy.
   214  	for i := range clientHosts {
   215  		node := clientHosts[i]
   216  		eg.Go(func() error {
   217  			err := k.infra.CmdAsync(node, nil, ipvsCmd, lvscareStaticCmd, shellcommand.CommandSetHostAlias(k.getAPIServerDomain(), k.getAPIServerVIP().String()))
   218  			if err != nil {
   219  				return fmt.Errorf("failed to config ndoes lvs policy %s: %v", ipvsCmd, err)
   220  			}
   221  			return nil
   222  		})
   223  	}
   224  
   225  	return eg.Wait()
   226  }