From 5267044f50a899a9664686c43419708afec1fc30 Mon Sep 17 00:00:00 2001 From: Norio Nomura Date: Mon, 22 Jul 2024 16:03:16 +0900 Subject: [PATCH 1/7] docker.yaml: add `.param.ContainerdImageStore` By passing the `--set .param.ContainerdImageStore=true` option to `limactl {create,start,edit}`, the `.features."containerd-snapshotter"` option will be enabled in `docker/daemon.json` inside the VM. Signed-off-by: Norio Nomura --- examples/docker.yaml | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/examples/docker.yaml b/examples/docker.yaml index 4f5e8fe562f..77b97ef0af5 100644 --- a/examples/docker.yaml +++ b/examples/docker.yaml @@ -48,14 +48,31 @@ provision: curl -fsSL https://get.docker.com | sh # NOTE: you may remove the lines below, if you prefer to use rootful docker, not rootless systemctl disable --now docker - apt-get install -y uidmap dbus-user-session + apt-get install -y dbus-user-session fuse3 jq uidmap - mode: user script: | #!/bin/bash set -eux -o pipefail systemctl --user start dbus - dockerd-rootless-setuptool.sh install + systemctl list-unit-files --user docker.service &>/dev/null || dockerd-rootless-setuptool.sh install docker context use rootless + + readonly config="$HOME/.config/docker/daemon.json" + needs_restart= + function set_docker_daemon_json() { + function cat_config() { test -s "$config" && cat "$config" || echo "{}" ; } + local -r current=$(cat_config | jq -r "$1 // empty") + [ "$current" = "$2" ] && return 0 + mkdir -p $(dirname "$config") && cat_config | jq "$1 = ${2:-empty}" | (sleep 0 && tee "$config") && needs_restart=1 + } + + # enable containerd image store + set_docker_daemon_json '.features."containerd-snapshotter"' "$( + [ "{{.Param.ContainerdImageStore}}" = "true" ] && echo 'true' + )" + + # restart docker to apply the new configuration + [ -z "$needs_restart" ] || systemctl --user restart docker probes: - script: | #!/bin/bash @@ -84,3 +101,5 @@ message: | docker context use lima-{{.Name}} docker run hello-world ------ +param: + ContainerdImageStore: false From 174e67a3a4aec40909a157b351d196b69caa6df6 Mon Sep 17 00:00:00 2001 From: Norio Nomura Date: Mon, 22 Jul 2024 16:35:59 +0900 Subject: [PATCH 2/7] docker.yaml: add `.param.Rootful` By passing the `--set .param.Rootful=true` option to `limactl {create,start,edit}`, Docker inside the VM will run in rootful mode. Signed-off-by: Norio Nomura --- examples/docker.yaml | 62 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/examples/docker.yaml b/examples/docker.yaml index 77b97ef0af5..c0b89b58997 100644 --- a/examples/docker.yaml +++ b/examples/docker.yaml @@ -44,26 +44,54 @@ provision: #!/bin/bash set -eux -o pipefail command -v docker >/dev/null 2>&1 && exit 0 + readonly override_conf=/etc/systemd/system/docker.socket.d/override.conf + if [ ! -e "$override_conf" ]; then + mkdir -p $(dirname "$override_conf") + # Alternatively we could just add the user to the "docker" group, but that requires restarting the user session + cat <"$override_conf" + [Socket] + SocketUser={{.User}} + EOF + fi export DEBIAN_FRONTEND=noninteractive curl -fsSL https://get.docker.com | sh - # NOTE: you may remove the lines below, if you prefer to use rootful docker, not rootless - systemctl disable --now docker - apt-get install -y dbus-user-session fuse3 jq uidmap -- mode: user +- mode: user # configure docker under non-root user script: | #!/bin/bash set -eux -o pipefail - systemctl --user start dbus - systemctl list-unit-files --user docker.service &>/dev/null || dockerd-rootless-setuptool.sh install - docker context use rootless + command -v jq &>/dev/null || sudo apt-get install -y jq + readonly rootless_installed=$(systemctl --user list-unit-files docker.service &>/dev/null && echo true || echo false) + + if [ "{{.Param.Rootful}}" = "true" ]; then + readonly config_dir="/etc/docker" + readonly systemctl="sudo systemctl" + readonly tee="sudo tee" + + [ "$rootless_installed" != "true" ] || systemctl --user disable --now docker + docker context use default + + else + readonly config_dir="$HOME/.config/docker" + readonly systemctl="systemctl --user" + readonly tee="tee" - readonly config="$HOME/.config/docker/daemon.json" + sudo systemctl disable --now docker.socket docker + if [ "$rootless_installed" != "true" ]; then + sudo apt-get install -y dbus-user-session fuse3 uidmap + $systemctl start dbus + dockerd-rootless-setuptool.sh install + fi + docker context use rootless + fi + $systemctl enable --now docker + + readonly config="$config_dir/daemon.json" needs_restart= function set_docker_daemon_json() { function cat_config() { test -s "$config" && cat "$config" || echo "{}" ; } local -r current=$(cat_config | jq -r "$1 // empty") [ "$current" = "$2" ] && return 0 - mkdir -p $(dirname "$config") && cat_config | jq "$1 = ${2:-empty}" | (sleep 0 && tee "$config") && needs_restart=1 + mkdir -p "$config_dir" && cat_config | jq "$1 = ${2:-empty}" | (sleep 0 && $tee "$config") && needs_restart=1 } # enable containerd image store @@ -72,7 +100,7 @@ provision: )" # restart docker to apply the new configuration - [ -z "$needs_restart" ] || systemctl --user restart docker + [ -z "$needs_restart" ] || $systemctl restart docker probes: - script: | #!/bin/bash @@ -81,8 +109,15 @@ probes: echo >&2 "docker is not installed yet" exit 1 fi - if ! timeout 30s bash -c "until pgrep rootlesskit; do sleep 3; done"; then - echo >&2 "rootlesskit (used by rootless docker) is not running" + if [ "{{.Param.Rootful}}" = "true" ]; then + target=dockerd + target_description="dockerd" + else + target=rootlesskit + target_description="rootlesskit (used by rootless docker)" + fi + if ! timeout 30s bash -c "until pgrep $target; do sleep 3; done"; then + echo >&2 "$target_description is not running" exit 1 fi hint: See "/var/log/cloud-init-output.log" in the guest @@ -92,7 +127,7 @@ hostResolver: hosts: host.docker.internal: host.lima.internal portForwards: -- guestSocket: "/run/user/{{.UID}}/docker.sock" +- guestSocket: "{{if eq .Param.Rootful \"true\"}}/var/run{{else}}/run/user/{{.UID}}{{end}}/docker.sock" hostSocket: "{{.Dir}}/sock/docker.sock" message: | To run `docker` on the host (assumes docker-cli is installed), run the following commands: @@ -103,3 +138,4 @@ message: | ------ param: ContainerdImageStore: false + Rootful: false From 2304e983bcb5ed3056da0dfe8c4188dd43fa3957 Mon Sep 17 00:00:00 2001 From: Norio Nomura Date: Mon, 22 Jul 2024 16:38:00 +0900 Subject: [PATCH 3/7] docker-rootful.yaml: make everything common except for setting `.param.Rootful=true` in `docker.yaml`. Signed-off-by: Norio Nomura --- examples/docker-rootful.yaml | 73 ++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 8 deletions(-) diff --git a/examples/docker-rootful.yaml b/examples/docker-rootful.yaml index 4ddd2c937d7..fba1171ebd8 100644 --- a/examples/docker-rootful.yaml +++ b/examples/docker-rootful.yaml @@ -44,16 +44,63 @@ provision: #!/bin/bash set -eux -o pipefail command -v docker >/dev/null 2>&1 && exit 0 - if [ ! -e /etc/systemd/system/docker.socket.d/override.conf ]; then - mkdir -p /etc/systemd/system/docker.socket.d + readonly override_conf=/etc/systemd/system/docker.socket.d/override.conf + if [ ! -e "$override_conf" ]; then + mkdir -p $(dirname "$override_conf") # Alternatively we could just add the user to the "docker" group, but that requires restarting the user session - cat <<-EOF >/etc/systemd/system/docker.socket.d/override.conf - [Socket] - SocketUser={{.User}} + cat <"$override_conf" + [Socket] + SocketUser={{.User}} EOF fi export DEBIAN_FRONTEND=noninteractive curl -fsSL https://get.docker.com | sh +- mode: user # configure docker under non-root user + script: | + #!/bin/bash + set -eux -o pipefail + command -v jq &>/dev/null || sudo apt-get install -y jq + readonly rootless_installed=$(systemctl --user list-unit-files docker.service &>/dev/null && echo true || echo false) + + if [ "{{.Param.Rootful}}" = "true" ]; then + readonly config_dir="/etc/docker" + readonly systemctl="sudo systemctl" + readonly tee="sudo tee" + + [ "$rootless_installed" != "true" ] || systemctl --user disable --now docker + docker context use default + + else + readonly config_dir="$HOME/.config/docker" + readonly systemctl="systemctl --user" + readonly tee="tee" + + sudo systemctl disable --now docker.socket docker + if [ "$rootless_installed" != "true" ]; then + sudo apt-get install -y dbus-user-session fuse3 uidmap + $systemctl start dbus + dockerd-rootless-setuptool.sh install + fi + docker context use rootless + fi + $systemctl enable --now docker + + readonly config="$config_dir/daemon.json" + needs_restart= + function set_docker_daemon_json() { + function cat_config() { test -s "$config" && cat "$config" || echo "{}" ; } + local -r current=$(cat_config | jq -r "$1 // empty") + [ "$current" = "$2" ] && return 0 + mkdir -p "$config_dir" && cat_config | jq "$1 = ${2:-empty}" | (sleep 0 && $tee "$config") && needs_restart=1 + } + + # enable containerd image store + set_docker_daemon_json '.features."containerd-snapshotter"' "$( + [ "{{.Param.ContainerdImageStore}}" = "true" ] && echo 'true' + )" + + # restart docker to apply the new configuration + [ -z "$needs_restart" ] || $systemctl restart docker probes: - script: | #!/bin/bash @@ -62,8 +109,15 @@ probes: echo >&2 "docker is not installed yet" exit 1 fi - if ! timeout 30s bash -c "until pgrep dockerd; do sleep 3; done"; then - echo >&2 "dockerd is not running" + if [ "{{.Param.Rootful}}" = "true" ]; then + target=dockerd + target_description="dockerd" + else + target=rootlesskit + target_description="rootlesskit (used by rootless docker)" + fi + if ! timeout 30s bash -c "until pgrep $target; do sleep 3; done"; then + echo >&2 "$target_description is not running" exit 1 fi hint: See "/var/log/cloud-init-output.log" in the guest @@ -73,7 +127,7 @@ hostResolver: hosts: host.docker.internal: host.lima.internal portForwards: -- guestSocket: "/var/run/docker.sock" +- guestSocket: "{{if eq .Param.Rootful \"true\"}}/var/run{{else}}/run/user/{{.UID}}{{end}}/docker.sock" hostSocket: "{{.Dir}}/sock/docker.sock" message: | To run `docker` on the host (assumes docker-cli is installed), run the following commands: @@ -82,3 +136,6 @@ message: | docker context use lima-{{.Name}} docker run hello-world ------ +param: + ContainerdImageStore: false + Rootful: true From 2dac1d95133cf6535e0df4b24a89a7afeb404e2d Mon Sep 17 00:00:00 2001 From: Norio Nomura Date: Mon, 22 Jul 2024 18:13:28 +0900 Subject: [PATCH 4/7] docker{,-rootful}.yaml: remove `/var/run/docker.sock` on installing rootless Signed-off-by: Norio Nomura --- examples/docker-rootful.yaml | 3 ++- examples/docker.yaml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/docker-rootful.yaml b/examples/docker-rootful.yaml index fba1171ebd8..5dcf8192bd0 100644 --- a/examples/docker-rootful.yaml +++ b/examples/docker-rootful.yaml @@ -75,10 +75,11 @@ provision: readonly systemctl="systemctl --user" readonly tee="tee" - sudo systemctl disable --now docker.socket docker + sudo systemctl disable --now docker if [ "$rootless_installed" != "true" ]; then sudo apt-get install -y dbus-user-session fuse3 uidmap $systemctl start dbus + [ ! -S /var/run/docker.sock ] || sudo rm /var/run/docker.sock dockerd-rootless-setuptool.sh install fi docker context use rootless diff --git a/examples/docker.yaml b/examples/docker.yaml index c0b89b58997..8a5d26728d1 100644 --- a/examples/docker.yaml +++ b/examples/docker.yaml @@ -75,10 +75,11 @@ provision: readonly systemctl="systemctl --user" readonly tee="tee" - sudo systemctl disable --now docker.socket docker + sudo systemctl disable --now docker if [ "$rootless_installed" != "true" ]; then sudo apt-get install -y dbus-user-session fuse3 uidmap $systemctl start dbus + [ ! -S /var/run/docker.sock ] || sudo rm /var/run/docker.sock dockerd-rootless-setuptool.sh install fi docker context use rootless From aaa9c33c63faf8e4b009946005b00665a4246a1c Mon Sep 17 00:00:00 2001 From: Norio Nomura Date: Tue, 23 Jul 2024 14:17:04 +0900 Subject: [PATCH 5/7] docker{,-rootful}.yaml: This template requires Lima v0.23.0 or later Signed-off-by: Norio Nomura --- examples/docker-rootful.yaml | 2 +- examples/docker.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/docker-rootful.yaml b/examples/docker-rootful.yaml index 5dcf8192bd0..00d05d1bfb3 100644 --- a/examples/docker-rootful.yaml +++ b/examples/docker-rootful.yaml @@ -6,7 +6,7 @@ # $ export DOCKER_HOST=$(limactl list docker-rootful --format 'unix://{{.Dir}}/sock/docker.sock') # $ docker ... -# This template requires Lima v0.20.0 or later +# This template requires Lima v0.23.0 or later images: # Try to use release-yyyyMMdd image if available. Note that release-yyyyMMdd will be removed after several months. - location: "https://cloud-images.ubuntu.com/releases/24.04/release-20240423/ubuntu-24.04-server-cloudimg-amd64.img" diff --git a/examples/docker.yaml b/examples/docker.yaml index 8a5d26728d1..2ccfff69ff9 100644 --- a/examples/docker.yaml +++ b/examples/docker.yaml @@ -6,7 +6,7 @@ # $ export DOCKER_HOST=$(limactl list docker --format 'unix://{{.Dir}}/sock/docker.sock') # $ docker ... -# This template requires Lima v0.8.0 or later +# This template requires Lima v0.23.0 or later images: # Try to use release-yyyyMMdd image if available. Note that release-yyyyMMdd will be removed after several months. - location: "https://cloud-images.ubuntu.com/releases/24.04/release-20240423/ubuntu-24.04-server-cloudimg-amd64.img" From cdb77320ea86c896c52bbbd69393a192331364b3 Mon Sep 17 00:00:00 2001 From: Norio Nomura Date: Thu, 25 Jul 2024 16:33:56 +0900 Subject: [PATCH 6/7] docker{,-rootful}.yaml: fix for yamllint Signed-off-by: Norio Nomura --- examples/docker-rootful.yaml | 2 +- examples/docker.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/docker-rootful.yaml b/examples/docker-rootful.yaml index 00d05d1bfb3..1950b8ec0cf 100644 --- a/examples/docker-rootful.yaml +++ b/examples/docker-rootful.yaml @@ -55,7 +55,7 @@ provision: fi export DEBIAN_FRONTEND=noninteractive curl -fsSL https://get.docker.com | sh -- mode: user # configure docker under non-root user +- mode: user # configure docker under non-root user script: | #!/bin/bash set -eux -o pipefail diff --git a/examples/docker.yaml b/examples/docker.yaml index 2ccfff69ff9..fd7f8d82527 100644 --- a/examples/docker.yaml +++ b/examples/docker.yaml @@ -55,7 +55,7 @@ provision: fi export DEBIAN_FRONTEND=noninteractive curl -fsSL https://get.docker.com | sh -- mode: user # configure docker under non-root user +- mode: user # configure docker under non-root user script: | #!/bin/bash set -eux -o pipefail From a72351303c403a6c3743191d06350986c009eedc Mon Sep 17 00:00:00 2001 From: Norio Nomura Date: Sun, 28 Jul 2024 20:05:30 +0900 Subject: [PATCH 7/7] docker{,-rootful}.yaml: apply reviews - Use `if then else fi` instead of `||` - Use long-from options - Omit double quotes during variable expansion where it is clear that spaces are not included - Use upper case on param variable names - Use wrapper functions instead variable expansion. e.g.(`systemctl_wrapper`) - Assign param variable to shell variable to making it easier to read cloud-init-output.log - Remove `systemctl --user start dbus` since it not required any more - Add some comments to describe the intentions that are difficult to infer from the code Signed-off-by: Norio Nomura --- examples/docker-rootful.yaml | 102 +++++++++++++++++++++++------------ examples/docker.yaml | 102 +++++++++++++++++++++++------------ 2 files changed, 134 insertions(+), 70 deletions(-) diff --git a/examples/docker-rootful.yaml b/examples/docker-rootful.yaml index 1950b8ec0cf..55263da3a91 100644 --- a/examples/docker-rootful.yaml +++ b/examples/docker-rootful.yaml @@ -45,10 +45,10 @@ provision: set -eux -o pipefail command -v docker >/dev/null 2>&1 && exit 0 readonly override_conf=/etc/systemd/system/docker.socket.d/override.conf - if [ ! -e "$override_conf" ]; then - mkdir -p $(dirname "$override_conf") + if [ ! -e $override_conf ]; then + mkdir -p $(dirname $override_conf) # Alternatively we could just add the user to the "docker" group, but that requires restarting the user session - cat <"$override_conf" + cat <$override_conf [Socket] SocketUser={{.User}} EOF @@ -58,50 +58,81 @@ provision: - mode: user # configure docker under non-root user script: | #!/bin/bash - set -eux -o pipefail - command -v jq &>/dev/null || sudo apt-get install -y jq - readonly rootless_installed=$(systemctl --user list-unit-files docker.service &>/dev/null && echo true || echo false) + set -o errexit -o nounset -o pipefail -o xtrace - if [ "{{.Param.Rootful}}" = "true" ]; then - readonly config_dir="/etc/docker" - readonly systemctl="sudo systemctl" - readonly tee="sudo tee" + if ! command -v jq &>/dev/null; then + sudo apt-get install --assume-yes jq + fi + if systemctl --user list-unit-files docker.service &>/dev/null; then + readonly rootless_installed=true + else + readonly rootless_installed=false + fi - [ "$rootless_installed" != "true" ] || systemctl --user disable --now docker - docker context use default + # Setting shell variable makes it easier to read cloud-init-output.log + readonly ROOTFUL="{{.Param.ROOTFUL}}" + if [ "$ROOTFUL" = true ]; then + if [ $rootless_installed = true ]; then + systemctl --user disable --now docker + fi + readonly config_dir=/etc/docker + readonly context=default + function systemctl_wrapper() { sudo systemctl "$@"; } + function tee_wrapper() { sudo tee "$@"; } else - readonly config_dir="$HOME/.config/docker" - readonly systemctl="systemctl --user" - readonly tee="tee" - sudo systemctl disable --now docker - if [ "$rootless_installed" != "true" ]; then - sudo apt-get install -y dbus-user-session fuse3 uidmap - $systemctl start dbus - [ ! -S /var/run/docker.sock ] || sudo rm /var/run/docker.sock + if [ $rootless_installed != true ]; then + sudo apt-get install --assume-yes dbus-user-session fuse3 uidmap + if [ -S /var/run/docker.sock ]; then + sudo rm /var/run/docker.sock + fi dockerd-rootless-setuptool.sh install fi - docker context use rootless + + readonly config_dir="$HOME/.config/docker" + readonly context=rootless + function systemctl_wrapper() { systemctl --user "$@"; } + function tee_wrapper() { tee "$@"; } fi - $systemctl enable --now docker + + systemctl_wrapper enable --now docker + docker context use $context readonly config="$config_dir/daemon.json" - needs_restart= + function print_config() { + if [ -s "$config" ]; then + cat "$config" + else + # print empty JSON object instead of empty string for jq to work + echo "{}" + fi + } + needs_restart=false function set_docker_daemon_json() { - function cat_config() { test -s "$config" && cat "$config" || echo "{}" ; } - local -r current=$(cat_config | jq -r "$1 // empty") + local -r current=$(print_config | jq --raw-output "$1 // empty") [ "$current" = "$2" ] && return 0 - mkdir -p "$config_dir" && cat_config | jq "$1 = ${2:-empty}" | (sleep 0 && $tee "$config") && needs_restart=1 + mkdir -p "$config_dir" + # sleep 0 is a trick to avoid tee_wrapper overwriting the file before reading it + if print_config | jq "$1 = ${2:-empty}" | (sleep 0 && tee_wrapper "$config"); then + needs_restart=true + fi } + # Setting shell variable makes it easier to read cloud-init-output.log + readonly CONTAINERD_IMAGE_STORE="{{.Param.CONTAINERD_IMAGE_STORE}}" # enable containerd image store - set_docker_daemon_json '.features."containerd-snapshotter"' "$( - [ "{{.Param.ContainerdImageStore}}" = "true" ] && echo 'true' - )" + if [ "$CONTAINERD_IMAGE_STORE" = true ]; then + set_docker_daemon_json '.features."containerd-snapshotter"' 'true' + else + # passing empty string to remove the key and use the default value + set_docker_daemon_json '.features."containerd-snapshotter"' '' + fi # restart docker to apply the new configuration - [ -z "$needs_restart" ] || $systemctl restart docker + if [ $needs_restart = true ]; then + systemctl_wrapper restart docker + fi probes: - script: | #!/bin/bash @@ -110,9 +141,10 @@ probes: echo >&2 "docker is not installed yet" exit 1 fi - if [ "{{.Param.Rootful}}" = "true" ]; then + readonly ROOTFUL="{{.Param.ROOTFUL}}" + if [ "$ROOTFUL" = true ]; then target=dockerd - target_description="dockerd" + target_description=dockerd else target=rootlesskit target_description="rootlesskit (used by rootless docker)" @@ -128,7 +160,7 @@ hostResolver: hosts: host.docker.internal: host.lima.internal portForwards: -- guestSocket: "{{if eq .Param.Rootful \"true\"}}/var/run{{else}}/run/user/{{.UID}}{{end}}/docker.sock" +- guestSocket: "{{if eq .Param.ROOTFUL \"true\"}}/var/run{{else}}/run/user/{{.UID}}{{end}}/docker.sock" hostSocket: "{{.Dir}}/sock/docker.sock" message: | To run `docker` on the host (assumes docker-cli is installed), run the following commands: @@ -138,5 +170,5 @@ message: | docker run hello-world ------ param: - ContainerdImageStore: false - Rootful: true + CONTAINERD_IMAGE_STORE: false + ROOTFUL: true diff --git a/examples/docker.yaml b/examples/docker.yaml index fd7f8d82527..430c34bda66 100644 --- a/examples/docker.yaml +++ b/examples/docker.yaml @@ -45,10 +45,10 @@ provision: set -eux -o pipefail command -v docker >/dev/null 2>&1 && exit 0 readonly override_conf=/etc/systemd/system/docker.socket.d/override.conf - if [ ! -e "$override_conf" ]; then - mkdir -p $(dirname "$override_conf") + if [ ! -e $override_conf ]; then + mkdir -p $(dirname $override_conf) # Alternatively we could just add the user to the "docker" group, but that requires restarting the user session - cat <"$override_conf" + cat <$override_conf [Socket] SocketUser={{.User}} EOF @@ -58,50 +58,81 @@ provision: - mode: user # configure docker under non-root user script: | #!/bin/bash - set -eux -o pipefail - command -v jq &>/dev/null || sudo apt-get install -y jq - readonly rootless_installed=$(systemctl --user list-unit-files docker.service &>/dev/null && echo true || echo false) + set -o errexit -o nounset -o pipefail -o xtrace - if [ "{{.Param.Rootful}}" = "true" ]; then - readonly config_dir="/etc/docker" - readonly systemctl="sudo systemctl" - readonly tee="sudo tee" + if ! command -v jq &>/dev/null; then + sudo apt-get install --assume-yes jq + fi + if systemctl --user list-unit-files docker.service &>/dev/null; then + readonly rootless_installed=true + else + readonly rootless_installed=false + fi - [ "$rootless_installed" != "true" ] || systemctl --user disable --now docker - docker context use default + # Setting shell variable makes it easier to read cloud-init-output.log + readonly ROOTFUL="{{.Param.ROOTFUL}}" + if [ "$ROOTFUL" = true ]; then + if [ $rootless_installed = true ]; then + systemctl --user disable --now docker + fi + readonly config_dir=/etc/docker + readonly context=default + function systemctl_wrapper() { sudo systemctl "$@"; } + function tee_wrapper() { sudo tee "$@"; } else - readonly config_dir="$HOME/.config/docker" - readonly systemctl="systemctl --user" - readonly tee="tee" - sudo systemctl disable --now docker - if [ "$rootless_installed" != "true" ]; then - sudo apt-get install -y dbus-user-session fuse3 uidmap - $systemctl start dbus - [ ! -S /var/run/docker.sock ] || sudo rm /var/run/docker.sock + if [ $rootless_installed != true ]; then + sudo apt-get install --assume-yes dbus-user-session fuse3 uidmap + if [ -S /var/run/docker.sock ]; then + sudo rm /var/run/docker.sock + fi dockerd-rootless-setuptool.sh install fi - docker context use rootless + + readonly config_dir="$HOME/.config/docker" + readonly context=rootless + function systemctl_wrapper() { systemctl --user "$@"; } + function tee_wrapper() { tee "$@"; } fi - $systemctl enable --now docker + + systemctl_wrapper enable --now docker + docker context use $context readonly config="$config_dir/daemon.json" - needs_restart= + function print_config() { + if [ -s "$config" ]; then + cat "$config" + else + # print empty JSON object instead of empty string for jq to work + echo "{}" + fi + } + needs_restart=false function set_docker_daemon_json() { - function cat_config() { test -s "$config" && cat "$config" || echo "{}" ; } - local -r current=$(cat_config | jq -r "$1 // empty") + local -r current=$(print_config | jq --raw-output "$1 // empty") [ "$current" = "$2" ] && return 0 - mkdir -p "$config_dir" && cat_config | jq "$1 = ${2:-empty}" | (sleep 0 && $tee "$config") && needs_restart=1 + mkdir -p "$config_dir" + # sleep 0 is a trick to avoid tee_wrapper overwriting the file before reading it + if print_config | jq "$1 = ${2:-empty}" | (sleep 0 && tee_wrapper "$config"); then + needs_restart=true + fi } + # Setting shell variable makes it easier to read cloud-init-output.log + readonly CONTAINERD_IMAGE_STORE="{{.Param.CONTAINERD_IMAGE_STORE}}" # enable containerd image store - set_docker_daemon_json '.features."containerd-snapshotter"' "$( - [ "{{.Param.ContainerdImageStore}}" = "true" ] && echo 'true' - )" + if [ "$CONTAINERD_IMAGE_STORE" = true ]; then + set_docker_daemon_json '.features."containerd-snapshotter"' 'true' + else + # passing empty string to remove the key and use the default value + set_docker_daemon_json '.features."containerd-snapshotter"' '' + fi # restart docker to apply the new configuration - [ -z "$needs_restart" ] || $systemctl restart docker + if [ $needs_restart = true ]; then + systemctl_wrapper restart docker + fi probes: - script: | #!/bin/bash @@ -110,9 +141,10 @@ probes: echo >&2 "docker is not installed yet" exit 1 fi - if [ "{{.Param.Rootful}}" = "true" ]; then + readonly ROOTFUL="{{.Param.ROOTFUL}}" + if [ "$ROOTFUL" = true ]; then target=dockerd - target_description="dockerd" + target_description=dockerd else target=rootlesskit target_description="rootlesskit (used by rootless docker)" @@ -128,7 +160,7 @@ hostResolver: hosts: host.docker.internal: host.lima.internal portForwards: -- guestSocket: "{{if eq .Param.Rootful \"true\"}}/var/run{{else}}/run/user/{{.UID}}{{end}}/docker.sock" +- guestSocket: "{{if eq .Param.ROOTFUL \"true\"}}/var/run{{else}}/run/user/{{.UID}}{{end}}/docker.sock" hostSocket: "{{.Dir}}/sock/docker.sock" message: | To run `docker` on the host (assumes docker-cli is installed), run the following commands: @@ -138,5 +170,5 @@ message: | docker run hello-world ------ param: - ContainerdImageStore: false - Rootful: false + CONTAINERD_IMAGE_STORE: false + ROOTFUL: false