Skip to content

Add support to migrate containers#2272

Merged
openshift-merge-robot merged 9 commits intocontainers:masterfrom
adrianreber:migration
Jun 7, 2019
Merged

Add support to migrate containers#2272
openshift-merge-robot merged 9 commits intocontainers:masterfrom
adrianreber:migration

Conversation

@adrianreber
Copy link
Collaborator

This series adds container migration support to Podman.

The basic steps to migrate containers are:

 Source system:
  * podman container checkpoint -l -e /tmp/checkpoint.tar.gz
  * scp /tmp/checkpoint.tar.gz destination:/tmp

 Destination system:
  * podman pull 'container-image-as-on-source-system'
  * podman container restore -i /tmp/checkpoint.tar.gz

For the newly added test to work an updated runc is required, which is still under review: opencontainers/runc#1968

Tries to solve: #1618

This PR includes the actual code, man-pages, bash-completion, tests, tutorial update.

Once this is merged I would also like to publish a related article on podman.io.

@rst0git
Copy link
Contributor

rst0git commented Feb 5, 2019

The restore of a looper example fails for me. Still investigating why...
restore.log

@openshift-merge-robot
Copy link
Collaborator

/retest

@adrianreber
Copy link
Collaborator Author

The restore of a looper example fails for me. Still investigating why...
restore.log

Are you using runc with the changes from opencontainers/runc#1968? Could be there is some runc code missing to create /proc just as it did not create bind mount mountpoints before opencontainers/runc#1968. Please let me know how you are testing it so I can try to recreate.

@rst0git
Copy link
Contributor

rst0git commented Feb 6, 2019

Are you using runc with the changes from opencontainers/runc#1968?

Yes, I installed runc from opencontainers/runc#1968, criu from the criu-dev branch and podman from this PR.

Could be there is some runc code missing to create /proc just as it did not create bind mount mountpoints before opencontainers/runc#1968. Please let me know how you are testing it so I can try to recreate.

I followed these steps to create, checkpoint, and restore a container:

sudo podman run -d --name looper busybox /bin/sh -c 'i=0; while true; do echo $i; i=$(expr $i + 1); sleep 1; done'
sudo podman container checkpoint looper -e /tmp/checkpoint.tar.gz
sudo podman container rm looper
sudo podman container restore -i /tmp/checkpoint.tar.gz

Even though the restore has failed in the last step, a looper container is still created (with status Created). Therefore, I can still run sudo podman container start looper to start the container.

@adrianreber
Copy link
Collaborator Author

@rst0git This is the same bug as in my runc pull request except that it is also true for non-bind mount mountpoints. It seems runc just creates all missing mountpoints even for read-only root filesystems. If you use a container image which includes all required mountpoints (in this case /run /proc /sys are missing) it should work. I will update my runc PR to handle also missing non-bind mount mountpoints.

@adrianreber
Copy link
Collaborator Author

@mheon Thanks for the review. At first I was unsure if I can do all the necessary changes, but now, after I have thought about it, I think I can actually do everything you suggested and the result will be better. I hope. So thanks for pointing it out.

@openshift-merge-robot
Copy link
Collaborator

/retest

@avagin
Copy link

avagin commented Feb 6, 2019

  • scp /tmp/checkpoint.tar.gz destination:/tmp
    What is inside /tmp/checkpoint.tar.gz? Do you snapshot a container rootfs?

@adrianreber
Copy link
Collaborator Author

  • scp /tmp/checkpoint.tar.gz destination:/tmp
    What is inside /tmp/checkpoint.tar.gz? Do you snapshot a container rootfs?

The checkpoint directory and the container definition (spec, config, network). No filesystem (yet). I was thinking about doing an automatic commit of the highest layer and including it also. But right now it is only the output of CRIU and some json files.

@adrianreber adrianreber force-pushed the migration branch 2 times, most recently from 74ab7b8 to 0ba0da7 Compare February 6, 2019 19:26
@adrianreber
Copy link
Collaborator Author

@mheon I tried to rework my changes to the newContainer() function. There is now a RestoreContainer() function. Please have a look if this is now a better approach.

@adrianreber
Copy link
Collaborator Author

All CI errors are the expected errors as long as the necessary runc patches have not been merged.

@mheon
Copy link
Member

mheon commented Feb 6, 2019

I'll do a more thorough review tomorrow, but I'm generally in favor of the way NewContainer was split up.

Still a little iffy on copying over the OCI config... I need to check, but there shouldn't be much in there that isn't deterministically generated, so it might not be necessary.

We do need to make sure that the ContainerConfig we copied over makes sense before we use it - if the container is in a pod, we need a pod with the same ID present on the remote host, and the same holds for named volumes. We might want to make a generic sanity checker for ContainerConfig that we can use for both NewContainer and this.

@rh-atomic-bot
Copy link
Collaborator

☔ The latest upstream changes (presumably #2252) made this pull request unmergeable. Please resolve the merge conflicts.

@openshift-ci-robot openshift-ci-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Feb 7, 2019
@cevich
Copy link
Member

cevich commented May 28, 2019

Nothing here and tests seem happy 😄

@rhatdan
Copy link
Member

rhatdan commented May 28, 2019

@mheon PTAL

@adrianreber
Copy link
Collaborator Author

@mheon any more comments on this PR?

@mheon
Copy link
Member

mheon commented Jun 3, 2019

Sorry, been distracted by other things. Let me do a final review.

@mheon
Copy link
Member

mheon commented Jun 3, 2019

Few things, but overall looks solid.

@rhatdan @vrothberg @giuseppe @TomSweeneyRedHat PTAL

@adrianreber
Copy link
Collaborator Author

@mheon , thanks a lot. I will add the checks for named volumes and dependencies and re-push.

Signed-off-by: Adrian Reber <areber@redhat.com>
This adds a couple of function in structure members needed in the next
commit to make container migration actually work. This just splits of
the function which are not modifying existing code.

Signed-off-by: Adrian Reber <areber@redhat.com>
This commit adds an option to the checkpoint command to export a
checkpoint into a tar.gz file as well as importing a checkpoint tar.gz
file during restore. With all checkpoint artifacts in one file it is
possible to easily transfer a checkpoint and thus enabling container
migration in Podman. With the following steps it is possible to migrate
a running container from one system (source) to another (destination).

 Source system:
  * podman container checkpoint -l -e /tmp/checkpoint.tar.gz
  * scp /tmp/checkpoint.tar.gz destination:/tmp

 Destination system:
  * podman pull 'container-image-as-on-source-system'
  * podman container restore -i /tmp/checkpoint.tar.gz

The exported tar.gz file contains the checkpoint image as created by
CRIU and a few additional JSON files describing the state of the
checkpointed container.

Now the container is running on the destination system with the same
state just as during checkpointing. If the container is kept running
on the source system with the checkpoint flag '-R', the result will be
that the same container is running on two different hosts.

Signed-off-by: Adrian Reber <areber@redhat.com>
The difference between container checkpoint/restore and container
migration is that for migration the container which was checkpointed
must not exist during restore. To simulate migration the container
is remove ('podman rm -fa') before being restored. The migration test
does following steps:

 * podman run
 * podman container checkpoint -l -e /tmp/checkpoint.tar.gz
 * podman rm -fa
 * podman container restore -i /tmp/checkpoint.tar.gz

Signed-off-by: Adrian Reber <areber@redhat.com>
Signed-off-by: Adrian Reber <areber@redhat.com>
Signed-off-by: Adrian Reber <areber@redhat.com>
Signed-off-by: Adrian Reber <areber@redhat.com>
If restoring a container from a checkpoint it was necessary that the
image the container is based was already available (podman pull).

This commit adds the image download to podman container restore if it
does not exist.

Signed-off-by: Adrian Reber <areber@redhat.com>
@adrianreber
Copy link
Collaborator Author

I think I was able to implememt all the changes from the latest review, let's see if the tests still pass.

The option to restore a container from an external checkpoint archive
(podman container restore -i /tmp/checkpoint.tar.gz) restores a
container with the same name and same ID as id had before checkpointing.

This commit adds the option '--name,-n' to 'podman container restore'.
With this option the restored container gets the name specified after
'--name,-n' and a new ID. This way it is possible to restore one
container multiple times.

If a container is restored with a new name Podman will not try to
request the same IP address for the container as it had during
checkpointing. This implicitly assumes that if a container is restored
from a checkpoint archive with a different name, that it will be
restored multiple times and restoring a container multiple times with
the same IP address will fail as each IP address can only be used once.

Signed-off-by: Adrian Reber <areber@redhat.com>
@adrianreber
Copy link
Collaborator Author

All tests green again (after a few retries).

@adrianreber
Copy link
Collaborator Author

Any further comments regarding this PR?

@mheon
Copy link
Member

mheon commented Jun 6, 2019

Sorry, we've been in a bit of a rush trying to get the recent CVE patched.

I'm good to merge with one more LGTM

@rhatdan
Copy link
Member

rhatdan commented Jun 7, 2019

/lgtm

@adrianreber
Copy link
Collaborator Author

Thanks everyone for the reviews and the patience getting this merged.

// a container from one host to another
It("podman checkpoint container with export (migration)", func() {
// CRIU does not work with seccomp correctly on RHEL7
session := podmanTest.Podman([]string{"run", "-it", "--security-opt", "seccomp=unconfined", "-d", ALPINE, "top"})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @adrianreber, I was wondering what is the reason for seccomp=unconfined, is there a GitHub issue for it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rst0git : This is a RHEL7 - CRIU limitation. CRIU cannot handle seccomp with the RHEL7 kernel. I never really tried to understand why it does not work, but is does not work on the RHEL7 kernel. I was using RHEL7 as a development platform initially, that is why I worked around the seccomp limitations there. Not sure it is necessary to fix it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the explanation Adrian! I was curious because the seccomp support seems to work on Fedora.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged. locked - please file new issue/PR Assist humans wanting to comment on an old issue or PR with locked comments.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants