/ get-docker.sh
get-docker.sh
  1  #!/bin/sh
  2  set -e
  3  # Docker Engine for Linux installation script.
  4  #
  5  # This script is intended as a convenient way to configure docker's package
  6  # repositories and to install Docker Engine, This script is not recommended
  7  # for production environments. Before running this script, make yourself familiar
  8  # with potential risks and limitations, and refer to the installation manual
  9  # at https://docs.docker.com/engine/install/ for alternative installation methods.
 10  #
 11  # The script:
 12  #
 13  # - Requires `root` or `sudo` privileges to run.
 14  # - Attempts to detect your Linux distribution and version and configure your
 15  #   package management system for you.
 16  # - Doesn't allow you to customize most installation parameters.
 17  # - Installs dependencies and recommendations without asking for confirmation.
 18  # - Installs the latest stable release (by default) of Docker CLI, Docker Engine,
 19  #   Docker Buildx, Docker Compose, containerd, and runc. When using this script
 20  #   to provision a machine, this may result in unexpected major version upgrades
 21  #   of these packages. Always test upgrades in a test environment before
 22  #   deploying to your production systems.
 23  # - Isn't designed to upgrade an existing Docker installation. When using the
 24  #   script to update an existing installation, dependencies may not be updated
 25  #   to the expected version, resulting in outdated versions.
 26  #
 27  # Source code is available at https://github.com/docker/docker-install/
 28  #
 29  # Usage
 30  # ==============================================================================
 31  #
 32  # To install the latest stable versions of Docker CLI, Docker Engine, and their
 33  # dependencies:
 34  #
 35  # 1. download the script
 36  #
 37  #   $ curl -fsSL https://get.docker.com -o install-docker.sh
 38  #
 39  # 2. verify the script's content
 40  #
 41  #   $ cat install-docker.sh
 42  #
 43  # 3. run the script with --dry-run to verify the steps it executes
 44  #
 45  #   $ sh install-docker.sh --dry-run
 46  #
 47  # 4. run the script either as root, or using sudo to perform the installation.
 48  #
 49  #   $ sudo sh install-docker.sh
 50  #
 51  # Command-line options
 52  # ==============================================================================
 53  #
 54  # --version <VERSION>
 55  # Use the --version option to install a specific version, for example:
 56  #
 57  #   $ sudo sh install-docker.sh --version 23.0
 58  #
 59  # --channel <stable|test>
 60  #
 61  # Use the --channel option to install from an alternative installation channel.
 62  # The following example installs the latest versions from the "test" channel,
 63  # which includes pre-releases (alpha, beta, rc):
 64  #
 65  #   $ sudo sh install-docker.sh --channel test
 66  #
 67  # Alternatively, use the script at https://test.docker.com, which uses the test
 68  # channel as default.
 69  #
 70  # --mirror <Aliyun|AzureChinaCloud>
 71  #
 72  # Use the --mirror option to install from a mirror supported by this script.
 73  # Available mirrors are "Aliyun" (https://mirrors.aliyun.com/docker-ce), and
 74  # "AzureChinaCloud" (https://mirror.azure.cn/docker-ce), for example:
 75  #
 76  #   $ sudo sh install-docker.sh --mirror AzureChinaCloud
 77  #
 78  # ==============================================================================
 79  
 80  
 81  # Git commit from https://github.com/docker/docker-install when
 82  # the script was uploaded (Should only be modified by upload job):
 83  SCRIPT_COMMIT_SHA="53a22f61c0628e58e1d6680b49e82993d304b449"
 84  
 85  # strip "v" prefix if present
 86  VERSION="${VERSION#v}"
 87  
 88  # The channel to install from:
 89  #   * stable
 90  #   * test
 91  DEFAULT_CHANNEL_VALUE="stable"
 92  if [ -z "$CHANNEL" ]; then
 93  	CHANNEL=$DEFAULT_CHANNEL_VALUE
 94  fi
 95  
 96  DEFAULT_DOWNLOAD_URL="https://download.docker.com"
 97  if [ -z "$DOWNLOAD_URL" ]; then
 98  	DOWNLOAD_URL=$DEFAULT_DOWNLOAD_URL
 99  fi
100  
101  DEFAULT_REPO_FILE="docker-ce.repo"
102  if [ -z "$REPO_FILE" ]; then
103  	REPO_FILE="$DEFAULT_REPO_FILE"
104  	# Automatically default to a staging repo fora
105  	# a staging download url (download-stage.docker.com)
106  	case "$DOWNLOAD_URL" in
107  		*-stage*) REPO_FILE="docker-ce-staging.repo";;
108  	esac
109  fi
110  
111  mirror=''
112  DRY_RUN=${DRY_RUN:-}
113  while [ $# -gt 0 ]; do
114  	case "$1" in
115  		--channel)
116  			CHANNEL="$2"
117  			shift
118  			;;
119  		--dry-run)
120  			DRY_RUN=1
121  			;;
122  		--mirror)
123  			mirror="$2"
124  			shift
125  			;;
126  		--version)
127  			VERSION="${2#v}"
128  			shift
129  			;;
130  		--*)
131  			echo "Illegal option $1"
132  			;;
133  	esac
134  	shift $(( $# > 0 ? 1 : 0 ))
135  done
136  
137  case "$mirror" in
138  	Aliyun)
139  		DOWNLOAD_URL="https://mirrors.aliyun.com/docker-ce"
140  		;;
141  	AzureChinaCloud)
142  		DOWNLOAD_URL="https://mirror.azure.cn/docker-ce"
143  		;;
144  	"")
145  		;;
146  	*)
147  		>&2 echo "unknown mirror '$mirror': use either 'Aliyun', or 'AzureChinaCloud'."
148  		exit 1
149  		;;
150  esac
151  
152  case "$CHANNEL" in
153  	stable|test)
154  		;;
155  	*)
156  		>&2 echo "unknown CHANNEL '$CHANNEL': use either stable or test."
157  		exit 1
158  		;;
159  esac
160  
161  command_exists() {
162  	command -v "$@" > /dev/null 2>&1
163  }
164  
165  # version_gte checks if the version specified in $VERSION is at least the given
166  # SemVer (Maj.Minor[.Patch]), or CalVer (YY.MM) version.It returns 0 (success)
167  # if $VERSION is either unset (=latest) or newer or equal than the specified
168  # version, or returns 1 (fail) otherwise.
169  #
170  # examples:
171  #
172  # VERSION=23.0
173  # version_gte 23.0  // 0 (success)
174  # version_gte 20.10 // 0 (success)
175  # version_gte 19.03 // 0 (success)
176  # version_gte 26.1  // 1 (fail)
177  version_gte() {
178  	if [ -z "$VERSION" ]; then
179  			return 0
180  	fi
181  	version_compare "$VERSION" "$1"
182  }
183  
184  # version_compare compares two version strings (either SemVer (Major.Minor.Path),
185  # or CalVer (YY.MM) version strings. It returns 0 (success) if version A is newer
186  # or equal than version B, or 1 (fail) otherwise. Patch releases and pre-release
187  # (-alpha/-beta) are not taken into account
188  #
189  # examples:
190  #
191  # version_compare 23.0.0 20.10 // 0 (success)
192  # version_compare 23.0 20.10   // 0 (success)
193  # version_compare 20.10 19.03  // 0 (success)
194  # version_compare 20.10 20.10  // 0 (success)
195  # version_compare 19.03 20.10  // 1 (fail)
196  version_compare() (
197  	set +x
198  
199  	yy_a="$(echo "$1" | cut -d'.' -f1)"
200  	yy_b="$(echo "$2" | cut -d'.' -f1)"
201  	if [ "$yy_a" -lt "$yy_b" ]; then
202  		return 1
203  	fi
204  	if [ "$yy_a" -gt "$yy_b" ]; then
205  		return 0
206  	fi
207  	mm_a="$(echo "$1" | cut -d'.' -f2)"
208  	mm_b="$(echo "$2" | cut -d'.' -f2)"
209  
210  	# trim leading zeros to accommodate CalVer
211  	mm_a="${mm_a#0}"
212  	mm_b="${mm_b#0}"
213  
214  	if [ "${mm_a:-0}" -lt "${mm_b:-0}" ]; then
215  		return 1
216  	fi
217  
218  	return 0
219  )
220  
221  is_dry_run() {
222  	if [ -z "$DRY_RUN" ]; then
223  		return 1
224  	else
225  		return 0
226  	fi
227  }
228  
229  is_wsl() {
230  	case "$(uname -r)" in
231  	*microsoft* ) true ;; # WSL 2
232  	*Microsoft* ) true ;; # WSL 1
233  	* ) false;;
234  	esac
235  }
236  
237  is_darwin() {
238  	case "$(uname -s)" in
239  	*darwin* ) true ;;
240  	*Darwin* ) true ;;
241  	* ) false;;
242  	esac
243  }
244  
245  deprecation_notice() {
246  	distro=$1
247  	distro_version=$2
248  	echo
249  	printf "\033[91;1mDEPRECATION WARNING\033[0m\n"
250  	printf "    This Linux distribution (\033[1m%s %s\033[0m) reached end-of-life and is no longer supported by this script.\n" "$distro" "$distro_version"
251  	echo   "    No updates or security fixes will be released for this distribution, and users are recommended"
252  	echo   "    to upgrade to a currently maintained version of $distro."
253  	echo
254  	printf   "Press \033[1mCtrl+C\033[0m now to abort this script, or wait for the installation to continue."
255  	echo
256  	sleep 10
257  }
258  
259  get_distribution() {
260  	lsb_dist=""
261  	# Every system that we officially support has /etc/os-release
262  	if [ -r /etc/os-release ]; then
263  		lsb_dist="$(. /etc/os-release && echo "$ID")"
264  	fi
265  	# Returning an empty string here should be alright since the
266  	# case statements don't act unless you provide an actual value
267  	echo "$lsb_dist"
268  }
269  
270  echo_docker_as_nonroot() {
271  	if is_dry_run; then
272  		return
273  	fi
274  	if command_exists docker && [ -e /var/run/docker.sock ]; then
275  		(
276  			set -x
277  			$sh_c 'docker version'
278  		) || true
279  	fi
280  
281  	# intentionally mixed spaces and tabs here -- tabs are stripped by "<<-EOF", spaces are kept in the output
282  	echo
283  	echo "================================================================================"
284  	echo
285  	if version_gte "20.10"; then
286  		echo "To run Docker as a non-privileged user, consider setting up the"
287  		echo "Docker daemon in rootless mode for your user:"
288  		echo
289  		echo "    dockerd-rootless-setuptool.sh install"
290  		echo
291  		echo "Visit https://docs.docker.com/go/rootless/ to learn about rootless mode."
292  		echo
293  	fi
294  	echo
295  	echo "To run the Docker daemon as a fully privileged service, but granting non-root"
296  	echo "users access, refer to https://docs.docker.com/go/daemon-access/"
297  	echo
298  	echo "WARNING: Access to the remote API on a privileged Docker daemon is equivalent"
299  	echo "         to root access on the host. Refer to the 'Docker daemon attack surface'"
300  	echo "         documentation for details: https://docs.docker.com/go/attack-surface/"
301  	echo
302  	echo "================================================================================"
303  	echo
304  }
305  
306  # Check if this is a forked Linux distro
307  check_forked() {
308  
309  	# Check for lsb_release command existence, it usually exists in forked distros
310  	if command_exists lsb_release; then
311  		# Check if the `-u` option is supported
312  		set +e
313  		lsb_release -a -u > /dev/null 2>&1
314  		lsb_release_exit_code=$?
315  		set -e
316  
317  		# Check if the command has exited successfully, it means we're in a forked distro
318  		if [ "$lsb_release_exit_code" = "0" ]; then
319  			# Print info about current distro
320  			cat <<-EOF
321  			You're using '$lsb_dist' version '$dist_version'.
322  			EOF
323  
324  			# Get the upstream release info
325  			lsb_dist=$(lsb_release -a -u 2>&1 | tr '[:upper:]' '[:lower:]' | grep -E 'id' | cut -d ':' -f 2 | tr -d '[:space:]')
326  			dist_version=$(lsb_release -a -u 2>&1 | tr '[:upper:]' '[:lower:]' | grep -E 'codename' | cut -d ':' -f 2 | tr -d '[:space:]')
327  
328  			# Print info about upstream distro
329  			cat <<-EOF
330  			Upstream release is '$lsb_dist' version '$dist_version'.
331  			EOF
332  		else
333  			if [ -r /etc/debian_version ] && [ "$lsb_dist" != "ubuntu" ] && [ "$lsb_dist" != "raspbian" ]; then
334  				if [ "$lsb_dist" = "osmc" ]; then
335  					# OSMC runs Raspbian
336  					lsb_dist=raspbian
337  				else
338  					# We're Debian and don't even know it!
339  					lsb_dist=debian
340  				fi
341  				dist_version="$(sed 's/\/.*//' /etc/debian_version | sed 's/\..*//')"
342  				case "$dist_version" in
343  					13)
344  						dist_version="trixie"
345  					;;
346  					12)
347  						dist_version="bookworm"
348  					;;
349  					11)
350  						dist_version="bullseye"
351  					;;
352  					10)
353  						dist_version="buster"
354  					;;
355  					9)
356  						dist_version="stretch"
357  					;;
358  					8)
359  						dist_version="jessie"
360  					;;
361  				esac
362  			fi
363  		fi
364  	fi
365  }
366  
367  do_install() {
368  	echo "# Executing docker install script, commit: $SCRIPT_COMMIT_SHA"
369  
370  	if command_exists docker; then
371  		cat >&2 <<-'EOF'
372  			Warning: the "docker" command appears to already exist on this system.
373  
374  			If you already have Docker installed, this script can cause trouble, which is
375  			why we're displaying this warning and provide the opportunity to cancel the
376  			installation.
377  
378  			If you installed the current Docker package using this script and are using it
379  			again to update Docker, you can ignore this message, but be aware that the
380  			script resets any custom changes in the deb and rpm repo configuration
381  			files to match the parameters passed to the script.
382  
383  			You may press Ctrl+C now to abort this script.
384  		EOF
385  		( set -x; sleep 20 )
386  	fi
387  
388  	user="$(id -un 2>/dev/null || true)"
389  
390  	sh_c='sh -c'
391  	if [ "$user" != 'root' ]; then
392  		if command_exists sudo; then
393  			sh_c='sudo -E sh -c'
394  		elif command_exists su; then
395  			sh_c='su -c'
396  		else
397  			cat >&2 <<-'EOF'
398  			Error: this installer needs the ability to run commands as root.
399  			We are unable to find either "sudo" or "su" available to make this happen.
400  			EOF
401  			exit 1
402  		fi
403  	fi
404  
405  	if is_dry_run; then
406  		sh_c="echo"
407  	fi
408  
409  	# perform some very rudimentary platform detection
410  	lsb_dist=$( get_distribution )
411  	lsb_dist="$(echo "$lsb_dist" | tr '[:upper:]' '[:lower:]')"
412  
413  	if is_wsl; then
414  		echo
415  		echo "WSL DETECTED: We recommend using Docker Desktop for Windows."
416  		echo "Please get Docker Desktop from https://www.docker.com/products/docker-desktop/"
417  		echo
418  		cat >&2 <<-'EOF'
419  
420  			You may press Ctrl+C now to abort this script.
421  		EOF
422  		( set -x; sleep 20 )
423  	fi
424  
425  	case "$lsb_dist" in
426  
427  		ubuntu)
428  			if command_exists lsb_release; then
429  				dist_version="$(lsb_release --codename | cut -f2)"
430  			fi
431  			if [ -z "$dist_version" ] && [ -r /etc/lsb-release ]; then
432  				dist_version="$(. /etc/lsb-release && echo "$DISTRIB_CODENAME")"
433  			fi
434  		;;
435  
436  		debian|raspbian)
437  			dist_version="$(sed 's/\/.*//' /etc/debian_version | sed 's/\..*//')"
438  			case "$dist_version" in
439  				13)
440  					dist_version="trixie"
441  				;;
442  				12)
443  					dist_version="bookworm"
444  				;;
445  				11)
446  					dist_version="bullseye"
447  				;;
448  				10)
449  					dist_version="buster"
450  				;;
451  				9)
452  					dist_version="stretch"
453  				;;
454  				8)
455  					dist_version="jessie"
456  				;;
457  			esac
458  		;;
459  
460  		centos|rhel)
461  			if [ -z "$dist_version" ] && [ -r /etc/os-release ]; then
462  				dist_version="$(. /etc/os-release && echo "$VERSION_ID")"
463  			fi
464  		;;
465  
466  		*)
467  			if command_exists lsb_release; then
468  				dist_version="$(lsb_release --release | cut -f2)"
469  			fi
470  			if [ -z "$dist_version" ] && [ -r /etc/os-release ]; then
471  				dist_version="$(. /etc/os-release && echo "$VERSION_ID")"
472  			fi
473  		;;
474  
475  	esac
476  
477  	# Check if this is a forked Linux distro
478  	check_forked
479  
480  	# Print deprecation warnings for distro versions that recently reached EOL,
481  	# but may still be commonly used (especially LTS versions).
482  	case "$lsb_dist.$dist_version" in
483  		centos.8|centos.7|rhel.7)
484  			deprecation_notice "$lsb_dist" "$dist_version"
485  			;;
486  		debian.buster|debian.stretch|debian.jessie)
487  			deprecation_notice "$lsb_dist" "$dist_version"
488  			;;
489  		raspbian.buster|raspbian.stretch|raspbian.jessie)
490  			deprecation_notice "$lsb_dist" "$dist_version"
491  			;;
492  		ubuntu.bionic|ubuntu.xenial|ubuntu.trusty)
493  			deprecation_notice "$lsb_dist" "$dist_version"
494  			;;
495  		ubuntu.mantic|ubuntu.lunar|ubuntu.kinetic|ubuntu.impish|ubuntu.hirsute|ubuntu.groovy|ubuntu.eoan|ubuntu.disco|ubuntu.cosmic)
496  			deprecation_notice "$lsb_dist" "$dist_version"
497  			;;
498  		fedora.*)
499  			if [ "$dist_version" -lt 40 ]; then
500  				deprecation_notice "$lsb_dist" "$dist_version"
501  			fi
502  			;;
503  	esac
504  
505  	# Run setup for each distro accordingly
506  	case "$lsb_dist" in
507  		ubuntu|debian|raspbian)
508  			pre_reqs="ca-certificates curl"
509  			apt_repo="deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] $DOWNLOAD_URL/linux/$lsb_dist $dist_version $CHANNEL"
510  			(
511  				if ! is_dry_run; then
512  					set -x
513  				fi
514  				$sh_c 'apt-get -qq update >/dev/null'
515  				$sh_c "DEBIAN_FRONTEND=noninteractive apt-get -y -qq install $pre_reqs >/dev/null"
516  				$sh_c 'install -m 0755 -d /etc/apt/keyrings'
517  				$sh_c "curl -fsSL \"$DOWNLOAD_URL/linux/$lsb_dist/gpg\" -o /etc/apt/keyrings/docker.asc"
518  				$sh_c "chmod a+r /etc/apt/keyrings/docker.asc"
519  				$sh_c "echo \"$apt_repo\" > /etc/apt/sources.list.d/docker.list"
520  				$sh_c 'apt-get -qq update >/dev/null'
521  			)
522  			pkg_version=""
523  			if [ -n "$VERSION" ]; then
524  				if is_dry_run; then
525  					echo "# WARNING: VERSION pinning is not supported in DRY_RUN"
526  				else
527  					# Will work for incomplete versions IE (17.12), but may not actually grab the "latest" if in the test channel
528  					pkg_pattern="$(echo "$VERSION" | sed 's/-ce-/~ce~.*/g' | sed 's/-/.*/g')"
529  					search_command="apt-cache madison docker-ce | grep '$pkg_pattern' | head -1 | awk '{\$1=\$1};1' | cut -d' ' -f 3"
530  					pkg_version="$($sh_c "$search_command")"
531  					echo "INFO: Searching repository for VERSION '$VERSION'"
532  					echo "INFO: $search_command"
533  					if [ -z "$pkg_version" ]; then
534  						echo
535  						echo "ERROR: '$VERSION' not found amongst apt-cache madison results"
536  						echo
537  						exit 1
538  					fi
539  					if version_gte "18.09"; then
540  							search_command="apt-cache madison docker-ce-cli | grep '$pkg_pattern' | head -1 | awk '{\$1=\$1};1' | cut -d' ' -f 3"
541  							echo "INFO: $search_command"
542  							cli_pkg_version="=$($sh_c "$search_command")"
543  					fi
544  					pkg_version="=$pkg_version"
545  				fi
546  			fi
547  			(
548  				pkgs="docker-ce${pkg_version%=}"
549  				if version_gte "18.09"; then
550  						# older versions didn't ship the cli and containerd as separate packages
551  						pkgs="$pkgs docker-ce-cli${cli_pkg_version%=} containerd.io"
552  				fi
553  				if version_gte "20.10"; then
554  						pkgs="$pkgs docker-compose-plugin docker-ce-rootless-extras$pkg_version"
555  				fi
556  				if version_gte "23.0"; then
557  						pkgs="$pkgs docker-buildx-plugin"
558  				fi
559  				if ! is_dry_run; then
560  					set -x
561  				fi
562  				$sh_c "DEBIAN_FRONTEND=noninteractive apt-get -y -qq install $pkgs >/dev/null"
563  			)
564  			echo_docker_as_nonroot
565  			exit 0
566  			;;
567  		centos|fedora|rhel)
568  			if [ "$(uname -m)" = "s390x" ]; then
569  				echo "Effective v27.5, please consult RHEL distro statement for s390x support."
570  				exit 1
571  			fi
572  			repo_file_url="$DOWNLOAD_URL/linux/$lsb_dist/$REPO_FILE"
573  			(
574  				if ! is_dry_run; then
575  					set -x
576  				fi
577  				if command_exists dnf5; then
578  					$sh_c "dnf -y -q --setopt=install_weak_deps=False install dnf-plugins-core"
579  					$sh_c "dnf5 config-manager addrepo --overwrite --save-filename=docker-ce.repo --from-repofile='$repo_file_url'"
580  
581  					if [ "$CHANNEL" != "stable" ]; then
582  						$sh_c "dnf5 config-manager setopt \"docker-ce-*.enabled=0\""
583  						$sh_c "dnf5 config-manager setopt \"docker-ce-$CHANNEL.enabled=1\""
584  					fi
585  					$sh_c "dnf makecache"
586  				elif command_exists dnf; then
587  					$sh_c "dnf -y -q --setopt=install_weak_deps=False install dnf-plugins-core"
588  					$sh_c "rm -f /etc/yum.repos.d/docker-ce.repo  /etc/yum.repos.d/docker-ce-staging.repo"
589  					$sh_c "dnf config-manager --add-repo $repo_file_url"
590  
591  					if [ "$CHANNEL" != "stable" ]; then
592  						$sh_c "dnf config-manager --set-disabled \"docker-ce-*\""
593  						$sh_c "dnf config-manager --set-enabled \"docker-ce-$CHANNEL\""
594  					fi
595  					$sh_c "dnf makecache"
596  				else
597  					$sh_c "yum -y -q install yum-utils"
598  					$sh_c "rm -f /etc/yum.repos.d/docker-ce.repo  /etc/yum.repos.d/docker-ce-staging.repo"
599  					$sh_c "yum-config-manager --add-repo $repo_file_url"
600  
601  					if [ "$CHANNEL" != "stable" ]; then
602  						$sh_c "yum-config-manager --disable \"docker-ce-*\""
603  						$sh_c "yum-config-manager --enable \"docker-ce-$CHANNEL\""
604  					fi
605  					$sh_c "yum makecache"
606  				fi
607  			)
608  			pkg_version=""
609  			if command_exists dnf; then
610  				pkg_manager="dnf"
611  				pkg_manager_flags="-y -q --best"
612  			else
613  				pkg_manager="yum"
614  				pkg_manager_flags="-y -q"
615  			fi
616  			if [ -n "$VERSION" ]; then
617  				if is_dry_run; then
618  					echo "# WARNING: VERSION pinning is not supported in DRY_RUN"
619  				else
620  					if [ "$lsb_dist" = "fedora" ]; then
621  						pkg_suffix="fc$dist_version"
622  					else
623  						pkg_suffix="el"
624  					fi
625  					pkg_pattern="$(echo "$VERSION" | sed 's/-ce-/\\\\.ce.*/g' | sed 's/-/.*/g').*$pkg_suffix"
626  					search_command="$pkg_manager list --showduplicates docker-ce | grep '$pkg_pattern' | tail -1 | awk '{print \$2}'"
627  					pkg_version="$($sh_c "$search_command")"
628  					echo "INFO: Searching repository for VERSION '$VERSION'"
629  					echo "INFO: $search_command"
630  					if [ -z "$pkg_version" ]; then
631  						echo
632  						echo "ERROR: '$VERSION' not found amongst $pkg_manager list results"
633  						echo
634  						exit 1
635  					fi
636  					if version_gte "18.09"; then
637  						# older versions don't support a cli package
638  						search_command="$pkg_manager list --showduplicates docker-ce-cli | grep '$pkg_pattern' | tail -1 | awk '{print \$2}'"
639  						cli_pkg_version="$($sh_c "$search_command" | cut -d':' -f 2)"
640  					fi
641  					# Cut out the epoch and prefix with a '-'
642  					pkg_version="-$(echo "$pkg_version" | cut -d':' -f 2)"
643  				fi
644  			fi
645  			(
646  				pkgs="docker-ce$pkg_version"
647  				if version_gte "18.09"; then
648  					# older versions didn't ship the cli and containerd as separate packages
649  					if [ -n "$cli_pkg_version" ]; then
650  						pkgs="$pkgs docker-ce-cli-$cli_pkg_version containerd.io"
651  					else
652  						pkgs="$pkgs docker-ce-cli containerd.io"
653  					fi
654  				fi
655  				if version_gte "20.10"; then
656  					pkgs="$pkgs docker-compose-plugin docker-ce-rootless-extras$pkg_version"
657  				fi
658  				if version_gte "23.0"; then
659  						pkgs="$pkgs docker-buildx-plugin"
660  				fi
661  				if ! is_dry_run; then
662  					set -x
663  				fi
664  				$sh_c "$pkg_manager $pkg_manager_flags install $pkgs"
665  			)
666  			echo_docker_as_nonroot
667  			exit 0
668  			;;
669  		sles)
670  			echo "Effective v27.5, please consult SLES distro statement for s390x support."
671  			exit 1
672  			;;
673  		*)
674  			if [ -z "$lsb_dist" ]; then
675  				if is_darwin; then
676  					echo
677  					echo "ERROR: Unsupported operating system 'macOS'"
678  					echo "Please get Docker Desktop from https://www.docker.com/products/docker-desktop"
679  					echo
680  					exit 1
681  				fi
682  			fi
683  			echo
684  			echo "ERROR: Unsupported distribution '$lsb_dist'"
685  			echo
686  			exit 1
687  			;;
688  	esac
689  	exit 1
690  }
691  
692  # wrapped up in a function so that we have some protection against only getting
693  # half the file during "curl | sh"
694  do_install