From 226057115f52200ab17cb4de2d70b6f7dfc31fb9 Mon Sep 17 00:00:00 2001 From: lvyongkang <33888081+wizardlyk@users.noreply.github.com> Date: Wed, 1 Mar 2023 17:33:07 +0800 Subject: [PATCH] support sealer upgrade (#2047) Signed-off-by: wb-lyk925458 Co-authored-by: wb-lyk925458 --- cmd/sealer/cmd/cluster/run.go | 94 ++++++++++++++++++++++++++++++++ common/common.go | 1 + pkg/cluster-runtime/hook.go | 2 + pkg/cluster-runtime/upgrader.go | 96 +++++++++++++++++++++++++++++++++ 4 files changed, 193 insertions(+) create mode 100644 pkg/cluster-runtime/upgrader.go diff --git a/cmd/sealer/cmd/cluster/run.go b/cmd/sealer/cmd/cluster/run.go index 049d004a446..5f19c2e1964 100644 --- a/cmd/sealer/cmd/cluster/run.go +++ b/cmd/sealer/cmd/cluster/run.go @@ -52,6 +52,9 @@ run cluster by CLI flags: run app image: sealer run localhost/nginx:v1 + +run upgrade image: + sealer run docker.io/sealerio/kubernetes:v1.22.15-upgrade --mode upgrade ` func NewRunCmd() *cobra.Command { @@ -86,6 +89,9 @@ func NewRunCmd() *cobra.Command { } if clusterFile != "" { + if runFlags.Mode == common.ApplyModeUpgrade { + return fmt.Errorf("you can't specify Clusterfile in upgrade mode") + } return runWithClusterfile(clusterFile, runFlags) } @@ -109,6 +115,10 @@ func NewRunCmd() *cobra.Command { return fmt.Errorf("failed to get cluster image extension: %s", err) } + if runFlags.Mode == common.ApplyModeUpgrade { + return upgradeCluster(imageEngine, imageSpec, args[0]) + } + if imageSpec.ImageExtension.Type == imagev1.AppInstaller { app := v2.ConstructApplication(nil, runFlags.Cmds, runFlags.AppNames) @@ -416,3 +426,87 @@ func installApplication(appImageName string, envs []string, app *v2.Application, return nil } + +func upgradeCluster(imageEngine imageengine.Interface, imageSpec *imagev1.ImageSpec, imageName string) error { + cf, err := clusterfile.NewClusterFile(nil) + if err != nil { + return err + } + + cluster := cf.GetCluster() + infraDriver, err := infradriver.NewInfraDriver(&cluster) + if err != nil { + return err + } + clusterHosts := infraDriver.GetHostIPList() + + clusterHostsPlatform, err := infraDriver.GetHostsPlatform(clusterHosts) + if err != nil { + return err + } + + logrus.Infof("start to upgrade cluster with image: %s", imageName) + + imageMounter, err := imagedistributor.NewImageMounter(imageEngine, clusterHostsPlatform) + if err != nil { + return err + } + + imageMountInfo, err := imageMounter.Mount(imageName) + if err != nil { + return err + } + + defer func() { + err = imageMounter.Umount(imageName, imageMountInfo) + if err != nil { + logrus.Errorf("failed to umount cluster image") + } + }() + + distributor, err := imagedistributor.NewScpDistributor(imageMountInfo, infraDriver, cf.GetConfigs()) + if err != nil { + return err + } + + plugins, err := loadPluginsFromImage(imageMountInfo) + if err != nil { + return err + } + + if cf.GetPlugins() != nil { + plugins = append(plugins, cf.GetPlugins()...) + } + + runtimeConfig := &clusterruntime.RuntimeConfig{ + Distributor: distributor, + ImageSpec: imageSpec, + Plugins: plugins, + ContainerRuntimeConfig: cluster.Spec.ContainerRuntime, + } + + upgrader, err := clusterruntime.NewInstaller(infraDriver, *runtimeConfig) + if err != nil { + return err + } + + //we need to save desired clusterfile to local disk temporarily + //and will use it later to clean the cluster node if apply failed. + if err = cf.SaveAll(clusterfile.SaveOptions{}); err != nil { + return err + } + + err = upgrader.Upgrade() + if err != nil { + return err + } + + //save and commit + if err = cf.SaveAll(clusterfile.SaveOptions{CommitToCluster: true}); err != nil { + return err + } + + logrus.Infof("succeeded in upgrading cluster with image %s", imageName) + + return nil +} diff --git a/common/common.go b/common/common.go index c31cb022011..f8fe099783b 100644 --- a/common/common.go +++ b/common/common.go @@ -75,6 +75,7 @@ const ( const ( ApplyModeApply = "apply" ApplyModeLoadImage = "loadImage" + ApplyModeUpgrade = "upgrade" ) // image module diff --git a/pkg/cluster-runtime/hook.go b/pkg/cluster-runtime/hook.go index 07fc6dfe261..4082b20af84 100644 --- a/pkg/cluster-runtime/hook.go +++ b/pkg/cluster-runtime/hook.go @@ -55,6 +55,8 @@ const ( PreScaleUpCluster Phase = "pre-scaleup" //PostScaleUpCluster on master0 PostScaleUpCluster Phase = "post-scaleup" + //UpgradeHost on master0 + UpgradeCluster Phase = "upgrade" //PreInitHost on role PreInitHost Phase = "pre-init-host" diff --git a/pkg/cluster-runtime/upgrader.go b/pkg/cluster-runtime/upgrader.go new file mode 100644 index 00000000000..38b1842c67c --- /dev/null +++ b/pkg/cluster-runtime/upgrader.go @@ -0,0 +1,96 @@ +// Copyright © 2022 Alibaba Group Holding Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package clusterruntime + +import ( + "fmt" + "net" + + "github.com/sealerio/sealer/common" + "github.com/sealerio/sealer/pkg/application" + imagev1 "github.com/sealerio/sealer/pkg/define/image/v1" + "github.com/sealerio/sealer/pkg/registry" + v2 "github.com/sealerio/sealer/types/api/v2" +) + +func (i *Installer) Upgrade() error { + var ( + masters = i.infraDriver.GetHostIPListByRole(common.MASTER) + master0 = masters[0] + workers = getWorkerIPList(i.infraDriver) + all = append(masters, workers...) + rootfs = i.infraDriver.GetClusterRootfsPath() + cmds = i.infraDriver.GetClusterLaunchCmds() + appNames = i.infraDriver.GetClusterLaunchApps() + extension = i.ImageSpec.ImageExtension + ) + + if extension.Type != imagev1.KubeInstaller { + return fmt.Errorf("exit upgrade process, wrong cluster image type: %s", extension.Type) + } + + // distribute rootfs + if err := i.Distributor.Distribute(all, rootfs); err != nil { + return err + } + + crInfo, err := i.containerRuntimeInstaller.GetInfo() + if err != nil { + return err + } + + var deployHosts []net.IP + if i.regConfig.LocalRegistry != nil { + installer := registry.NewInstaller(nil, i.regConfig.LocalRegistry, i.infraDriver, i.Distributor) + if *i.regConfig.LocalRegistry.HA { + deployHosts, err = installer.Reconcile(masters) + if err != nil { + return err + } + } else { + deployHosts, err = installer.Reconcile([]net.IP{master0}) + if err != nil { + return err + } + } + } + registryConfigurator, err := registry.NewConfigurator(deployHosts, crInfo, i.regConfig, i.infraDriver, i.Distributor) + if err != nil { + return err + } + + if err = registryConfigurator.InstallOn(masters, workers); err != nil { + return err + } + + if err := i.runClusterHook(master0, UpgradeCluster); err != nil { + return err + } + + //CMD + + appInstaller := NewAppInstaller(i.infraDriver, i.Distributor, extension) + + v2App, err := application.NewV2Application(v2.ConstructApplication(i.Application, cmds, appNames), extension) + if err != nil { + return fmt.Errorf("failed to parse application:%v ", err) + } + + if err = appInstaller.Launch(master0, v2App.GetImageLaunchCmds()); err != nil { + return err + } + + return nil +}