Commit 91a82fde authored by Saied Kazemi's avatar Saied Kazemi Committed by Pavel Emelyanov

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: 's avatarSaied Kazemi <saied@google.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 5c18267d
...@@ -26,6 +26,20 @@ set -o pipefail ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment