github.com/wozhu6104/docker@v20.10.10+incompatible/contrib/dockerd-rootless-setuptool.sh (about) 1 #!/bin/sh 2 # dockerd-rootless-setuptool.sh: setup tool for dockerd-rootless.sh 3 # Needs to be executed as a non-root user. 4 # 5 # Typical usage: dockerd-rootless-setuptool.sh install --force 6 # 7 # Documentation: https://docs.docker.com/go/rootless/ 8 set -eu 9 10 # utility functions 11 INFO() { 12 /bin/echo -e "\e[104m\e[97m[INFO]\e[49m\e[39m $@" 13 } 14 15 WARNING() { 16 /bin/echo >&2 -e "\e[101m\e[97m[WARNING]\e[49m\e[39m $@" 17 } 18 19 ERROR() { 20 /bin/echo >&2 -e "\e[101m\e[97m[ERROR]\e[49m\e[39m $@" 21 } 22 23 # constants 24 DOCKERD_ROOTLESS_SH="dockerd-rootless.sh" 25 SYSTEMD_UNIT="docker.service" 26 CLI_CONTEXT="rootless" 27 28 # CLI opt: --force 29 OPT_FORCE="" 30 # CLI opt: --skip-iptables 31 OPT_SKIP_IPTABLES="" 32 33 # global vars 34 ARG0="$0" 35 DOCKERD_ROOTLESS_SH_FLAGS="" 36 BIN="" 37 SYSTEMD="" 38 CFG_DIR="" 39 XDG_RUNTIME_DIR_CREATED="" 40 41 # run checks and also initialize global vars 42 init() { 43 # OS verification: Linux only 44 case "$(uname)" in 45 Linux) ;; 46 47 *) 48 ERROR "Rootless Docker cannot be installed on $(uname)" 49 exit 1 50 ;; 51 esac 52 53 # User verification: deny running as root 54 if [ "$(id -u)" = "0" ]; then 55 ERROR "Refusing to install rootless Docker as the root user" 56 exit 1 57 fi 58 59 # set BIN 60 if ! BIN="$(command -v "$DOCKERD_ROOTLESS_SH" 2> /dev/null)"; then 61 ERROR "$DOCKERD_ROOTLESS_SH needs to be present under \$PATH" 62 exit 1 63 fi 64 BIN=$(dirname "$BIN") 65 66 # set SYSTEMD 67 if systemctl --user show-environment > /dev/null 2>&1; then 68 SYSTEMD=1 69 fi 70 71 # HOME verification 72 if [ -z "${HOME:-}" ] || [ ! -d "$HOME" ]; then 73 ERROR "HOME needs to be set" 74 exit 1 75 fi 76 if [ ! -w "$HOME" ]; then 77 ERROR "HOME needs to be writable" 78 exit 1 79 fi 80 81 # set CFG_DIR 82 CFG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}" 83 84 # Existing rootful docker verification 85 if [ -w /var/run/docker.sock ] && [ -z "$OPT_FORCE" ]; then 86 ERROR "Aborting because rootful Docker (/var/run/docker.sock) is running and accessible. Set --force to ignore." 87 exit 1 88 fi 89 90 # Validate XDG_RUNTIME_DIR and set XDG_RUNTIME_DIR_CREATED 91 if [ -z "${XDG_RUNTIME_DIR:-}" ] || [ ! -w "$XDG_RUNTIME_DIR" ]; then 92 if [ -n "$SYSTEMD" ]; then 93 ERROR "Aborting because systemd was detected but XDG_RUNTIME_DIR (\"$XDG_RUNTIME_DIR\") is not set, does not exist, or is not writable" 94 ERROR "Hint: this could happen if you changed users with 'su' or 'sudo'. To work around this:" 95 ERROR "- try again by first running with root privileges 'loginctl enable-linger <user>' where <user> is the unprivileged user and export XDG_RUNTIME_DIR to the value of RuntimePath as shown by 'loginctl show-user <user>'" 96 ERROR "- or simply log back in as the desired unprivileged user (ssh works for remote machines, machinectl shell works for local machines)" 97 exit 1 98 fi 99 export XDG_RUNTIME_DIR="$HOME/.docker/run" 100 mkdir -p -m 700 "$XDG_RUNTIME_DIR" 101 XDG_RUNTIME_DIR_CREATED=1 102 fi 103 104 instructions="" 105 # instruction: uidmap dependency check 106 if ! command -v newuidmap > /dev/null 2>&1; then 107 if command -v apt-get > /dev/null 2>&1; then 108 instructions=$( 109 cat <<- EOI 110 ${instructions} 111 # Install newuidmap & newgidmap binaries 112 apt-get install -y uidmap 113 EOI 114 ) 115 elif command -v dnf > /dev/null 2>&1; then 116 instructions=$( 117 cat <<- EOI 118 ${instructions} 119 # Install newuidmap & newgidmap binaries 120 dnf install -y shadow-utils 121 EOI 122 ) 123 elif command -v yum > /dev/null 2>&1; then 124 instructions=$( 125 cat <<- EOI 126 ${instructions} 127 # Install newuidmap & newgidmap binaries 128 yum install -y shadow-utils 129 EOI 130 ) 131 else 132 ERROR "newuidmap binary not found. Please install with a package manager." 133 exit 1 134 fi 135 fi 136 137 # instruction: iptables dependency check 138 faced_iptables_error="" 139 if ! command -v iptables > /dev/null 2>&1 && [ ! -f /sbin/iptables ] && [ ! -f /usr/sbin/iptables ]; then 140 faced_iptables_error=1 141 if [ -z "$OPT_SKIP_IPTABLES" ]; then 142 if command -v apt-get > /dev/null 2>&1; then 143 instructions=$( 144 cat <<- EOI 145 ${instructions} 146 # Install iptables 147 apt-get install -y iptables 148 EOI 149 ) 150 elif command -v dnf > /dev/null 2>&1; then 151 instructions=$( 152 cat <<- EOI 153 ${instructions} 154 # Install iptables 155 dnf install -y iptables 156 EOI 157 ) 158 elif command -v yum > /dev/null 2>&1; then 159 instructions=$( 160 cat <<- EOI 161 ${instructions} 162 # Install iptables 163 yum install -y iptables 164 EOI 165 ) 166 else 167 ERROR "iptables binary not found. Please install with a package manager." 168 exit 1 169 fi 170 fi 171 fi 172 173 # instruction: ip_tables module dependency check 174 if ! grep -q ip_tables /proc/modules 2> /dev/null && ! grep -q ip_tables /lib/modules/$(uname -r)/modules.builtin 2> /dev/null; then 175 faced_iptables_error=1 176 if [ -z "$OPT_SKIP_IPTABLES" ]; then 177 instructions=$( 178 cat <<- EOI 179 ${instructions} 180 # Load ip_tables module 181 modprobe ip_tables 182 EOI 183 ) 184 fi 185 fi 186 187 # set DOCKERD_ROOTLESS_SH_FLAGS 188 if [ -n "$faced_iptables_error" ] && [ -n "$OPT_SKIP_IPTABLES" ]; then 189 DOCKERD_ROOTLESS_SH_FLAGS="${DOCKERD_ROOTLESS_SH_FLAGS} --iptables=false" 190 fi 191 192 # instruction: Debian and Arch require setting unprivileged_userns_clone 193 if [ -f /proc/sys/kernel/unprivileged_userns_clone ]; then 194 if [ "1" != "$(cat /proc/sys/kernel/unprivileged_userns_clone)" ]; then 195 instructions=$( 196 cat <<- EOI 197 ${instructions} 198 # Set kernel.unprivileged_userns_clone 199 cat <<EOT > /etc/sysctl.d/50-rootless.conf 200 kernel.unprivileged_userns_clone = 1 201 EOT 202 sysctl --system 203 EOI 204 ) 205 fi 206 fi 207 208 # instruction: RHEL/CentOS 7 requires setting max_user_namespaces 209 if [ -f /proc/sys/user/max_user_namespaces ]; then 210 if [ "0" = "$(cat /proc/sys/user/max_user_namespaces)" ]; then 211 instructions=$( 212 cat <<- EOI 213 ${instructions} 214 # Set user.max_user_namespaces 215 cat <<EOT > /etc/sysctl.d/51-rootless.conf 216 user.max_user_namespaces = 28633 217 EOT 218 sysctl --system 219 EOI 220 ) 221 fi 222 fi 223 224 # instructions: validate subuid/subgid files for current user 225 if ! grep -q "^$(id -un):\|^$(id -u):" /etc/subuid 2> /dev/null; then 226 instructions=$( 227 cat <<- EOI 228 ${instructions} 229 # Add subuid entry for $(id -un) 230 echo "$(id -un):100000:65536" >> /etc/subuid 231 EOI 232 ) 233 fi 234 if ! grep -q "^$(id -un):\|^$(id -u):" /etc/subgid 2> /dev/null; then 235 instructions=$( 236 cat <<- EOI 237 ${instructions} 238 # Add subgid entry for $(id -un) 239 echo "$(id -un):100000:65536" >> /etc/subgid 240 EOI 241 ) 242 fi 243 244 # fail with instructions if requirements are not satisfied. 245 if [ -n "$instructions" ]; then 246 ERROR "Missing system requirements. Run the following commands to" 247 ERROR "install the requirements and run this tool again." 248 if [ -n "$faced_iptables_error" ] && [ -z "$OPT_SKIP_IPTABLES" ]; then 249 ERROR "Alternatively iptables checks can be disabled with --skip-iptables ." 250 fi 251 echo 252 echo "########## BEGIN ##########" 253 echo "sudo sh -eux <<EOF" 254 echo "$instructions" | sed -e '/^$/d' 255 echo "EOF" 256 echo "########## END ##########" 257 echo 258 exit 1 259 fi 260 # TODO: support printing non-essential but recommended instructions: 261 # - sysctl: "net.ipv4.ping_group_range" 262 # - sysctl: "net.ipv4.ip_unprivileged_port_start" 263 # - external binary: slirp4netns 264 # - external binary: fuse-overlayfs 265 } 266 267 # CLI subcommand: "check" 268 cmd_entrypoint_check() { 269 # requirements are already checked in init() 270 INFO "Requirements are satisfied" 271 } 272 273 show_systemd_error() { 274 n="20" 275 ERROR "Failed to start ${SYSTEMD_UNIT}. Run \`journalctl -n ${n} --no-pager --user --unit ${SYSTEMD_UNIT}\` to show the error log." 276 ERROR "Before retrying installation, you might need to uninstall the current setup: \`$0 uninstall -f ; ${BIN}/rootlesskit rm -rf ${HOME}/.local/share/docker\`" 277 if journalctl -q -n ${n} --user --unit ${SYSTEMD_UNIT} | grep -qF "/run/xtables.lock: Permission denied"; then 278 ERROR "Failure likely related to https://github.com/moby/moby/issues/41230" 279 ERROR "This may work as a workaround: \`sudo dnf install -y policycoreutils-python-utils && sudo semanage permissive -a iptables_t\`" 280 fi 281 } 282 283 # install (systemd) 284 install_systemd() { 285 mkdir -p "${CFG_DIR}/systemd/user" 286 unit_file="${CFG_DIR}/systemd/user/${SYSTEMD_UNIT}" 287 if [ -f "${unit_file}" ]; then 288 WARNING "File already exists, skipping: ${unit_file}" 289 else 290 INFO "Creating ${unit_file}" 291 cat <<- EOT > "${unit_file}" 292 [Unit] 293 Description=Docker Application Container Engine (Rootless) 294 Documentation=https://docs.docker.com/go/rootless/ 295 296 [Service] 297 Environment=PATH=$BIN:/sbin:/usr/sbin:$PATH 298 ExecStart=$BIN/dockerd-rootless.sh $DOCKERD_ROOTLESS_SH_FLAGS 299 ExecReload=/bin/kill -s HUP \$MAINPID 300 TimeoutSec=0 301 RestartSec=2 302 Restart=always 303 StartLimitBurst=3 304 StartLimitInterval=60s 305 LimitNOFILE=infinity 306 LimitNPROC=infinity 307 LimitCORE=infinity 308 TasksMax=infinity 309 Delegate=yes 310 Type=simple 311 KillMode=mixed 312 313 [Install] 314 WantedBy=default.target 315 EOT 316 systemctl --user daemon-reload 317 fi 318 if ! systemctl --user --no-pager status "${SYSTEMD_UNIT}" > /dev/null 2>&1; then 319 INFO "starting systemd service ${SYSTEMD_UNIT}" 320 ( 321 set -x 322 if ! systemctl --user start "${SYSTEMD_UNIT}"; then 323 set +x 324 show_systemd_error 325 exit 1 326 fi 327 sleep 3 328 ) 329 fi 330 ( 331 set -x 332 if ! systemctl --user --no-pager --full status "${SYSTEMD_UNIT}"; then 333 set +x 334 show_systemd_error 335 exit 1 336 fi 337 DOCKER_HOST="unix://$XDG_RUNTIME_DIR/docker.sock" $BIN/docker version 338 systemctl --user enable "${SYSTEMD_UNIT}" 339 ) 340 INFO "Installed ${SYSTEMD_UNIT} successfully." 341 INFO "To control ${SYSTEMD_UNIT}, run: \`systemctl --user (start|stop|restart) ${SYSTEMD_UNIT}\`" 342 INFO "To run ${SYSTEMD_UNIT} on system startup, run: \`sudo loginctl enable-linger $(id -un)\`" 343 echo 344 } 345 346 # install (non-systemd) 347 install_nonsystemd() { 348 INFO "systemd not detected, ${DOCKERD_ROOTLESS_SH} needs to be started manually:" 349 echo 350 echo "PATH=$BIN:/sbin:/usr/sbin:\$PATH ${DOCKERD_ROOTLESS_SH} ${DOCKERD_ROOTLESS_SH_FLAGS}" 351 echo 352 } 353 354 cli_ctx_exists() { 355 name="$1" 356 "${BIN}/docker" context inspect -f "{{.Name}}" "${name}" > /dev/null 2>&1 357 } 358 359 cli_ctx_create() { 360 name="$1" 361 host="$2" 362 description="$3" 363 "${BIN}/docker" context create "${name}" --docker "host=${host}" --description "${description}" > /dev/null 364 } 365 366 cli_ctx_rm() { 367 name="$1" 368 "${BIN}/docker" context rm -f "${name}" > /dev/null 369 } 370 371 # CLI subcommand: "install" 372 cmd_entrypoint_install() { 373 # requirements are already checked in init() 374 if [ -z "$SYSTEMD" ]; then 375 install_nonsystemd 376 else 377 install_systemd 378 fi 379 380 if cli_ctx_exists "${CLI_CONTEXT}"; then 381 INFO "CLI context \"${CLI_CONTEXT}\" already exists" 382 else 383 INFO "Creating CLI context \"${CLI_CONTEXT}\"" 384 cli_ctx_create "${CLI_CONTEXT}" "unix://${XDG_RUNTIME_DIR}/docker.sock" "Rootless mode" 385 fi 386 387 echo 388 INFO "Make sure the following environment variables are set (or add them to ~/.bashrc):" 389 echo 390 if [ -n "$XDG_RUNTIME_DIR_CREATED" ]; then 391 echo "# WARNING: systemd not found. You have to remove XDG_RUNTIME_DIR manually on every logout." 392 echo "export XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR}" 393 fi 394 echo "export PATH=${BIN}:\$PATH" 395 echo "export DOCKER_HOST=unix://${XDG_RUNTIME_DIR}/docker.sock" 396 echo 397 398 } 399 400 # CLI subcommand: "uninstall" 401 cmd_entrypoint_uninstall() { 402 # requirements are already checked in init() 403 if [ -z "$SYSTEMD" ]; then 404 INFO "systemd not detected, ${DOCKERD_ROOTLESS_SH} needs to be stopped manually:" 405 else 406 unit_file="${CFG_DIR}/systemd/user/${SYSTEMD_UNIT}" 407 ( 408 set -x 409 systemctl --user stop "${SYSTEMD_UNIT}" 410 ) || : 411 ( 412 set -x 413 systemctl --user disable "${SYSTEMD_UNIT}" 414 ) || : 415 rm -f "${unit_file}" 416 INFO "Uninstalled ${SYSTEMD_UNIT}" 417 fi 418 419 if cli_ctx_exists "${CLI_CONTEXT}"; then 420 cli_ctx_rm "${CLI_CONTEXT}" 421 INFO "Deleted CLI context \"${CLI_CONTEXT}\"" 422 fi 423 424 INFO "This uninstallation tool does NOT remove Docker binaries and data." 425 INFO "To remove data, run: \`$BIN/rootlesskit rm -rf $HOME/.local/share/docker\`" 426 } 427 428 # text for --help 429 usage() { 430 echo "Usage: ${ARG0} [OPTIONS] COMMAND" 431 echo 432 echo "A setup tool for Rootless Docker (${DOCKERD_ROOTLESS_SH})." 433 echo 434 echo "Documentation: https://docs.docker.com/go/rootless/" 435 echo 436 echo "Options:" 437 echo " -f, --force Ignore rootful Docker (/var/run/docker.sock)" 438 echo " --skip-iptables Ignore missing iptables" 439 echo 440 echo "Commands:" 441 echo " check Check prerequisites" 442 echo " install Install systemd unit (if systemd is available) and show how to manage the service" 443 echo " uninstall Uninstall systemd unit" 444 } 445 446 # parse CLI args 447 if ! args="$(getopt -o hf --long help,force,skip-iptables -n "$ARG0" -- "$@")"; then 448 usage 449 exit 1 450 fi 451 eval set -- "$args" 452 while [ "$#" -gt 0 ]; do 453 arg="$1" 454 shift 455 case "$arg" in 456 -h | --help) 457 usage 458 exit 0 459 ;; 460 -f | --force) 461 OPT_FORCE=1 462 ;; 463 --skip-iptables) 464 OPT_SKIP_IPTABLES=1 465 ;; 466 --) 467 break 468 ;; 469 *) 470 # XXX this means we missed something in our "getopt" arguments above! 471 ERROR "Scripting error, unknown argument '$arg' when parsing script arguments." 472 exit 1 473 ;; 474 esac 475 done 476 477 command="${1:-}" 478 if [ -z "$command" ]; then 479 ERROR "No command was specified. Run with --help to see the usage. Maybe you want to run \`$ARG0 install\`?" 480 exit 1 481 fi 482 483 if ! command -v "cmd_entrypoint_${command}" > /dev/null 2>&1; then 484 ERROR "Unknown command: ${command}. Run with --help to see the usage." 485 exit 1 486 fi 487 488 # main 489 init 490 "cmd_entrypoint_${command}"