原文来自CRIU官网的文章:
翻译此文,用于学习CRIU的dump和pre-dump机制。翻译时没有用翻译软件,不求字字准确,能表达出核心含义,语句通顺就行。甚至会按照我对CRIU的研究拓展一下。
本文作者按个人理解加以描述的文字用(__)来标记。

:::warning 注意:关于热迁移/实时迁移的文章应该参考这篇,本文只是介绍了为什么热迁移是可以实现的 ::: 热迁移的目的是想在物理机之间提供一种无缝迁移的服务,这不会影响到客户进程或者应用程序的运行。(即热迁移前后进程/容器的内存不变,状态不变)。
CRIU工具可以用来为应用或者容器执行热迁移,这篇文章描述了它是怎么做到的。

前提条件

为了对一个应用或者容器执行热迁移,你应该要确保被进程访问的文件在迁移的两个节点(即,源端和目的端)上都是可以访问的。这个目标是可以被达到的,使用共享文件系统比如NFS、GlusterFS或者CEPH,甚至可以用rsync工具在节点之间拷贝文件。在本文中,我们进一步假设两个节点的文件系统是相同的。
另一个要关注的要点是“网络”。一般来说要关注的是IP地址,也就是应用程序使用的IP在目标节点上是可用的。关注IP的原因是,CRIU在恢复TCP socket的时候,会尝试bind()和connect()他们的原始凭证(用于恢复进程的网络)。如果需要的IP地址因为某些原因在目的端不可用,则相应的系统调用将会失败(这里指上述的bind()和connect()等)。另外,在热迁移的过程中,网络连接会被CRIU锁定,这里有两种选择:
第一种是应用程序和主机共享网络。这种情况下CRIU用iptables规则来锁定连接。因此要确保iptables规则在目标节点可用。
第二种是应用程序有自己的网络命令空间(如容器中),这种情况下CRIU会调用一个叫做action scripts来锁定网络,这取决于你想怎样锁定(即支持自定义),在docker的情况下,docker daemon(docker的守护程序)会通过libnetwork库处理。
到这里,为了进程热迁移,你要做出以下步骤:

dump

把你想迁移的程序dump到一个位置,并通知CRIU在dump之后让程序处于停止状态。
在源端执行以下命令

  1. criu dump --tree <pid> --images-dir <path-to-existing-directory> --leave-stopped

如果你是用的是共享文件系统(如共享存储、或者软件实现的共享文件系统,即目的端能访问到的),则放置image的目录可以放在共享文件系统中,这样你可以跳过copy这个步骤,执行restore。

copy

拷贝生成的image到目的端,在源端执行以下命令

  1. scp -r <path-to-images-dir> <dst>:/<path-to-images>

restore

到目的节点,用image来恢复应用程序。在目的端执行以下命令

  1. criu restore --images-dir <path-to-images>

kill

如果所有步骤都完成并成功,可以回到源节点干掉原来的进程。(这里应该是dump之后程序是被冻结而不是被干掉。要手动干掉程序才行。)

注意

  • 存放image的目录会包含两份应用程序的内存(这里猜想应该是在源节点dump一份,然后拷贝到目标节点又一份),这可能会消耗空间,CRIU可以执行无磁盘迁移(,这里会用到page-server,即dump时利用tcp直接传输到远端并生成image)来解决这个问题。
  • 上面这种热迁移的方式(即disk-less migration)导致的另一个问题是,当拷贝内存到远端时,进程仍然是被冻结的,如果它使用了大量的内存,则进程冻结的时间会非常的长!CRIU对这一场景的提速方式建议参考迭代迁移。
  • 如果你在一个shell中做热迁移,记得一定要在源端和目的端用--shell-job选项,而且是dump和restore的时候都要用。具体可以参考。

    查看更多

  • P.Haul

  • Iterative migration
  • Disk-less migration
  • Lazy migration
  • Page server