mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-22 09:58:09 +00:00
Add OverlayFS support to docker_cr.sh
The main purpose of this patch is to add OverlayFS support to docker_cr.sh for external checkpoint and restore. It also does a bit of cleaning and minor enhancements. Signed-off-by: Saied Kazemi <saied@google.com> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
parent
5c18267ddf
commit
91a82fde71
@ -26,6 +26,20 @@ set -o pipefail
|
|||||||
: ${CRIU_BINARY=criu}
|
: ${CRIU_BINARY=criu}
|
||||||
: ${DOCKERINIT_BINARY=}
|
: ${DOCKERINIT_BINARY=}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Patterns for different filesystem types in dump.log.
|
||||||
|
#
|
||||||
|
readonly AUFS_PATTERN='/sys/fs/aufs/si_'
|
||||||
|
readonly OVERLAYFS_PATTERN='type.*source.*options.*lowerdir=.*upperdir=.*workdir='
|
||||||
|
readonly UNIONFS_PATTERN='type.*source.*options.*dirs='
|
||||||
|
|
||||||
|
#
|
||||||
|
# These globals will be set by init_container_vars()
|
||||||
|
#
|
||||||
|
declare CID
|
||||||
|
declare CONTAINER_IMG_DIR
|
||||||
|
declare CONTAINER_DUMP_LOG
|
||||||
|
|
||||||
declare -A BIND_MOUNT
|
declare -A BIND_MOUNT
|
||||||
BIND_MOUNT[/etc/resolv.conf]=.ResolvConfPath
|
BIND_MOUNT[/etc/resolv.conf]=.ResolvConfPath
|
||||||
BIND_MOUNT[/etc/hosts]=.HostsPath
|
BIND_MOUNT[/etc/hosts]=.HostsPath
|
||||||
@ -149,10 +163,17 @@ init_container_vars() {
|
|||||||
d=$("${DOCKER_BINARY}" info 2> /dev/null | awk '/Storage Driver:/ { print $3 }')
|
d=$("${DOCKER_BINARY}" info 2> /dev/null | awk '/Storage Driver:/ { print $3 }')
|
||||||
if [[ "${d}" == "vfs" ]]; then
|
if [[ "${d}" == "vfs" ]]; then
|
||||||
CONTAINER_ROOT_DIR="${DOCKER_HOME}/${d}/dir/${CID}"
|
CONTAINER_ROOT_DIR="${DOCKER_HOME}/${d}/dir/${CID}"
|
||||||
else
|
elif [[ "${d}" == "aufs" || "${d}" == "unionfs" ]]; then
|
||||||
CONTAINER_ROOT_DIR="${DOCKER_HOME}/${d}/mnt/${CID}"
|
CONTAINER_ROOT_DIR="${DOCKER_HOME}/${d}/mnt/${CID}"
|
||||||
|
elif [[ "${d}" == "overlay" ]]; then
|
||||||
|
CONTAINER_ROOT_DIR="${DOCKER_HOME}/${d}/${CID}/merged"
|
||||||
|
else
|
||||||
|
echo "${d}: unknown filesystem type"
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
CONTAINER_IMG_DIR="${CRIU_IMG_DIR}/${CID}"
|
CONTAINER_IMG_DIR="${CRIU_IMG_DIR}/${CID}"
|
||||||
|
CONTAINER_DUMP_LOG="${CONTAINER_IMG_DIR}/dump.log"
|
||||||
}
|
}
|
||||||
|
|
||||||
get_container_conf() {
|
get_container_conf() {
|
||||||
@ -182,19 +203,23 @@ setup_mount_map() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fs_mounted() {
|
fs_mounted() {
|
||||||
grep -wq "$1" /proc/mounts
|
if grep -wq "$1" /proc/self/mountinfo; then
|
||||||
|
${ECHO} "container root directory already mounted"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
${ECHO} "container root directory not mounted"
|
||||||
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Pretty print the mount command in verbose mode by putting each branch
|
# Pretty print the mount command in verbose mode by putting each branch
|
||||||
# pathname on a single line for easier visual inspection.
|
# pathname on a single line for easier visual inspection.
|
||||||
#
|
#
|
||||||
pp_mount() {
|
pp_mount() {
|
||||||
${ECHO} -e "\nmount -t $1 -o"
|
${ECHO} -e "\nmount -t $1 -o"
|
||||||
${ECHO} "${2}" | tr ':' '\n'
|
${ECHO} "${2}" | tr ':,' '\n'
|
||||||
${ECHO} none
|
|
||||||
${ECHO} "${3}"
|
${ECHO} "${3}"
|
||||||
|
${ECHO} "${4}"
|
||||||
}
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -209,19 +234,18 @@ pp_mount() {
|
|||||||
# safe for typical Docker containers.
|
# safe for typical Docker containers.
|
||||||
#
|
#
|
||||||
setup_aufs() {
|
setup_aufs() {
|
||||||
local logf="${CONTAINER_IMG_DIR}/dump.log"
|
local -r tmpf="${CONTAINER_IMG_DIR}/aufs.br"
|
||||||
local tmpf="${CONTAINER_IMG_DIR}/aufs.br"
|
|
||||||
local br
|
local br
|
||||||
local branches
|
local branches
|
||||||
|
|
||||||
# create a temporary file with branches listed in
|
|
||||||
# ascending order (line 1 is branch 0)
|
|
||||||
awk '/aufs.si_/ { print $2, $4 }' "${logf}" | sort | uniq | \
|
|
||||||
awk '{ print $2 }' > "${tmpf}"
|
|
||||||
|
|
||||||
# nothing to do if filesystem already mounted
|
# nothing to do if filesystem already mounted
|
||||||
fs_mounted "${CONTAINER_ROOT_DIR}" && return
|
fs_mounted "${CONTAINER_ROOT_DIR}" && return
|
||||||
|
|
||||||
|
# create a temporary file with branches listed in
|
||||||
|
# ascending order (line 1 is branch 0)
|
||||||
|
awk '/aufs.si_/ { print $2, $4 }' "${CONTAINER_DUMP_LOG}" | \
|
||||||
|
sort | uniq | awk '{ print $2 }' > "${tmpf}"
|
||||||
|
|
||||||
# construct the mount option string from branches
|
# construct the mount option string from branches
|
||||||
branches=""
|
branches=""
|
||||||
while read br; do
|
while read br; do
|
||||||
@ -229,11 +253,31 @@ setup_aufs() {
|
|||||||
done < "${tmpf}"
|
done < "${tmpf}"
|
||||||
|
|
||||||
# mount the container's filesystem
|
# mount the container's filesystem
|
||||||
pp_mount "aufs" "${branches}" "${CONTAINER_ROOT_DIR}"
|
pp_mount "aufs" "${branches}" "none" "${CONTAINER_ROOT_DIR}"
|
||||||
mount -t aufs -o br="${branches}" none "${CONTAINER_ROOT_DIR}"
|
mount -t aufs -o br="${branches}" none "${CONTAINER_ROOT_DIR}"
|
||||||
rm -f "${tmpf}"
|
rm -f "${tmpf}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setup_overlayfs() {
|
||||||
|
local lowerdir
|
||||||
|
local upperdir
|
||||||
|
local workdir
|
||||||
|
local ovlydirs
|
||||||
|
local -r f="${CONTAINER_DUMP_LOG}"
|
||||||
|
|
||||||
|
# nothing to do if filesystem already mounted
|
||||||
|
fs_mounted "${CONTAINER_ROOT_DIR}" && return
|
||||||
|
|
||||||
|
lowerdir=$(grep "${OVERLAYFS_PATTERN}" "${f}" | sed -n -e 's/.*lowerdir=\([^,]*\).*/\1/p')
|
||||||
|
upperdir=$(grep "${OVERLAYFS_PATTERN}" "${f}" | sed -n -e 's/.*upperdir=\([^,]*\).*/\1/p')
|
||||||
|
workdir=$(grep "${OVERLAYFS_PATTERN}" "${f}" | sed -n -e 's/.*workdir=\([^,]*\).*/\1/p')
|
||||||
|
ovlydirs="lowerdir=${lowerdir},upperdir=${upperdir},workdir=${workdir}"
|
||||||
|
|
||||||
|
# mount the container's filesystem
|
||||||
|
pp_mount "overlay" "${ovlydirs}" "overlay" "${CONTAINER_ROOT_DIR}"
|
||||||
|
mount -t overlay -o "${ovlydirs}" overlay "${CONTAINER_ROOT_DIR}"
|
||||||
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
# Reconstruct the UnionFS filesystem from information in CRIU's dump log.
|
# Reconstruct the UnionFS filesystem from information in CRIU's dump log.
|
||||||
# The dump log has the mountinfo root entry for the filesystem. The
|
# The dump log has the mountinfo root entry for the filesystem. The
|
||||||
@ -250,17 +294,16 @@ setup_aufs() {
|
|||||||
# device file by mknod.
|
# device file by mknod.
|
||||||
#
|
#
|
||||||
setup_unionfs() {
|
setup_unionfs() {
|
||||||
local logf="${CONTAINER_IMG_DIR}/dump.log"
|
|
||||||
local dirs
|
local dirs
|
||||||
|
|
||||||
# nothing to do if filesystem already mounted
|
# nothing to do if filesystem already mounted
|
||||||
fs_mounted "${CONTAINER_ROOT_DIR}" && return
|
fs_mounted "${CONTAINER_ROOT_DIR}" && return
|
||||||
|
|
||||||
dirs=$(sed -n -e 's/.*type.*dirs=/dirs=/p' "${logf}")
|
dirs=$(sed -n -e 's/.*type.*dirs=/dirs=/p' "${CONTAINER_DUMP_LOG}")
|
||||||
[[ "${dirs}" = "" ]] && echo "do not have branch information" && exit 1
|
[[ "${dirs}" = "" ]] && echo "do not have branch information" && exit 1
|
||||||
|
|
||||||
# mount the container's filesystem
|
# mount the container's filesystem
|
||||||
pp_mount "unionfs" "${dirs}" "${CONTAINER_ROOT_DIR}"
|
pp_mount "unionfs" "${dirs}" "none" "${CONTAINER_ROOT_DIR}"
|
||||||
mount -t unionfs -o "${dirs}" none "${CONTAINER_ROOT_DIR}"
|
mount -t unionfs -o "${dirs}" none "${CONTAINER_ROOT_DIR}"
|
||||||
|
|
||||||
# see comment at the beginning of the function
|
# see comment at the beginning of the function
|
||||||
@ -277,6 +320,7 @@ prep_dump() {
|
|||||||
# docker returns 0 for containers it thinks have exited
|
# docker returns 0 for containers it thinks have exited
|
||||||
# (i.e., dumping a restored container again)
|
# (i.e., dumping a restored container again)
|
||||||
if [[ ${pid} -eq 0 ]]; then
|
if [[ ${pid} -eq 0 ]]; then
|
||||||
|
echo -e "\nCheckpointing a restored container?"
|
||||||
read -p "Process ID: " pid
|
read -p "Process ID: " pid
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -293,19 +337,27 @@ prep_dump() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Set up container's root filesystem if not already set up.
|
||||||
|
#
|
||||||
prep_restore() {
|
prep_restore() {
|
||||||
local aufs_pattern='/sys/fs/aufs/si_'
|
local -r f="${CONTAINER_DUMP_LOG}"
|
||||||
local unionfs_pattern='type.*source.*options.*dirs='
|
|
||||||
|
|
||||||
# set up aufs and unionfs mounts if they're not already set up
|
if [[ ! -f "${f}" ]]; then
|
||||||
if grep -q "${aufs_pattern}" "${CONTAINER_IMG_DIR}/dump.log"; then
|
echo "${f} does not exist"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if grep -q "${AUFS_PATTERN}" "${f}"; then
|
||||||
setup_aufs
|
setup_aufs
|
||||||
elif grep -q "${unionfs_pattern}" "${CONTAINER_IMG_DIR}/dump.log"; then
|
elif grep -q "${OVERLAYFS_PATTERN}" "${f}"; then
|
||||||
|
setup_overlayfs
|
||||||
|
elif grep -q "${UNIONFS_PATTERN}" "${f}"; then
|
||||||
setup_unionfs
|
setup_unionfs
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# criu requires this (due to container using pivot_root)
|
# criu requires this (due to container using pivot_root)
|
||||||
if ! grep -q "${CONTAINER_ROOT_DIR}" /proc/mounts; then
|
if ! grep -qw "${CONTAINER_ROOT_DIR}" /proc/self/mountinfo; then
|
||||||
execute mount --rbind "${CONTAINER_ROOT_DIR}" "${CONTAINER_ROOT_DIR}"
|
execute mount --rbind "${CONTAINER_ROOT_DIR}" "${CONTAINER_ROOT_DIR}"
|
||||||
MOUNTED=1
|
MOUNTED=1
|
||||||
else
|
else
|
||||||
@ -334,8 +386,8 @@ run_criu() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wrap_up() {
|
wrap_up() {
|
||||||
local logf="${CONTAINER_IMG_DIR}/${CMD}.log"
|
local -r logf="${CONTAINER_IMG_DIR}/${CMD}.log"
|
||||||
local pidf="${CONTAINER_IMG_DIR}/restore.pid"
|
local -r pidf="${CONTAINER_IMG_DIR}/restore.pid"
|
||||||
|
|
||||||
if [[ $1 -eq 0 ]]; then
|
if [[ $1 -eq 0 ]]; then
|
||||||
${ECHO} -e "\n"
|
${ECHO} -e "\n"
|
||||||
@ -362,18 +414,43 @@ wrap_up() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolve_path() {
|
||||||
|
local p
|
||||||
|
|
||||||
|
p="${2}"
|
||||||
|
if which realpath > /dev/null; then
|
||||||
|
p=$(realpath "${p}")
|
||||||
|
fi
|
||||||
|
${ECHO} "${1}: ${p}"
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_cmd() {
|
||||||
|
local cpath
|
||||||
|
|
||||||
|
cpath=$(which "${2}")
|
||||||
|
resolve_path "${1}" "${cpath}"
|
||||||
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
local rv=0
|
local rv=0
|
||||||
|
|
||||||
|
if [[ $(id -u) -ne 0 ]]; then
|
||||||
|
echo "not running as root"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
parse_args "$@"
|
parse_args "$@"
|
||||||
find_dockerinit
|
find_dockerinit
|
||||||
init_container_vars
|
init_container_vars
|
||||||
|
|
||||||
${ECHO} "docker binary: ${DOCKER_BINARY}"
|
if [[ "${VERBOSE}" == "-v" ]]; then
|
||||||
${ECHO} "dockerinit binary: ${DOCKERINIT_BINARY}"
|
echo
|
||||||
${ECHO} "criu binary: ${CRIU_BINARY}"
|
resolve_cmd "docker binary" "${DOCKER_BINARY}"
|
||||||
${ECHO} "image directory: ${CONTAINER_IMG_DIR}"
|
resolve_cmd "dockerinit binary" "${DOCKERINIT_BINARY}"
|
||||||
${ECHO} "container root directory: ${CONTAINER_ROOT_DIR}"
|
resolve_cmd "criu binary" "${CRIU_BINARY}"
|
||||||
|
resolve_path "image directory" "${CONTAINER_IMG_DIR}"
|
||||||
|
resolve_path "container root directory" "${CONTAINER_ROOT_DIR}"
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ "${CMD}" == "dump" ]]; then
|
if [[ "${CMD}" == "dump" ]]; then
|
||||||
prep_dump
|
prep_dump
|
||||||
|
Loading…
x
Reference in New Issue
Block a user