Documentation ¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var Command = cli.Command{ Name: "migrate", Usage: "Migrate running container", Flags: []cli.Flag{ cli.StringFlag{ Name: "src", Usage: "Source host where the container is running", }, cli.StringFlag{ Name: "dst", Usage: "Target host to migrate the container", }, cli.BoolFlag{ Name: "pre-dump", Usage: "Perform a pre-dump to minimize downtime", }, cli.BoolFlag{ Name: "force", Usage: "Doesn't fail of validations related to different versions of executable binaries and cpu differences", }, cli.StringFlag{ Name: "hook-pre-restore", Usage: "Command to run right before restoring process", }, cli.StringFlag{ Name: "hook-post-restore", Usage: "Command to run right after a successful process restoration", }, cli.StringFlag{ Name: "hook-failed-restore", Usage: "Command to run right after a failed process restoration", }, }, Action: func(c *cli.Context) { srcUrl := validate.ParseURL(c.String("src")) dstUrl := validate.ParseURL(c.String("dst")) log.Println("Performing validations") src, dst := validate.Validate(srcUrl, dstUrl, c.Bool("force")) log.Println("Preparing everything to do a checkpoint") containerId := getContainerId(srcUrl.Path) var imagesPath string var restoreCmd cmd.Cmd var migrateStart time.Time var downtime time.Duration if c.Bool("pre-dump") { predumpPath := fmt.Sprintf("%s/images/0", srcUrl.Path) prepareDir(src, predumpPath) checkpoint(src, containerId, predumpPath, true) srcTarFile := fmt.Sprintf("%s/predump.tar.gz", srcUrl.Path) prepareTar(src, srcTarFile, predumpPath) prepareDir(dst, fmt.Sprintf("%s/images/0", dstUrl.Path)) log.Println("Copying predump image to dst") err := cmd.Scp(src.URL(srcTarFile), dst.URL(fmt.Sprintf("%s/images/0", dstUrl.Path))) if err != nil { log.Fatal("Error copying predump image files to dst", err) } dstTarFile := fmt.Sprintf("%s/images/0/predump.tar.gz", dstUrl.Path) unpackTar(dst, dstTarFile, fmt.Sprintf("%s/images/0", dstUrl.Path)) migrateStart = time.Now() iptablesBefore, ipErr := getIPTables(src) if ipErr != nil { log.Fatal("Error capturing iptables rules. ", ipErr) } imagesPath = fmt.Sprintf("%s/images/1", srcUrl.Path) prepareDir(src, fmt.Sprintf("%s/images/1", srcUrl.Path)) log.Println("Performing the checkpoint") _, _, err = src.Run("sudo", "runc", "--id", containerId, "checkpoint", "--image-path", imagesPath, "--prev-images-dir", "../0", "--track-mem", "--tcp-established") if err != nil { log.Fatal("Error performing checkpoint:", err) } iptablesAfter, ipErr2 := getIPTables(src) if ipErr2 != nil { log.Fatal("Error capturing iptables rules. ", ipErr2) } iptablesRules := iptables.Diff(iptablesAfter, iptablesBefore) srcTarFile = fmt.Sprintf("%s/dump.tar.gz", srcUrl.Path) prepareTar(src, srcTarFile, imagesPath) prepareDir(dst, fmt.Sprintf("%s/images/1", dstUrl.Path)) log.Println("Copying final dump image to dst") err = cmd.Scp(src.URL(srcTarFile), dst.URL(fmt.Sprintf("%s/images/1", dstUrl.Path))) if err != nil { log.Fatal("Error copying predump image files to dst", err) } dstTarFile = fmt.Sprintf("%s/images/1/dump.tar.gz", dstUrl.Path) unpackTar(dst, dstTarFile, fmt.Sprintf("%s/images/1", dstUrl.Path)) log.Println("Performing the restore") applyErr := applyIPTablesRules(dst, iptablesRules) if applyErr != nil { log.Fatal("Error applying IPTables rules. ", applyErr) } TriggerHook(c.String("hook-pre-restore")) removeErr := removeIPTablesRules(src, iptablesRules) if removeErr != nil { log.Fatal("Error removing IPTables rules. ", removeErr) } configFilePath := fmt.Sprintf("%s/config.json", dstUrl.Path) runtimeFilePath := fmt.Sprintf("%s/runtime.json", dstUrl.Path) dstImagesPath := fmt.Sprintf("%s/images/1", dstUrl.Path) restoreCmd, err = dst.Start("sudo", "runc", "--id", containerId, "restore", "--tcp-established", "--image-path", dstImagesPath, "--config-file", configFilePath, "--runtime-file", runtimeFilePath) if err != nil { log.Fatal("Error performing restore:", err) } } else { imagesPath = fmt.Sprintf("%s/images", srcUrl.Path) prepareDir(src, imagesPath) migrateStart = time.Now() iptablesBefore, ipErr := getIPTables(src) if ipErr != nil { log.Fatal("Error capturing iptables rules. ", ipErr) } checkpoint(src, containerId, imagesPath, false) iptablesAfter, ipErr2 := getIPTables(src) if ipErr2 != nil { log.Fatal("Error capturing iptables rules. ", ipErr2) } iptablesRules := iptables.Diff(iptablesAfter, iptablesBefore) srcTarFile := fmt.Sprintf("%s/dump.tar.gz", srcUrl.Path) prepareTar(src, srcTarFile, imagesPath) prepareDir(dst, fmt.Sprintf("%s/images", dstUrl.Path)) log.Println("Copying checkpoint image to dst") err := cmd.Scp(src.URL(srcTarFile), dst.URL(fmt.Sprintf("%s/images", dstUrl.Path))) if err != nil { log.Fatal("Error copying image files to dst", err) } dstTarFile := fmt.Sprintf("%s/images/dump.tar.gz", dstUrl.Path) unpackTar(dst, dstTarFile, fmt.Sprintf("%s/images", dstUrl.Path)) log.Println("Performing the restore") applyErr := applyIPTablesRules(dst, iptablesRules) if applyErr != nil { log.Fatal("Error applying IPTables rules. ", applyErr) } TriggerHook(c.String("hook-pre-restore")) removeErr := removeIPTablesRules(src, iptablesRules) if removeErr != nil { log.Fatal("Error removing IPTables rules. ", removeErr) } configFilePath := fmt.Sprintf("%s/config.json", dstUrl.Path) runtimeFilePath := fmt.Sprintf("%s/runtime.json", dstUrl.Path) dstImagesPath := fmt.Sprintf("%s/images", dstUrl.Path) restoreCmd, err = dst.Start("sudo", "runc", "--id", containerId, "restore", "--tcp-established", "--image-path", dstImagesPath, "--config-file", configFilePath, "--runtime-file", runtimeFilePath) if err != nil { log.Fatal("Error performing restore:", err) } } var restoreSucceed bool var restoreError error var wg sync.WaitGroup wg.Add(1) go func() { restoreError = restoreCmd.Wait() wg.Done() }() go func() { log.Println("Waiting for container to start...") if isRunning(containerId, dst) { restoreSucceed = true wg.Done() return } ticker := time.NewTicker(200 * time.Millisecond) go func() { for _ = range ticker.C { if isRunning(containerId, dst) { restoreSucceed = true break } } ticker.Stop() wg.Done() }() }() wg.Wait() downtime = time.Since(migrateStart) if restoreSucceed { log.Printf("Restore finished successfully, total downtime: %dms", downtime/time.Millisecond) TriggerHook(c.String("hook-post-restore")) } else { log.Println("Error performing restore:", restoreError) TriggerHook(c.String("hook-failed-restore")) } }, }
Functions ¶
func TriggerHook ¶
Types ¶
This section is empty.
Click to show internal directories.
Click to hide internal directories.