[CRIU] [PATCH] Add OverlayFS support to docker_cr.sh

Saied Kazemi saied at google.com
Mon Aug 17 13:40:38 PDT 2015


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 at google.com>
---
 contrib/docker_cr.sh | 135 ++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 106 insertions(+), 29 deletions(-)

diff --git a/contrib/docker_cr.sh b/contrib/docker_cr.sh
index 1adb577..1a8b203 100755
--- a/contrib/docker_cr.sh
+++ b/contrib/docker_cr.sh
@@ -26,6 +26,20 @@ set -o pipefail
 : ${CRIU_BINARY=criu}
 : ${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
 BIND_MOUNT[/etc/resolv.conf]=.ResolvConfPath
 BIND_MOUNT[/etc/hosts]=.HostsPath
@@ -149,10 +163,17 @@ init_container_vars() {
 	d=$("${DOCKER_BINARY}" info 2> /dev/null | awk '/Storage Driver:/ { print $3 }')
 	if [[ "${d}" == "vfs" ]]; then
 		CONTAINER_ROOT_DIR="${DOCKER_HOME}/${d}/dir/${CID}"
-	else
+	elif [[ "${d}" == "aufs" || "${d}" == "unionfs" ]]; then
 		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
+
 	CONTAINER_IMG_DIR="${CRIU_IMG_DIR}/${CID}"
+	CONTAINER_DUMP_LOG="${CONTAINER_IMG_DIR}/dump.log"
 }
 
 get_container_conf() {
@@ -182,19 +203,23 @@ setup_mount_map() {
 }
 
 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
 # pathname on a single line for easier visual inspection.
 #
 pp_mount() {
 	${ECHO} -e "\nmount -t $1 -o"
-	${ECHO} "${2}" | tr ':' '\n'
-	${ECHO} none
+	${ECHO} "${2}" | tr ':,' '\n'
 	${ECHO} "${3}"
+	${ECHO} "${4}"
 }
 
 #
@@ -209,19 +234,18 @@ pp_mount() {
 # safe for typical Docker containers.
 #
 setup_aufs() {
-	local logf="${CONTAINER_IMG_DIR}/dump.log"
-	local tmpf="${CONTAINER_IMG_DIR}/aufs.br"
+	local -r tmpf="${CONTAINER_IMG_DIR}/aufs.br"
 	local br
 	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
 	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
 	branches=""
 	while read br; do
@@ -229,11 +253,31 @@ setup_aufs() {
 	done < "${tmpf}"
 
 	# 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}"
 	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.
 # The dump log has the mountinfo root entry for the filesystem.  The
@@ -250,17 +294,16 @@ setup_aufs() {
 #     device file by mknod.
 #
 setup_unionfs() {
-	local logf="${CONTAINER_IMG_DIR}/dump.log"
 	local dirs
 
 	# nothing to do if filesystem already mounted
 	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
 
 	# 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}"
 
 	# see comment at the beginning of the function
@@ -277,6 +320,7 @@ prep_dump() {
 	# docker returns 0 for containers it thinks have exited
 	# (i.e., dumping a restored container again)
 	if [[ ${pid} -eq 0 ]]; then
+		echo -e "\nCheckpointing a restored container?"
 		read -p "Process ID: " pid
 	fi
 
@@ -293,19 +337,27 @@ prep_dump() {
 	fi
 }
 
+#
+# Set up container's root filesystem if not already set up.
+#
 prep_restore() {
-	local aufs_pattern='/sys/fs/aufs/si_'
-	local unionfs_pattern='type.*source.*options.*dirs='
+	local -r f="${CONTAINER_DUMP_LOG}"
 
-	# set up aufs and unionfs mounts if they're not already set up
-	if grep -q "${aufs_pattern}" "${CONTAINER_IMG_DIR}/dump.log"; then
+	if [[ ! -f "${f}" ]]; then
+		echo "${f} does not exist"
+		return 1
+	fi
+
+	if grep -q "${AUFS_PATTERN}" "${f}"; then
 		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
 	fi
 
 	# 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}"
 		MOUNTED=1
 	else
@@ -334,8 +386,8 @@ run_criu() {
 }
 
 wrap_up() {
-	local logf="${CONTAINER_IMG_DIR}/${CMD}.log"
-	local pidf="${CONTAINER_IMG_DIR}/restore.pid"
+	local -r logf="${CONTAINER_IMG_DIR}/${CMD}.log"
+	local -r pidf="${CONTAINER_IMG_DIR}/restore.pid"
 
 	if [[ $1 -eq 0 ]]; then
 		${ECHO} -e "\n"
@@ -362,18 +414,43 @@ wrap_up() {
 	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() {
 	local rv=0
 
+	if [[ $(id -u) -ne 0 ]]; then
+		echo "not running as root"
+		exit 1
+	fi
+
 	parse_args "$@"
 	find_dockerinit
 	init_container_vars
 
-	${ECHO} "docker binary: ${DOCKER_BINARY}"
-	${ECHO} "dockerinit binary: ${DOCKERINIT_BINARY}"
-	${ECHO} "criu binary: ${CRIU_BINARY}"
-	${ECHO} "image directory: ${CONTAINER_IMG_DIR}"
-	${ECHO} "container root directory: ${CONTAINER_ROOT_DIR}"
+	if [[ "${VERBOSE}" == "-v" ]]; then
+		echo
+		resolve_cmd "docker binary" "${DOCKER_BINARY}"
+		resolve_cmd "dockerinit binary" "${DOCKERINIT_BINARY}"
+		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
 		prep_dump
-- 
2.5.0.276.gf5e568e



More information about the CRIU mailing list