本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 [署名 4.0 国际 (CC BY 4.0)](https://creativecommons.org/licenses/by/4.0/deed.zh) 本文作者: 苏洋 创建时间: 2026年10月06日 统计字数: 4464字 阅读时间: 9分钟阅读 本文链接: https://soulteary.com/2026/10/06/install-docker-on-ubuntu-26-04-with-aliyun-and-tencent-cloud-mirrors-and-basic-security.html ----- # Ubuntu 26.04 安装 Docker:阿里云、腾讯云镜像源与基础安全配置 这篇文章记录 Ubuntu 26.04 云服务器上的 Docker 安装过程,以及装好后需要做的一些基础配置。 ## 写在前面 在 Ubuntu 云服务器上安装 Docker,常见的做法是直接运行官方安装脚本。需要使用阿里云软件源时,可以加上 `--mirror Aliyun`: ```bash curl -fsSL https://get.docker.com | bash -s -- --mirror Aliyun ``` 这条命令很方便。不过,安装时可能遇到脚本下载超时、APT 找不到软件包,或者装好后拉不下来容器镜像。这些问题发生在不同环节,需要分别排查。 下面先介绍如何配置阿里云或腾讯云的 APT 软件源,安装 Docker Engine、Buildx 和 Compose,再处理日志轮转、操作权限和端口配置。后续部署各种应用时,也能沿用这些配置。 对于长期运行的服务器,我更倾向于直接配置 APT 源,方便检查软件包来源和管理后续升级。便捷脚本可以用于开发和测试环境,[Docker 官方也不建议依赖它部署生产系统](https://github.com/docker/docker-install)。 本文以运行 Ubuntu 26.04 的阿里云 ECS 和腾讯云 CVM 为例,有相应系统权限的轻量服务器也可以参考。使用 Alibaba Cloud Linux、TencentOS,或已经部署 Kubernetes 的节点时,需要按实际环境调整安装步骤。 ## 安装源和容器镜像源分开看 安装 Docker 时,容易把安装脚本、软件包源和容器镜像源混在一起。它们分别负责不同的事情: | 下载内容 | 用途 | 对应的配置 | | ------------- | --------------------------------------- | -------------------------------------------- | | 安装脚本 | 自动配置软件源、安装软件包 | `get.docker.com`、官方源码仓库,或本文 fork / 脚本附录 | | Docker CE 软件包 | 安装 Engine、CLI、containerd、Buildx、Compose | APT 源、脚本的 `--mirror` 或 `DOWNLOAD_URL` | | 容器镜像 | 运行应用,例如 Traefik、Gitea | 镜像仓库地址、Docker daemon 代理,或适用的 Registry mirror | 有一个细节是安装脚本支持的`--mirror Aliyun` 只会把 Docker 软件包源切换到阿里云。安装脚本仍从 `get.docker.com` 下载,`docker pull` 也不会因此获得加速。 遇到报错,我们需要先看失败的是哪一步。如果 Docker 已经安装成功,但拉取容器镜像超时,就继续检查容器仓库、网络和 daemon 代理,通常无需重装 Docker。 ## 安装前的准备 ### 确认系统和架构 登录服务器后,查看系统版本、软件包架构和内核版本: ```bash cat /etc/os-release dpkg --print-architecture uname -r ``` Ubuntu 26.04 的发行版代号是 `resolute`。后面的命令会自动读取代号和架构,使用 `amd64` 或 `arm64` 时都不需要手动修改。Ubuntu 24.04 和 22.04 也在 Docker 官方支持范围内,配置时保留各自的发行版代号。 如果镜像站返回 404,先检查地址和同步情况。不要把 Ubuntu 26.04 的代号换成 `noble`,也不要修改系统版本信息来绕过检查。 AMD64 和 ARM64 使用同一个 Docker CE 仓库地址,APT 根据架构配置下载对应的软件包。Ubuntu 系统源与 Docker 软件包源分别配置,下面的步骤无需修改 `ubuntu.sources` 或全局替换域名。 接下来,我们使用的命令按 Bash 编写,默认当前用户具有 `sudo` 权限。使用 Zsh 时,先运行 `bash` 切换 Shell;以 root 登录时,可以去掉命令中的 `sudo`。 ### 检查现有安装和软件源 查看机器上是否已经安装相关组件: ```bash dpkg-query -W -f='${binary:Package}\t${Status}\t${Version}\n' \ docker-ce docker-ce-cli containerd.io \ docker.io docker-compose docker-compose-v2 docker-doc \ docker-buildx podman-docker containerd runc 2>/dev/null || true ``` 输出中,状态为 `install ok installed` 的软件包才是已安装的。 再检查是否已有 Docker 软件源配置: ```bash sudo grep -RnsE 'docker-ce|download\.docker\.com' \ /etc/apt/sources.list /etc/apt/sources.list.d \ 2>/dev/null || true ``` 新服务器检查完后,可以继续安装。如果机器已经在运行容器,先备份业务数据和配置,再安排维护时间。下面按初始化新环境编写,直接用于现有环境可能影响正在运行的服务。 如果之前安装的是 Ubuntu 自带的 Docker 包,切换到 Docker CE 前需要检查冲突。下面按照 [Docker 官方列出的冲突包](https://docs.docker.com/engine/install/ubuntu/#uninstall-old-versions),收集机器上实际安装的包,再由 APT 显示卸载计划,等待确认: ```bash ( set -eu packages=() for pkg in docker.io docker-compose docker-compose-v2 docker-doc \ docker-buildx podman-docker containerd runc; do status="$(dpkg-query -W -f='${Status}' "$pkg" 2>/dev/null || true)" if [ "$status" = "install ok installed" ]; then packages+=("$pkg") fi done if [ "${#packages[@]}" -gt 0 ]; then sudo apt-get remove "${packages[@]}" fi ) ``` 确认卸载前,仔细看 APT 列出的软件包和关联删除项。`containerd`、`runc` 也可能被其他容器平台使用,无法确认用途时,先取消操作。 已有 Docker 软件源的机器,先检查对应文件,备份后再停用重复配置。同一仓库使用不同的 `Signed-By` 可能导致 APT 报错,同时配置多家镜像站也会让软件包来源难以判断。只修改确认过的 Docker 源文件。 ### 安装基础工具 ```bash sudo apt-get -o APT::Update::Error-Mode=any update && \ sudo apt-get install -y ca-certificates curl gnupg ``` 这一步使用 Ubuntu 系统源。如果失败,先检查系统源、DNS 和出站网络。Docker 软件源还没有配置,调整 `--mirror` 参数帮不上忙。 准备完成后,从下面的阿里云和腾讯云方案中选择一套。公网源可以按实际访问情况选择,云内地址则在对应的云环境中使用。 ## 配置 Docker 软件源 根据你的实际环境,阿里云和腾讯云的配置选一套即可。两套命令都会读取系统代号和架构,检查仓库元数据,再保存公钥并写入 APT 配置。这一步完成后,还需要继续安装 Docker 软件包。 ### 使用阿里云软件源 [阿里云 Docker CE 镜像站](https://developer.aliyun.com/mirror/docker-ce/)提供的公网地址是: ```text https://mirrors.aliyun.com/docker-ce ``` [阿里云 ECS 安装文档](https://help.aliyun.com/zh/ecs/user-guide/install-and-use-docker)还提供了 VPC 环境中的云内地址: ```text http://mirrors.cloud.aliyuncs.com/docker-ce ``` 下面统一使用公网 HTTPS 地址,下载仓库公钥时也走 HTTPS。非阿里云服务器使用公网地址;只有内网访问条件的 ECS,需要另行确认镜像站的访问路径,并通过可信渠道准备公钥。 完成前面的安装准备后,执行: ```bash ( set -eu . /etc/os-release [ "$ID" = "ubuntu" ] || { echo "这段配置仅适用于 Ubuntu。" >&2 exit 1 } MIRROR="https://mirrors.aliyun.com/docker-ce" CODENAME="${UBUNTU_CODENAME:-${VERSION_CODENAME:-}}" ARCH="$(dpkg --print-architecture)" [ -n "$CODENAME" ] || { echo "无法确定 Ubuntu 代号。" >&2 exit 1 } # 已有配置时先检查,避免直接覆盖。 if [ -e /etc/apt/sources.list.d/docker.sources ]; then echo "docker.sources 已存在,请先检查现有配置。" >&2 exit 1 fi WORK="$(mktemp -d)" trap 'rm -rf "$WORK"' EXIT # 检查当前发行版的仓库元数据和架构记录。 curl -fsSL --connect-timeout 10 --max-time 60 \ "$MIRROR/linux/ubuntu/dists/$CODENAME/Release" \ -o "$WORK/Release" grep -Fq "stable/binary-$ARCH/Packages" "$WORK/Release" || { echo "仓库元数据未列出当前架构,请检查镜像同步状态。" >&2 exit 1 } # 公钥先下载到临时目录,成功后再保存到系统目录。 curl -fsSL --connect-timeout 10 --max-time 60 \ "$MIRROR/linux/ubuntu/gpg" \ -o "$WORK/docker.asc" gpg --batch --show-keys "$WORK/docker.asc" sudo install -m 0755 -d /etc/apt/keyrings sudo install -m 0644 "$WORK/docker.asc" /etc/apt/keyrings/docker.asc sudo tee /etc/apt/sources.list.d/docker.sources >/dev/null <&2 exit 1 } MIRROR="https://mirrors.cloud.tencent.com/docker-ce" CODENAME="${UBUNTU_CODENAME:-${VERSION_CODENAME:-}}" ARCH="$(dpkg --print-architecture)" [ -n "$CODENAME" ] || { echo "无法确定 Ubuntu 代号。" >&2 exit 1 } # 已有配置时先检查,避免直接覆盖。 if [ -e /etc/apt/sources.list.d/docker.sources ]; then echo "docker.sources 已存在,请先检查现有配置。" >&2 exit 1 fi WORK="$(mktemp -d)" trap 'rm -rf "$WORK"' EXIT # 检查当前发行版的仓库元数据和架构记录。 curl -fsSL --connect-timeout 10 --max-time 60 \ "$MIRROR/linux/ubuntu/dists/$CODENAME/Release" \ -o "$WORK/Release" grep -Fq "stable/binary-$ARCH/Packages" "$WORK/Release" || { echo "仓库元数据未列出当前架构,请检查镜像同步状态。" >&2 exit 1 } # 公钥先下载到临时目录,成功后再保存到系统目录。 curl -fsSL --connect-timeout 10 --max-time 60 \ "$MIRROR/linux/ubuntu/gpg" \ -o "$WORK/docker.asc" gpg --batch --show-keys "$WORK/docker.asc" sudo install -m 0755 -d /etc/apt/keyrings sudo install -m 0644 "$WORK/docker.asc" /etc/apt/keyrings/docker.asc sudo tee /etc/apt/sources.list.d/docker.sources >/dev/null <&2 exit 1 fi CONFIG="$(mktemp)" trap 'rm -f "$CONFIG"' EXIT cat > "$CONFIG" <<'EOF' { "log-driver": "local", "log-opts": { "max-size": "20m", "max-file": "5" } } EOF sudo dockerd --validate --config-file="$CONFIG" sudo install -m 0755 -d /etc/docker sudo install -m 0644 "$CONFIG" /etc/docker/daemon.json sudo systemctl restart docker ) ``` [`dockerd --validate`](https://docs.docker.com/reference/cli/dockerd/) 检查配置后就会退出,不启动服务。当我们执行脚本,写入文件并重启后,还要确认 Docker 正常运行,尤其要检查已有的 systemd 启动参数是否与文件配置冲突。机器已经承载业务时,建议在维护窗口修改和重启。 检查服务状态和默认日志驱动: ```bash sudo systemctl is-active docker sudo docker info --format '{{.LoggingDriver}}' ``` 输出应分别为 `active` 和 `local`。 [新的默认日志配置](https://docs.docker.com/engine/logging/configure/)只用于后续新建的容器。已有容器需要重建才能采用新选项,重启 Docker 或容器都不会自动改变其日志配置。已经接入日志采集器的环境,先确认采集方式支持 `local`。 ### 控制 Docker 操作权限 [Docker 官方文档](https://docs.docker.com/engine/install/linux-postinstall/)明确说明,加入 `docker` 组的账号可以获得相当于 root 的权限。所以这里继续使用 `sudo docker`,不为了省去 sudo,就把 CI、网站运行账号或其他用户全部加入该组。 通过 sudo 调用也需要控制授权范围。能够执行任意 Docker 命令的账号,依然具有很高的权限。 Docker API 应有访问保护,也不要随手把 Docker socket 挂进业务容器。即使挂载时加上 `:ro`,容器仍然可以通过 socket 调用 API,无法据此限制为只读操作。相关说明见 [Docker Engine 安全文档](https://docs.docker.com/engine/security/)。 ### 公网只开放需要的端口 后面如果使用 Traefik 统一提供 Web 入口,可以在云安全组中按下面的方式配置入站访问: | 入口 | 建议策略 | | -------------------- | ------------------- | | SSH,例如 TCP 22 | 只允许管理 IP、VPN 或堡垒机来源 | | TCP 80、443 | 部署 Web 入口时按实际需求开放 | | 业务管理后台、数据库端口 | 不直接向公网开放 | | Docker API 2375、2376 | 本方案不开放 | 仅安装 Docker,无需开放 80、443 的入站访问。下载软件包需要的是服务器能够向外访问相应软件源。 修改 SSH 或安全组规则前,保留当前连接,并确认另一个管理连接能够正常登录,避免把自己锁在服务器外面。 容器端口发布后,也要检查监听地址。[`8080:80` 这样的写法](https://docs.docker.com/engine/network/port-publishing/)默认会发布到宿主机的所有地址。只供本机访问的服务,可以在 Compose 中明确绑定回环地址: ```yaml ports: - "127.0.0.1:8080:80" ``` 这是服务中的 `ports` 配置片段,适用于常规 bridge/NAT 网络,没有额外启用容器直连路由。 Docker 发布端口还可能[绕过 UFW 的常规规则](https://docs.docker.com/engine/network/packet-filtering-firewalls/)。配置主机防火墙时,先确认 Docker 使用的后端:iptables 和原生 nftables 的规则挂接方式不同,[原生 nftables 后端](https://docs.docker.com/engine/network/firewall-nftables/)没有 `DOCKER-USER` 链,不能直接照搬旧教程。 也不要通过关闭 Docker 的防火墙规则管理来处理端口问题,这可能破坏容器网络。应检查实际发布的端口、监听地址和对应防火墙规则。 ## 拉取容器镜像时再检查加速配置 Docker 装好后,拉取容器镜像还需要单独检查网络和仓库配置。前面的安装方案只配置软件包源,不会自动设置 `registry-mirrors`。 按照[阿里云目前的镜像加速说明](https://help.aliyun.com/zh/acr/user-guide/accelerate-the-pulls-of-docker-official-images),ACR 镜像加速已经停止同步最新镜像,服务面向个人开发场景,不允许再次封装或用于商业用途。以前保存的加速地址,使用前需要重新确认所需镜像版本是否存在,以及服务限制是否符合使用场景。 这项变化针对容器镜像加速,Docker CE 的 APT 镜像站是另一项服务。 腾讯云环境中,旧教程里的公共加速地址也需要重新检查。先确认服务是否仍在提供、是否限制访问来源,再尝试拉取实际需要的镜像版本。 对于需要长期运行的应用和服务,我更倾向于提前将所需镜像保存到自己可控的仓库,记录验证过的版本和 digest。部署时直接使用这些镜像,避免临时寻找公共代理。 [`registry-mirrors`](https://docs.docker.com/docker-hub/image-library/mirror/) 用于 Docker Hub 镜像代理,其他 Registry 不会因此自动走代理。普通私有仓库也不能直接当作镜像代理填写;使用其中的镜像时,按包含仓库域名和路径的完整名称拉取即可。 如果通过代理访问镜像仓库,还要区分 Shell 和 Docker daemon 的配置。Shell 中设置的代理不会自动传给 systemd 管理的 Docker 服务。`curl` 已经能访问外网,Docker 仍拉不下来镜像时,继续检查 [Docker daemon 的代理设置](https://docs.docker.com/engine/daemon/proxy/)。 ## 遇到问题和后续升级 ### 按失败环节排查 遇到报错,先分清问题出在脚本下载、软件包安装,还是容器运行。不同环节使用的地址和配置不同,可以按下面的线索继续检查。 | 现象 | 优先检查 | | --------------------------------------------- | ---------------------------------------------------- | | `get.docker.com` 超时 | 脚本下载链路;改用官方源码入口、本文 fork 或完整脚本附录,也可以绕过脚本配置 APT | | `unknown mirror 'Tencent'` | fork 参数应为 `TencentCloud`;前面的官方脚本方案仍使用 `DOWNLOAD_URL` | | 官方脚本提示 `unknown mirror 'TencentCloud'` | 可能拿错脚本;使用本文 fork,或回到官方 `DOWNLOAD_URL` 用法 | | `raw.githubusercontent.com` 不可达 | 只是脚本下载入口失败;使用本文完整脚本附录,并单独检查软件包源 | | 附录保存时校验失败 | 停止执行;检查复制是否完整、Tab 是否被转换,以及是否引用了不同提交 | | 保存脚本时提示文件已存在 | 不会覆盖旧文件;先审阅、备份或更换目标文件名,不继续执行不明版本 | | `Release` 下载失败、返回 404 | 网络、路径和该发行版的镜像同步状态;不要借用其他系统代号 | | 软件包候选版本是 `(none)` | APT 索引是否成功更新,`Suites`、架构和镜像同步状态 | | `NO_PUBKEY`、签名验证失败 | 公钥来源、文件可读性、`Signed-By` 配置;不要关闭签名验证 | | `Conflicting values set for option Signed-By` | 同一个 Docker 仓库是否被重复配置,且绑定了不同公钥 | | `docker version` 只有 Client | 当前连接的 daemon、服务状态、上下文及权限 | | `docker pull` 超时 | 容器 Registry 访问、认证或 daemon 代理,不是 APT 软件源 | 软件包安装问题可以对照 [Docker Ubuntu 安装文档](https://docs.docker.com/engine/install/ubuntu/)检查;需要通过代理拉取镜像时,参考 [Docker daemon 代理配置](https://docs.docker.com/engine/daemon/proxy/),再结合实际日志定位。 ### 后续升级使用 APT 安装完成后,保存当前的软件包版本: ```bash dpkg-query -W -f='${binary:Package}\t${Version}\n' \ docker-ce docker-ce-cli containerd.io \ docker-buildx-plugin docker-compose-plugin \ | tee docker-package-versions.txt ``` 准备升级时,更新索引并查看 Engine 和 CLI 的可用版本: ```bash sudo apt-get -o APT::Update::Error-Mode=any update && \ apt-cache madison docker-ce docker-ce-cli ``` 先在测试环境验证新版本,备份业务数据和配置,再于维护窗口执行升级: ```bash sudo apt-get install --only-upgrade \ docker-ce docker-ce-cli containerd.io \ docker-buildx-plugin docker-compose-plugin ``` 这条命令可能升级到仓库中的新主版本,执行前检查 APT 给出的升级计划。需要固定版本时,显式指定验证过的软件包版本,并继续安排后续安全更新。 已有安装通过 APT 升级即可。[Docker 安装脚本说明](https://github.com/docker/docker-install)也提醒,便捷脚本不适合作为已有环境的常规升级工具。 ### 调整存储前,先检查实际配置 旧教程中的存储配置,不一定适用于当前版本。设置 `storage-driver: overlay2` 或修改 `data-root` 前,先确认 Docker 实际使用的存储方式。 按照 [Docker containerd image store 文档](https://docs.docker.com/engine/storage/containerd/),Engine 29.0 及以后版本的新安装默认使用 containerd image store。镜像内容和容器快照可能位于 `/var/lib/containerd`,其他 Docker 数据仍在 `/var/lib/docker`。 这种情况下,修改 [Docker 的 `data-root`](https://docs.docker.com/engine/daemon/)不会同时迁移 containerd 的存储目录,需要分别规划。 先查看当前配置和磁盘用量: ```bash sudo docker info sudo docker system df df -h df -ih ``` 各种服务还有各自的数据目录和数据卷,需要单独安排备份与恢复。遇到安装或启动问题时,先保留这些数据,查清原因后再处理,避免把重装软件变成数据丢失。 ## 其他 ### 完整的 fork 安装脚本快照 下面的脚本来自 [soulteary/docker-install](https://github.com/soulteary/docker-install/blob/f6ea53e5f8447c97d1b0d9eca8f2d5bab9637de2/install.sh),固定提交为 `f6ea53e5f8447c97d1b0d9eca8f2d5bab9637de2`,与前面的固定版本下载示例一致。 `install.sh` 大小为 24,847 字节,Git blob 为 `a759809fae73e15e5c6ce743acb048949d041f78`。脚本正文保留原始内容,采用 [Apache License 2.0](https://github.com/soulteary/docker-install/blob/f6ea53e5f8447c97d1b0d9eca8f2d5bab9637de2/LICENSE),并保留原始版权声明和 [NOTICE](https://github.com/soulteary/docker-install/blob/f6ea53e5f8447c97d1b0d9eca8f2d5bab9637de2/NOTICE)。 复制下面的完整代码块,从开头的 `(` 到结尾的 `)`,不要包含 Markdown 代码围栏。在普通用户的工作目录中执行,会保存 `get-docker-fork.sh`。这一步不需要 `sudo`,也不会安装 Docker。 保存命令会检查 SHA-256 和 Shell 语法。如果同名文件已经存在,命令会停止并保留旧文件。保存成功后,回到前面的脚本章节,查看内容、预演,再执行安装。 这个版本已经包含 `--setup-repo` 参数解析修复,可以与 `--dry-run` 一起使用,无需采用旧版的参数顺序规避写法。 复制时保留脚本中的 Tab、换行和结束标记。如果校验失败,先检查复制内容和对应版本,不要跳过校验继续安装。 ```bash ( set -eu umask 077 WORK="$(mktemp -d ./docker-install.XXXXXXXX)" trap 'rm -rf "$WORK"' EXIT cat > "$WORK/install.sh" <<'DOCKER_INSTALL_SNAPSHOT_EOF' #!/bin/sh set -e # Docker Engine for Linux installation script. # # This script is intended as a convenient way to configure docker's package # repositories and to install Docker Engine, This script is not recommended # for production environments. Before running this script, make yourself familiar # with potential risks and limitations, and refer to the installation manual # at https://docs.docker.com/engine/install/ for alternative installation methods. # # The script: # # - Requires `root` or `sudo` privileges to run. # - Attempts to detect your Linux distribution and version and configure your # package management system for you. # - Doesn't allow you to customize most installation parameters. # - Installs dependencies and recommendations without asking for confirmation. # - Installs the latest stable release (by default) of Docker CLI, Docker Engine, # Docker Buildx, Docker Compose, containerd, and runc. When using this script # to provision a machine, this may result in unexpected major version upgrades # of these packages. Always test upgrades in a test environment before # deploying to your production systems. # - Isn't designed to upgrade an existing Docker installation. When using the # script to update an existing installation, dependencies may not be updated # to the expected version, resulting in outdated versions. # # Source code is available at https://github.com/docker/docker-install/ # # Usage # ============================================================================== # # To install the latest stable versions of Docker CLI, Docker Engine, and their # dependencies: # # 1. download the script # # $ curl -fsSL https://get.docker.com -o install-docker.sh # # 2. verify the script's content # # $ cat install-docker.sh # # 3. run the script with --dry-run to verify the steps it executes # # $ sh install-docker.sh --dry-run # # 4. run the script either as root, or using sudo to perform the installation. # # $ sudo sh install-docker.sh # # Command-line options # ============================================================================== # # --version # Use the --version option to install a specific version, for example: # # $ sudo sh install-docker.sh --version 23.0 # # --channel # # Use the --channel option to install from an alternative installation channel. # The following example installs the latest versions from the "test" channel, # which includes pre-releases (alpha, beta, rc): # # $ sudo sh install-docker.sh --channel test # # Alternatively, use the script at https://test.docker.com, which uses the test # channel as default. # # --mirror # # Use the --mirror option to install from a mirror supported by this script. # Available mirrors are "Aliyun" (https://mirrors.aliyun.com/docker-ce), # "AzureChinaCloud" (https://mirror.azure.cn/docker-ce), and # "TencentCloud" (https://mirrors.cloud.tencent.com/docker-ce), for example: # # $ sudo sh install-docker.sh --mirror AzureChinaCloud # $ sudo sh install-docker.sh --mirror TencentCloud # # --setup-repo # # Use the --setup-repo option to configure Docker's package repositories without # installing Docker packages. This is useful when you want to add the repository # but install packages separately: # # $ sudo sh install-docker.sh --setup-repo # # Automatic Service Start # # By default, this script automatically starts the Docker daemon and enables the docker # service after installation if systemd is used as init. # # If you prefer to start the service manually, use the --no-autostart option: # # $ sudo sh install-docker.sh --no-autostart # # Note: Starting the service requires appropriate privileges to manage system services. # # Installing docker-sbx # # Set the SBX environment variable to "1" to also install the docker-sbx # package alongside the regular Docker Engine packages: # # $ curl -fsSL https://get.docker.com | sudo SBX=1 sh # # ============================================================================== # Git commit from https://github.com/docker/docker-install when # the script was uploaded (Should only be modified by upload job): SCRIPT_COMMIT_SHA="${LOAD_SCRIPT_COMMIT_SHA}" # strip "v" prefix if present VERSION="${VERSION#v}" # The channel to install from: # * stable # * test DEFAULT_CHANNEL_VALUE="stable" if [ -z "$CHANNEL" ]; then CHANNEL=$DEFAULT_CHANNEL_VALUE fi DEFAULT_DOWNLOAD_URL="https://download.docker.com" if [ -z "$DOWNLOAD_URL" ]; then DOWNLOAD_URL=$DEFAULT_DOWNLOAD_URL fi DEFAULT_REPO_FILE="docker-ce.repo" if [ -z "$REPO_FILE" ]; then REPO_FILE="$DEFAULT_REPO_FILE" # Automatically default to a staging repo fora # a staging download url (download-stage.docker.com) case "$DOWNLOAD_URL" in *-stage*) REPO_FILE="docker-ce-staging.repo";; esac fi mirror='' DRY_RUN=${DRY_RUN:-} REPO_ONLY=${REPO_ONLY:-0} NO_AUTOSTART=${NO_AUTOSTART:-0} SBX=${SBX:-0} # Provide a helpful usage statement when --help or any invalid argument is passed # to the script. Exit code deliberately not included here as error depends on # argument provided. usage() { echo echo "USAGE: " echo " ${0} [--channel ] [--mirror ] [--version ] [--setup-repo] [--no-autostart] [--dry-run] [--help]" echo } while [ $# -gt 0 ]; do case "$1" in --channel) CHANNEL="$2" shift ;; --dry-run) DRY_RUN=1 ;; --mirror) mirror="$2" shift ;; --version) VERSION="${2#v}" shift ;; --setup-repo) REPO_ONLY=1 shift ;; --no-autostart) NO_AUTOSTART=1 ;; --help) usage exit 0 ;; --*) echo "Illegal option $1" usage exit 1 ;; esac shift $(( $# > 0 ? 1 : 0 )) done case "$mirror" in Aliyun) DOWNLOAD_URL="https://mirrors.aliyun.com/docker-ce" ;; AzureChinaCloud) DOWNLOAD_URL="https://mirror.azure.cn/docker-ce" ;; TencentCloud) DOWNLOAD_URL="https://mirrors.cloud.tencent.com/docker-ce" ;; "") ;; *) >&2 echo "unknown mirror '$mirror': use 'Aliyun', 'AzureChinaCloud', or 'TencentCloud'." exit 1 ;; esac case "$CHANNEL" in stable|test) ;; *) >&2 echo "unknown CHANNEL '$CHANNEL': use either stable or test." exit 1 ;; esac command_exists() { command -v "$@" > /dev/null 2>&1 } # Quote one argument for commands executed through the POSIX shell in $sh_c. # A closing quote preserves trailing newlines when the result is captured. shell_quote() ( value=$1 printf "'" while :; do case "$value" in *"'"*) printf '%s' "${value%%\'*}" "'\''" value=${value#*\'} ;; *) printf "%s'" "$value" break ;; esac done ) # version_gte checks if the version specified in $VERSION is at least the given # SemVer (Maj.Minor[.Patch]), or CalVer (YY.MM) version.It returns 0 (success) # if $VERSION is either unset (=latest) or newer or equal than the specified # version, or returns 1 (fail) otherwise. # # examples: # # VERSION=23.0 # version_gte 23.0 // 0 (success) # version_gte 20.10 // 0 (success) # version_gte 19.03 // 0 (success) # version_gte 26.1 // 1 (fail) version_gte() { if [ -z "$VERSION" ]; then return 0 fi version_compare "$VERSION" "$1" } # version_compare compares two version strings (either SemVer (Major.Minor.Path), # or CalVer (YY.MM) version strings. It returns 0 (success) if version A is newer # or equal than version B, or 1 (fail) otherwise. Patch releases and pre-release # (-alpha/-beta) are not taken into account # # examples: # # version_compare 23.0.0 20.10 // 0 (success) # version_compare 23.0 20.10 // 0 (success) # version_compare 20.10 19.03 // 0 (success) # version_compare 20.10 20.10 // 0 (success) # version_compare 19.03 20.10 // 1 (fail) version_compare() ( set +x yy_a="$(echo "$1" | cut -d'.' -f1)" yy_b="$(echo "$2" | cut -d'.' -f1)" if [ "$yy_a" -lt "$yy_b" ]; then return 1 fi if [ "$yy_a" -gt "$yy_b" ]; then return 0 fi mm_a="$(echo "$1" | cut -d'.' -f2)" mm_b="$(echo "$2" | cut -d'.' -f2)" # trim leading zeros to accommodate CalVer mm_a="${mm_a#0}" mm_b="${mm_b#0}" if [ "${mm_a:-0}" -lt "${mm_b:-0}" ]; then return 1 fi return 0 ) # Select the first APT package version matching a literal Docker version prefix. # Restrict matching to madison's version field, ignoring the epoch and distro # suffix. Require a component boundary so 24.0.1 cannot select 24.0.10. # Debian packages use "~" for Docker's "-ce" and pre-release separators. # Repository ordering is preserved, including the existing test-channel behavior. select_apt_package_version() ( # An embedded newline would give grep multiple expressions and could turn a # later fragment into an unanchored match. Invalid pins must select nothing. case "$1" in *' '*) return ;; esac pkg_pattern="$(printf '%s\n' "$1" | sed 's/-/~/g; s/[][\\.^$*+?(){}|]/\\&/g')" awk -F '|' '{gsub(/^[ \t]+|[ \t]+$/, "", $2); print $2}' | grep -E "^([0-9]+:)?$pkg_pattern([.~+-]|$)" | head -1 ) is_dry_run() { if [ -z "$DRY_RUN" ]; then return 1 else return 0 fi } is_wsl() { case "$(uname -r)" in *microsoft* ) true ;; # WSL 2 *Microsoft* ) true ;; # WSL 1 * ) false;; esac } is_darwin() { case "$(uname -s)" in *darwin* ) true ;; *Darwin* ) true ;; * ) false;; esac } deprecation_notice() { distro=$1 distro_version=$2 echo printf "\033[91;1mDEPRECATION WARNING\033[0m\n" 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" echo " No updates or security fixes will be released for this distribution, and users are recommended" echo " to upgrade to a currently maintained version of $distro." echo printf "Press \033[1mCtrl+C\033[0m now to abort this script, or wait for the installation to continue." echo sleep 10 } get_distribution() { lsb_dist="" # Every system that we officially support has /etc/os-release if [ -r /etc/os-release ]; then lsb_dist="$(. /etc/os-release && echo "$ID")" fi # Normalize Fedora Asahi Remix to fedora if [ "$lsb_dist" = "fedora-asahi-remix" ]; then lsb_dist="fedora" fi # Returning an empty string here should be alright since the # case statements don't act unless you provide an actual value echo "$lsb_dist" } start_docker_daemon() { # Use systemctl if available (for systemd-based systems) if command_exists systemctl; then is_dry_run || >&2 echo "Using systemd to manage Docker service" if ( is_dry_run || set -x $sh_c "systemctl enable --now docker.service 2>/dev/null" ); then is_dry_run || echo "INFO: Docker daemon enabled and started" >&2 else is_dry_run || echo "WARNING: unable to enable the docker service" >&2 fi else # No service management available (container environment) if ! is_dry_run; then >&2 echo "Note: Running in a container environment without service management" >&2 echo "Docker daemon cannot be started automatically in this environment" >&2 echo "The Docker packages have been installed successfully" fi fi >&2 echo } echo_docker_as_nonroot() { if is_dry_run; then return fi if command_exists docker && [ -e /var/run/docker.sock ]; then ( set -x $sh_c 'docker version' ) || true fi # intentionally mixed spaces and tabs here -- tabs are stripped by "<<-EOF", spaces are kept in the output echo echo "================================================================================" echo if version_gte "20.10"; then echo "To run Docker as a non-privileged user, consider setting up the" echo "Docker daemon in rootless mode for your user:" echo echo " dockerd-rootless-setuptool.sh install" echo echo "Visit https://docs.docker.com/go/rootless/ to learn about rootless mode." echo fi echo echo "To run the Docker daemon as a fully privileged service, but granting non-root" echo "users access, refer to https://docs.docker.com/go/daemon-access/" echo echo "WARNING: Access to the remote API on a privileged Docker daemon is equivalent" echo " to root access on the host. Refer to the 'Docker daemon attack surface'" echo " documentation for details: https://docs.docker.com/go/attack-surface/" echo echo "================================================================================" echo } # Check if this is a forked Linux distro check_forked() { # Check for lsb_release command existence, it usually exists in forked distros if command_exists lsb_release; then # A successful upstream probe means we're in a forked distro. if lsb_release -a -u > /dev/null 2>&1; then # Print info about current distro cat <<-EOF You're using '$lsb_dist' version '$dist_version'. EOF # Get the upstream release info lsb_dist=$(lsb_release -a -u 2>&1 | tr '[:upper:]' '[:lower:]' | grep -E 'id' | cut -d ':' -f 2 | tr -d '[:space:]') dist_version=$(lsb_release -a -u 2>&1 | tr '[:upper:]' '[:lower:]' | grep -E 'codename' | cut -d ':' -f 2 | tr -d '[:space:]') # Print info about upstream distro cat <<-EOF Upstream release is '$lsb_dist' version '$dist_version'. EOF else if [ -r /etc/debian_version ] && [ "$lsb_dist" != "ubuntu" ] && [ "$lsb_dist" != "raspbian" ]; then if [ "$lsb_dist" = "osmc" ]; then # OSMC runs Raspbian lsb_dist=raspbian else # We're Debian and don't even know it! lsb_dist=debian fi dist_version="$(sed 's/\/.*//' /etc/debian_version | sed 's/\..*//')" case "$dist_version" in 13|14|forky) dist_version="trixie" ;; 12) dist_version="bookworm" ;; 11) dist_version="bullseye" ;; 10) dist_version="buster" ;; 9) dist_version="stretch" ;; 8) dist_version="jessie" ;; esac fi fi fi } do_install() { echo "# Executing docker install script, commit: $SCRIPT_COMMIT_SHA" if [ "$REPO_ONLY" != "1" ] && command_exists docker; then cat >&2 <<-'EOF' Warning: the "docker" command appears to already exist on this system. If you already have Docker installed, this script can cause trouble, which is why we're displaying this warning and provide the opportunity to cancel the installation. If you installed the current Docker package using this script and are using it again to update Docker, you can ignore this message, but be aware that the script resets any custom changes in the deb and rpm repo configuration files to match the parameters passed to the script. You may press Ctrl+C now to abort this script. EOF ( set -x; sleep 20 ) fi user="$(id -un 2>/dev/null || true)" sh_c='sh -c' if [ "$user" != 'root' ]; then if command_exists sudo; then sh_c='sudo -E sh -c' elif command_exists su; then sh_c='su -c' else cat >&2 <<-'EOF' Error: this installer needs the ability to run commands as root. We are unable to find either "sudo" or "su" available to make this happen. EOF exit 1 fi fi if is_dry_run; then sh_c="echo" fi # perform some very rudimentary platform detection lsb_dist=$( get_distribution ) lsb_dist="$(echo "$lsb_dist" | tr '[:upper:]' '[:lower:]')" if is_wsl; then echo echo "WSL DETECTED: We recommend using Docker Desktop for Windows." echo "Please get Docker Desktop from https://www.docker.com/products/docker-desktop/" echo cat >&2 <<-'EOF' You may press Ctrl+C now to abort this script. EOF ( set -x; sleep 20 ) fi case "$lsb_dist" in ubuntu) if command_exists lsb_release; then dist_version="$(lsb_release --codename | cut -f2)" fi if [ -z "$dist_version" ] && [ -r /etc/lsb-release ]; then dist_version="$(. /etc/lsb-release && echo "$DISTRIB_CODENAME")" fi ;; debian|raspbian) dist_version="$(sed 's/\/.*//' /etc/debian_version | sed 's/\..*//')" case "$dist_version" in 13) dist_version="trixie" ;; 12) dist_version="bookworm" ;; 11) dist_version="bullseye" ;; 10) dist_version="buster" ;; 9) dist_version="stretch" ;; 8) dist_version="jessie" ;; esac ;; centos|rhel|rocky) if [ -z "$dist_version" ] && [ -r /etc/os-release ]; then dist_version="$(. /etc/os-release && echo "$VERSION_ID")" fi ;; *) if command_exists lsb_release; then dist_version="$(lsb_release --release | cut -f2)" fi if [ -z "$dist_version" ] && [ -r /etc/os-release ]; then dist_version="$(. /etc/os-release && echo "$VERSION_ID")" fi ;; esac # Check if this is a forked Linux distro check_forked # Print deprecation warnings for distro versions that recently reached EOL, # but may still be commonly used (especially LTS versions). case "$lsb_dist.$dist_version" in centos.8|centos.7|rhel.7) deprecation_notice "$lsb_dist" "$dist_version" ;; debian.bullseye|debian.buster|debian.stretch|debian.jessie) deprecation_notice "$lsb_dist" "$dist_version" ;; raspbian.buster|raspbian.stretch|raspbian.jessie) deprecation_notice "$lsb_dist" "$dist_version" ;; ubuntu.focal|ubuntu.bionic|ubuntu.xenial|ubuntu.trusty) deprecation_notice "$lsb_dist" "$dist_version" ;; ubuntu.questing|ubuntu.oracular|ubuntu.mantic|ubuntu.lunar|ubuntu.kinetic|ubuntu.impish|ubuntu.hirsute|ubuntu.groovy|ubuntu.eoan|ubuntu.disco|ubuntu.cosmic) deprecation_notice "$lsb_dist" "$dist_version" ;; fedora.*) if [ "$dist_version" -lt 43 ]; then deprecation_notice "$lsb_dist" "$dist_version" fi ;; esac # Run setup for each distro accordingly case "$lsb_dist" in ubuntu|debian|raspbian) pre_reqs="ca-certificates curl" apt_repo_lsb_dist="$lsb_dist" # Docker does not publish a Raspbian Trixie repo; use Debian Trixie instead. if [ "$lsb_dist" = "raspbian" ] && [ "$dist_version" = "trixie" ]; then apt_repo_lsb_dist="debian" fi apt_repo="deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] $DOWNLOAD_URL/linux/$apt_repo_lsb_dist $dist_version $CHANNEL" ( if ! is_dry_run; then set -x fi $sh_c 'apt-get -qq update >/dev/null' $sh_c "DEBIAN_FRONTEND=noninteractive apt-get -o DPkg::Lock::Timeout=60 -y -qq install $pre_reqs >/dev/null" $sh_c 'install -m 0755 -d /etc/apt/keyrings' $sh_c "curl -fsSL \"$DOWNLOAD_URL/linux/$apt_repo_lsb_dist/gpg\" -o /etc/apt/keyrings/docker.asc" $sh_c "chmod a+r /etc/apt/keyrings/docker.asc" $sh_c "echo \"$apt_repo\" > /etc/apt/sources.list.d/docker.list" $sh_c 'apt-get -qq update >/dev/null' ) if [ "$REPO_ONLY" = "1" ]; then exit 0 fi pkg_version="" cli_pkg_version="" if [ -n "$VERSION" ]; then if is_dry_run; then echo "# WARNING: VERSION pinning is not supported in DRY_RUN" else search_command="apt-cache madison docker-ce" echo "INFO: Searching repository for VERSION '$VERSION'" echo "INFO: $search_command" pkg_version="$($sh_c "$search_command" | select_apt_package_version "$VERSION")" if [ -z "$pkg_version" ]; then echo echo "ERROR: '$VERSION' not found amongst apt-cache madison results" echo exit 1 fi pkg_version="=$pkg_version" if version_gte "18.09"; then search_command="apt-cache madison docker-ce-cli" echo "INFO: $search_command" cli_pkg_version="$($sh_c "$search_command" | select_apt_package_version "$VERSION")" if [ -n "$cli_pkg_version" ]; then cli_pkg_version="=$cli_pkg_version" fi fi fi fi ( pkgs="docker-ce${pkg_version}" if version_gte "18.09"; then # older versions didn't ship the cli and containerd as separate packages pkgs="$pkgs docker-ce-cli${cli_pkg_version} containerd.io" fi if version_gte "20.10"; then pkgs="$pkgs docker-compose-plugin docker-ce-rootless-extras$pkg_version" fi if version_gte "23.0"; then pkgs="$pkgs docker-buildx-plugin" fi if version_gte "28.2"; then pkgs="$pkgs docker-model-plugin" fi if [ "$SBX" = "1" ]; then pkgs="$pkgs docker-sbx" fi if ! is_dry_run; then set -x fi apt_flags="-y -qq" if [ -n "$pkg_version" ]; then apt_flags="$apt_flags --allow-downgrades" fi $sh_c "DEBIAN_FRONTEND=noninteractive apt-get -o DPkg::Lock::Timeout=60 $apt_flags install $pkgs >/dev/null" ) if [ "$NO_AUTOSTART" != "1" ]; then start_docker_daemon fi echo_docker_as_nonroot exit 0 ;; centos|fedora|rhel|rocky) repo_file_url="$DOWNLOAD_URL/linux/$lsb_dist/$REPO_FILE" repo_file_url_quoted=$(shell_quote "$repo_file_url") ( if ! is_dry_run; then set -x fi if command_exists dnf5; then $sh_c "dnf -y -q --setopt=install_weak_deps=False install dnf-plugins-core" $sh_c "dnf5 config-manager addrepo --overwrite --save-filename=docker-ce.repo --from-repofile=$repo_file_url_quoted" if [ "$CHANNEL" != "stable" ]; then $sh_c "dnf5 config-manager setopt \"docker-ce-*.enabled=0\"" $sh_c "dnf5 config-manager setopt \"docker-ce-$CHANNEL.enabled=1\"" fi $sh_c "dnf makecache" elif command_exists dnf; then $sh_c "dnf -y -q --setopt=install_weak_deps=False install dnf-plugins-core" $sh_c "rm -f /etc/yum.repos.d/docker-ce.repo /etc/yum.repos.d/docker-ce-staging.repo" $sh_c "dnf config-manager --add-repo $repo_file_url_quoted" if [ "$CHANNEL" != "stable" ]; then $sh_c "dnf config-manager --set-disabled \"docker-ce-*\"" $sh_c "dnf config-manager --set-enabled \"docker-ce-$CHANNEL\"" fi $sh_c "dnf makecache" else $sh_c "yum -y -q install yum-utils" $sh_c "rm -f /etc/yum.repos.d/docker-ce.repo /etc/yum.repos.d/docker-ce-staging.repo" $sh_c "yum-config-manager --add-repo $repo_file_url_quoted" if [ "$CHANNEL" != "stable" ]; then $sh_c "yum-config-manager --disable \"docker-ce-*\"" $sh_c "yum-config-manager --enable \"docker-ce-$CHANNEL\"" fi $sh_c "yum makecache" fi ) if [ "$REPO_ONLY" = "1" ]; then exit 0 fi pkg_version="" cli_pkg_version="" if command_exists dnf; then pkg_manager="dnf" pkg_manager_flags="-y -q --best" else pkg_manager="yum" pkg_manager_flags="-y -q" fi if [ -n "$VERSION" ]; then if is_dry_run; then echo "# WARNING: VERSION pinning is not supported in DRY_RUN" else if [ "$lsb_dist" = "fedora" ]; then pkg_suffix="fc$dist_version" else pkg_suffix="el" fi pkg_pattern="$(echo "$VERSION" | sed 's/-ce-/\\\\.ce.*/g' | sed 's/-/.*/g').*$pkg_suffix" search_command="$pkg_manager list --showduplicates docker-ce | grep '$pkg_pattern' | tail -1 | awk '{print \$2}'" echo "INFO: Searching repository for VERSION '$VERSION'" echo "INFO: $search_command" pkg_version="$($sh_c "$search_command")" if [ -z "$pkg_version" ]; then echo echo "ERROR: '$VERSION' not found amongst $pkg_manager list results" echo exit 1 fi # Cut out the epoch and prefix with a '-' pkg_version="-$(echo "$pkg_version" | cut -d':' -f 2)" if version_gte "18.09"; then # older versions don't support a cli package search_command="$pkg_manager list --showduplicates docker-ce-cli | grep '$pkg_pattern' | tail -1 | awk '{print \$2}'" cli_pkg_version="$($sh_c "$search_command" | cut -d':' -f 2)" fi fi fi ( pkgs="docker-ce$pkg_version" if version_gte "18.09"; then # older versions didn't ship the cli and containerd as separate packages if [ -n "$cli_pkg_version" ]; then pkgs="$pkgs docker-ce-cli-$cli_pkg_version containerd.io" else pkgs="$pkgs docker-ce-cli containerd.io" fi fi if version_gte "20.10"; then pkgs="$pkgs docker-compose-plugin docker-ce-rootless-extras$pkg_version" fi if version_gte "23.0"; then pkgs="$pkgs docker-buildx-plugin docker-model-plugin" fi if [ "$SBX" = "1" ]; then pkgs="$pkgs docker-sbx" fi if ! is_dry_run; then set -x fi $sh_c "$pkg_manager $pkg_manager_flags install $pkgs" ) if [ "$NO_AUTOSTART" != "1" ]; then start_docker_daemon fi echo_docker_as_nonroot exit 0 ;; sles) echo "Effective v27.5, please consult SLES distro statement for s390x support." exit 1 ;; *) if [ -z "$lsb_dist" ]; then if is_darwin; then echo echo "ERROR: Unsupported operating system 'macOS'" echo "Please get Docker Desktop from https://www.docker.com/products/docker-desktop" echo exit 1 fi fi echo echo "ERROR: Unsupported distribution '$lsb_dist'" echo exit 1 ;; esac exit 1 } # wrapped up in a function so that we have some protection against only getting # half the file during "curl | sh" do_install DOCKER_INSTALL_SNAPSHOT_EOF printf '%s %s\n' \ 'fdae16d31d2a87d0056fec49454a2e1475230abe64c52ad900efb65e425399ef' \ "$WORK/install.sh" | sha256sum -c - sh -n "$WORK/install.sh" ln "$WORK/install.sh" ./get-docker-fork.sh printf '%s\n' '脚本已保存为 get-docker-fork.sh;尚未执行安装。' ) ``` 保存完成后,回到「也可以使用安装脚本」,审阅、预演,再选一套安装命令执行。 ### 选择 main 或固定版本? 如果希望获取后续维护的脚本,可以使用 `main` 分支。需要与本文附录保持一致,则使用下面这个[包含参数解析修复的固定提交](https://github.com/soulteary/docker-install/blob/f6ea53e5f8447c97d1b0d9eca8f2d5bab9637de2/install.sh): ```text f6ea53e5f8447c97d1b0d9eca8f2d5bab9637de2 ``` 对应 `install.sh` 的 SHA-256 为: ```text 2b9273b4c126ee83f2cf4eea558f415ab0e16c8c946ca7898bd426ac0d819ab2 ``` 下面的命令会下载固定版本,检查校验和与语法,再保存脚本。它与前面的 `main` 下载方式二选一,同样不会覆盖已有文件: ```bash ( set -eu umask 077 WORK="$(mktemp -d ./docker-install.XXXXXXXX)" trap 'rm -rf "$WORK"' EXIT curl -q -fsSL --proto '=https' --proto-redir '=https' \ --connect-timeout 10 --max-time 120 \ https://raw.githubusercontent.com/soulteary/docker-install/f6ea53e5f8447c97d1b0d9eca8f2d5bab9637de2/install.sh \ -o "$WORK/install.sh" test -s "$WORK/install.sh" printf '%s %s\n' \ '2b9273b4c126ee83f2cf4eea558f415ab0e16c8c946ca7898bd426ac0d819ab2' \ "$WORK/install.sh" | sha256sum -c - sh -n "$WORK/install.sh" ln "$WORK/install.sh" ./get-docker-fork.sh printf '%s\n' '脚本已保存为 get-docker-fork.sh;尚未执行安装。' ) ``` 这个校验值只对应上述固定提交。`main` 更新后,文件内容和校验值都可能变化,不能继续拿这里的值校验新文件。 SHA-256 用于检查下载或复制的内容是否一致,预期校验值也需要来自可信渠道。它不能替代作者签名或脚本审阅。 固定脚本版本后,最终安装的软件包仍可能变化。未指定版本时,脚本会从软件源选择软件包,`--version` 也不会锁定全部依赖和插件。需要复现安装环境时,把实际软件包版本、架构、软件源和验证结果一起记录下来。 ### fork 中的其他调整 除了腾讯云参数和参数解析修复,这个版本还调整了 dpkg 锁等待、APT 版本匹配、RPM 仓库 URL 参数引用,以及衍生发行版的上游探测。具体改动和测试范围可以查看[仓库说明](https://github.com/soulteary/docker-install/blob/f6ea53e5f8447c97d1b0d9eca8f2d5bab9637de2/README.md)。 APT 安装命令加入了 `DPkg::Lock::Timeout=60`,用于等待 dpkg 锁,最多等待 60 秒。这个设置不限制整个安装过程,也不覆盖 `apt-get update` 使用的索引锁。遇到锁占用,先确认系统初始化或自动更新是否仍在运行,等它完成,不要直接删除锁文件。 [脚本默认安装的组件](https://github.com/soulteary/docker-install/blob/f6ea53e5f8447c97d1b0d9eca8f2d5bab9637de2/install.sh)可能比前面的手动 APT 方案多,包括 rootless extras、Model 插件等。某个附加包找不到时,先对照预演输出检查镜像站同步情况。自行删掉报错包再继续,会改变原本的安装内容。 下载 `install.sh` 后可以直接使用,无需先执行 `make build`。未设置构建变量 `LOAD_SCRIPT_COMMIT_SHA` 时,脚本开头的 `commit:` 可能为空,不影响软件源选择。这个值也能通过环境变量设置,追溯版本时,仍以保存的来源提交和文件校验值为准。 ## 最后 当我们将脚本下载、软件包安装和容器镜像拉取分开检查,遇到网络问题时,会少走一些弯路。 Docker 的配置和安装聊到这里,基础准备就差不多了。后面再继续折腾具体应用的时候,把应用权限、持久化和备份再一起配好。 这篇文章就先写到这里吧。 —EOF