ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Ubuntu 22.04 安装 Docker 实战:apt 源配置、Compose v2 与镜像加速全指南

Ubuntu 22.04 安装 Docker 实战:apt 源配置、Compose v2 与镜像加速全指南 每次帮同事处理 Ubuntu 服务器上的 Docker 问题我都习惯性会问一句你是自己手动装的还是用了个什么脚本这个问题的答案基本决定了后面半小时是轻松收工还是开始排雷。网上搜“Ubuntu22.04 安装 Docker”出来的教程确实多但不少还停留在老一套一键脚本装完不知道装的是哪个版本、docker-compose和docker compose两个命令混着用、装完拉镜像慢到怀疑人生、容器 network 出问题不知道怎么查。这篇我把自己在 Ubuntu 22.04 上反复验证过的一套安装流程完整写出来覆盖 Docker 引擎、Docker Compose v2 插件、镜像加速配置以及我踩过之后整理了排查思路的几个高频报错。无论你是第一次在新机器上装还是已经被各种错误信息卡到心累照着这套走基本能避开大部分坑。1. 装之前先把三件事想清楚版本、方式和残留1.1 先确认系统版本和 CPU 架构任何安装教程的第一步都该是先看清楚自己站在哪块地上。Ubuntu 22.04 的代号是 jammy这个代号在后面添加软件源时会被直接用上。lsb_release -a cat /etc/os-release我一般直接看cat /etc/os-release里面VERSION_CODENAMEjammy这一行比较关键。再看一下 CPU 架构uname -mx86_64 对应 AMD64 架构aarch64 对应 ARM64。国内很多云服务器是 x86_64但树莓派、飞腾、鲲鹏这些 ARM 机器也不少见。架构直接决定了后面 apt 源里arch参数的值所以先确认没有坏处。内核版本方面Ubuntu 22.04 默认内核是 5.15Docker 要求的内核最低版本早就覆盖到了不用刻意升级内核。不过如果你的机器是从老版本 LTS 一路升上来、内核还停留在 4.x那先别急着装 Docker把系统完整升级一遍再继续。1.2 为什么我不用一键脚本也不用 snap 版本你可能会问Docker 官网上不是有curl -fsSL https://get.docker.com -o get-docker.sh这种一键脚本吗为什么不用我用它装过几次确实快但有几个让我不太放心的地方第一脚本会自动判断系统然后配置源并安装整个过程像黑盒出了问题你很难知道它到底改了什么卸载的时候更是两眼一摸黑。第二它安装的版本取决于脚本发布时的指向可能不是你预期中的那个稳定版本。第三一键脚本在有些精简版系统上还会顺手改掉一些网络配置比如iptables的默认策略装完可能留下一堆你并不希望发生的改动。snap 版的 Docker 我也试过它的问题是运行和隔离方式跟传统 systemd 服务有点区别在部分服务器上会导致 systemctl 管理 docker 的体验很奇怪而且 snap 包默认的刷新策略有可能会半夜自动升级 Docker 版本这在生产环境里并不让人省心。我的选择是用 Docker 官方维护的 apt 仓库安装。这样装出来的是标准 deb 包能被apt-get upgrade统一管理也能用apt remove docker-ce干干净净卸载版本锁定和回滚都方便。下面这个表格是三种方式的直接对比安装方式优点缺点官方 apt 仓库标准 deb 包可卸载、可锁版本和 systemd 配合正常需要多敲几步命令get.docker.com 脚本一次执行完看起来省事黑盒式改动卸载困难行为不可控snap install docker命令简单自动刷新存在变数systemd 关联不直观部分功能受限1.3 清掉历史残留再动手如果你之前已经用 apt 装过 docker、docker.io、containerd 这类包先清理掉不然新老版本会互相干扰。sudo apt-get remove docker docker-engine docker.io containerd runc如果之前用二进制方式或者手动装过 Docker Engine还要手动确认一下是否有残留进程which -a docker ps aux | grep dockerd这些命令会告诉你当前系统里是不是已经有 docker 可执行文件在跑。如果查到/usr/bin/docker和/usr/local/bin/docker同时存在一定先处理掉非 apt 的那份再继续。有一点必须提醒除非你已经明确决定放弃所有容器镜像和容器数据否则别在这个阶段直接删/var/lib/docker目录。这个目录存放所有镜像层、容器层和卷数据删了就真没了。卸载不解决问题的数据问题完全可以留到确认不需要时再做处理。2. 正式安装 Docker 引擎我固定使用的 apt 流程2.1 导入 GPG key 并创建 apt 源二维码没意思直接讲命令背后的逻辑。Docker 官方 apt 仓库为了保证包安全所有 Release 文件都用 GPG 签名。我们需要先把官方 GPG key 下载下来转成 apt 能识别的 keyring 文件再在 sources.list 里通过signed-by指定它。sudo apt-get update sudo apt-get install -y ca-certificates curl gnupg lsb-release sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod ar /etc/apt/keyrings/docker.gpg echo deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null sudo apt-get update逐行说几个细节。sudo install -m 0755 -d /etc/apt/keyrings这行是很多老教程里没有的。早期 Docker 文档推荐直接用gpg --dearmor输出到/usr/share/keyrings但为了统一干净现在官方文档从 22.04 起推荐独立使用/etc/apt/keyrings目录并设置 0755 权限。如果没有这个目录后面 curl 管道输出的重定向可能会因为找不到路径失败。$(dpkg --print-architecture)会自动输出 amd64 或 arm64这比手工写死amd64稳妥。$(lsb_release -cs)在 22.04 上会输出jammy。如果之前装了 lsb-release直接可用。还有一个注意点如果apt-get update更新官方 Docker 仓库时一直落在download.docker.com上超时那是这条源的问题不是后面镜像加速能解决的。这种情况下可以考虑把源地址换成国内的 docker-ce 镜像源比如清华或阿里云维护的 docker-ce 仓库这是另一套配置不影响后面 registry mirror 的设置。不过并不建议一上来就换很多网络环境下官方源本身是通的。2.2 一次性安装五个核心组件源配置好之后直接装sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin这里我把 docker-buildx-plugin 和 docker-compose-plugin 一起装了。很多教程只写 docker-ce 和 docker-ce-cli装完发现docker buildx和docker compose都不存在。这几个包各自负责什么docker-ceDocker 引擎守护进程也就是 dockerd。docker-ce-clidocker 命令行工具。containerd.io容器运行时dockerd 底层通过它管理容器生命周期。docker-buildx-plugin构建镜像的核心插件负责 BuildKit 支持。docker-compose-pluginDocker Compose v2 的官方插件命令是docker compose。2.3 启动服务并跑通第一个容器装完立刻启动并设置开机自启sudo systemctl enable --now docker sudo systemctl status docker如果一切正常你会看到服务状态是 active (running)。然后跑一下官方提供的最小测试镜像sudo docker run hello-worldhello-world是一个极小镜像拉取下来后会启动一个容器并打印一段提示然后退出。看到提示说明守护进程能正常工作。如果卡在 Pulling 那一步先去看后面第 4 节的镜像加速配置大概率是网络问题。3. 权限、开机自启和 Compose v2 插件一次配好3.1 让普通用户免 sudo 操作 docker默认情况下操作 docker 命令需要 root 权限因为 docker CLI 是通过/var/run/docker.sock与守护进程通信的这个 socket 的所有者是 root。执行sudo usermod -aG docker $USER把当前用户加进 docker 用户组。然后必须重新登录注销当前会话或重新连接 SSH组权限才会生效。验证方式id -nG输出里能看到docker就算成功。如果重新登录后 docker 命令还提示权限不足多半是当前 SSH 会话的组缓存没刷新可以试试newgrp docker或者干脆重开一个连接。我不建议通过chmod 666 /var/run/docker.sock或手动改 socket 权限来解决问题那是把守护进程完全裸露给所有本地用户安全风险极高。docker 用户组是官方推荐的正规做法安全边界也清晰得多。3.2 Docker Compose v2同一个命令的两种身份这是最容易踩坑的地方。Docker Compose v2 现在是 Go 语言实现的插件使用方式是docker compose version注意是docker compose中间有空格连字符版本是老一代 Python 实现的docker-compose命令。v2 插件已经包含在上一步安装的docker-compose-plugin包里所以你不需要再去 pip install docker-compose。我见过不少人在 22.04 上装完 Docker然后习惯性地curl -L ... docker-compose-Linux-x86_64下载一个 v1 二进制到/usr/local/bin/docker-compose再继续用连字符命令。这会导致系统中同时存在docker compose和docker-compose两套工具compose.yaml 文件的字段解析逻辑和不一致问题会在后续逐步暴露。如果确实还需要旧版兼容可以用 Compose v1 的独立二进制但我建议新项目统一用docker compose。验证 v2 插件是否生效docker compose version能看到类似Docker Compose version v2.x.x的输出就没问题。3.3 systemd 开机自启的完整配置刚才已经执行过systemctl enable --now docker它的作用是把 docker 服务设置为开机启动并立即启动。containerd 也一样处理sudo systemctl enable containerd虽然 docker 服务在启动时会拉起 containerd但显式 enable 可以避免某些系统环境下服务依赖不完整的问题。确认状态systemctl is-enabled docker systemctl is-enabled containerd两个都是 enabled 就正常。4. 镜像加速和 daemon.json装完马上做的一件事4.1 registry-mirrors 到底怎么配Ubuntu 22.04 装好 Docker 后第一件不要拖延的事情就是配置 registry mirror。原因很简单没有加速的情况下docker pull拉镜像分分钟超时尤其是刚接触 Docker 想跑第一个 Nginx 的时候。Docker 守护进程的全局配置文件是/etc/docker/daemon.json。这个文件默认不存在需要自己创建。sudo vim /etc/docker/daemon.json写入{ registry-mirrors: [ https://docker.mirrors.ustc.edu.cn, https://hub-mirror.c.163.com ] }注意这些公共镜像站地址可能因运营策略变更而失效实际用时最好确认当前可用的加速地址。如果你用的是云厂商服务器比如阿里云或腾讯云可以在容器镜像服务控制台里找到分配给你的专属加速地址那种个人专属地址一般更稳定。写 JSON 的时候要特别小心不能有注释不能有尾逗号否则 docker 启动时解析失败直接起不来。写完后可以用下面命令校验python3 -m json.tool /etc/docker/daemon.json4.2 顺手把日志轮转也做了有一个坑在没有预兆的情况下经常爆某个容器日志一直在写把/var/lib/docker所在磁盘塞满整个服务器所有服务开始报“磁盘空间不足”。所以我会在 daemon.json 里顺手加上日志轮转配置{ registry-mirrors: [ https://docker.mirrors.ustc.edu.cn, https://hub-mirror.c.163.com ], log-driver: json-file, log-opts: { max-size: 10m, max-file: 3 } }这表示每个容器的单个日志文件超过 10MB 时自动滚动最多保留 3 个文件。改完配置重启 Dockersudo systemctl restart docker验证配置是否生效docker info | grep -A 2 Registry Mirrors docker info | grep Logging Driver能看到镜像加速地址列表以及Logging Driver为json-file就算配置成功。顺便说一句daemon.json 里配置镜像加速只影响docker pull对 Docker Hub 的拉取不会影响前面 apt 源里的 download.docker.com。很多人在 apt update 卡住时以为是这里的问题这两个是完全不同的链路。5. 装完之后我最常用的一组命令5.1 镜像、容器、日志、清理速查装完 Docker 之后光有命令不算完关键是理解每个命令的作用。下面是我实际使用中最常用的一套组合。用途命令说明查看运行中的容器docker ps只显示 running 状态的容器查看所有容器docker ps -a包含已退出的容器查看镜像docker images列出本地所有镜像拉取镜像docker pull nginx从仓库拉取前台运行测试docker run --rm -it ubuntu bash用完即删适合测试后台运行docker run -d --name web -p 8080:80 nginx用 -d 进入后台查看日志docker logs -f --tail 100 web实时滚动最后 100 行进入容器docker exec -it web bash在运行中容器里开一个 shell停止/启动/重启docker stop web/docker start web/docker restart web容器生命周期管理清理失效容器docker rm $(docker ps -aq)谨慎使用会删所有停止容器清理悬空镜像docker image prune只删 dangling 镜像有一个习惯我强烈建议养着测试容器的时候只要不需要保留容器状态就加上--rm。这样容器退出后会自动删除不会让系统里堆满 Exited 状态的僵尸容器。docker run里的常用参数也说明一下-p 宿主机端口:容器端口做端口映射-v 宿主机目录:容器目录做数据卷挂载--restartalways设置容器异常退出后自动重启。初次配置服务时建议先不加--restartalways跑通命中了再加避免因为配置错误陷入重启循环。5.2 第一次跑 Nginx 和 MySQL 的实践样板跑一个 Nginx 试手常规操作docker run -d --name nginx-test -p 8080:80 nginx curl 127.0.0.1:8080生成出 HTML 页面就是正常的。跑数据库的时候不一样MySQL 必须挂载数据卷并设置环境变量docker run -d --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDyourpassword \ -v /data/mysql8:/var/lib/mysql \ mysql:8.0启动后先看docker logs mysql8确认没有报错再考虑用客户端连接。数据卷挂载的意义在于删除容器不会丢掉数据库数据这点在不上点心的人手里经常被忽略。6. 高频故障排查每一条我都走了一遍完整链路6.1 Cannot connect to the Docker daemon先分清两类原因这是新手遇到最多的报错完整内容是Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?这个报错就两种可能守护进程根本没启动或者当前用户没有访问 socket 的权限。我的排查顺序是固定的先看进程状态再看日志最后看权限。systemctl status docker systemctl start docker journalctl -u docker -n 50如果 service inactive启动它。如果启动失败journalctl 会给出真正原因。如果服务是 active 的但还是报这个错误那大概率是权限问题用id -nG确认自己是否在 docker 组里或者临时用sudo docker ps验证一下。还有一个容易忽略的情况你人在 A 机器上DOCKER_HOST环境变量却指向了 B 机器的地址或者残留了 Windows Docker Desktop 环境里的DOCKER_HOST。检查一下env | grep DOCKER如果 DOCKER_HOST 被设置了优先把它清掉再看。6.2 守护进程启动失败containerd 冲突、overlay2 和磁盘问题journalctl -u docker -n 100能看到类似failed to start containerd: ... failed to load plugin: ...这种情况先检查 containerd 版本和 Docker 版本是否匹配docker version containerd --version如果你是通过 apt 装的版本一般是自动对齐的。但如果之前系统里有 snap 或二进制残留的 containerd就可能出现两份 containerd 抢 socket 的情况。overlay2 存储驱动的问题也经常出现。Docker 默认存储驱动是 overlay2它要求宿主机文件系统是 ext4 或 xfs。如果/var/lib/docker所在分区是 btrfs、zfs 或者其他特殊文件系统Docker 可能会自动降级或直接起不来。可以用这个命令确认df -T /var/lib/docker文件系统类型不对的情况下要么换个挂载点要么换文件系统别硬扛。磁盘写满也是一个隐蔽原因。df -h看到 100%Docker 在写镜像或容器层时就会失败。可以先清理日志sudo sh -c truncate -s 0 /var/lib/docker/containers/*/*-json.log这是应急手段长期方案还得靠日志轮转和定时清理。6.3 容器内 ping 不通外网但宿主机能上网这个报错的排查链路比较重要因为它不是单点问题。我的习惯是先区分是网络不通还是 DNS 不通。先跑一个临时测试容器sudo docker run --rm alpine ping -c 3 8.8.8.8如果 8.8.8.8 能通说明容器网络和 NAT 没问题问题出在域名解析上。接着试sudo docker run --rm alpine ping -c 3 baidu.com域名不通而 IP 通就是 DNS 问题。Ubuntu 22.04 默认用 systemd-resolved宿主机上的/etc/resolv.conf会被链接到 127.0.0.53容器拿到这个地址后可能无法解析。解决办法是在 daemon.json 里直接指定一个可靠 DNS{ dns: [223.5.5.5, 8.8.8.8] }重启 docker 之后新创建的容器内部 DNS 就会使用这个配置。如果 IP 也不通那就是数据链路问题。常见原因有三个宿主机 net.ipv4.ip_forward 被设为 0iptables 规则被云平台初始化脚本改动防火墙软件截断了转发。依次排查sysctl net.ipv4.ip_forward sudo iptables -t nat -L -n | grep -i masquerade sudo systemctl status firewalldnet.ipv4.ip_forward应该是 1不是的话执行sudo sysctl -w net.ipv4.ip_forward1并写进/etc/sysctl.conf永久保存。iptables 的 nat 表里应该有 Docker 创建的 MASQUERADE 规则链如果规则丢了重启 Docker 服务通常能重建。6.4 配置了镜像加速拉镜像还是慢先确认 daemon.json 写的位置对不对。必须是/etc/docker/daemon.json不是用户目录不是 home 下的 docker 文件夹。写完后必须sudo systemctl restart docker重启后看:docker info输出里能直接看到Registry Mirrors列表。如果列表是空的说明配置没被加载先检查 JSON 是否合法。我见过不少人把注释写进了 JSON导致整个文件解析失败。还要注意一个问题镜像加速服务也有很多不同的实现不是每个镜像站都能覆盖所有热门仓库的镜像。万一某个加速源挂了或者同步慢多配几个备用的Docker Hub 会按顺序尝试。6.5 容器日志把磁盘塞满之后的应急与长效容器日志文件的位置在/var/lib/docker/containers/容器ID/*-json.log这几个文件可能轻松膨胀到几十 GB。临时清理可以这样sudo find /var/lib/docker/containers -name *-json.log -type f -size 100M -exec truncate -s 0 {} \;但只治标不治本。长效方案是第 4 节里配置的日志轮转再加下面两个定期命令docker system df docker system prunedocker system df查看磁盘占用分布docker system prune清理停止的容器、悬空镜像、无用网络。如果连构建缓存的垃圾都要清加-a但要注意这会删掉所有未被容器使用的镜像包括你可能之后还要用到的那些。7. 现在我在新机器上三分钟装完的流程这篇文档写到最后分享点真正实操层面的东西。因为装得多了我自己已经有一套固定的执行顺序基本可以在十分钟内完成全套安装和配置先确认系统和架构再把旧包清掉。创建/etc/apt/keyrings目录导入 GPG key写入 docker.list。apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin。立刻编辑/etc/docker/daemon.json把镜像加速和日志轮转一次性写好。systemctl restart docker docker run hello-world。usermod -aG docker $USER重登验证。顺序里有一点比较关键我习惯先把 daemon.json 写好再启动 docker而不是启动好了再改配置。这样避免第一次启动时用错配置后面还要重启一次。另外一个小技巧把整套步骤写进一个 shell 脚本放到~/bin/docker-setup.sh新机器或新服务器到手直接执行。但不要在脚本里写死密钥和专属加速地址这些可以留到执行时替换否则脚本复制到别的机器上会有兼容问题。还有一点是我实际踩过坑之后的经验不要在容器里为了“方便”再套一层 docker。除非你明确需要 docker-in-docker 做 CI 流水线否则多服务项目直接用docker compose管理就够嵌套 Docker 会带来网络、存储和权限一连串莫名其妙的麻烦排查起来非常费神。这套流程我在干净安装的 22.04 上跑过很多次也在从 20.04 升级上来的旧系统上跑过只要装之前肯花 30 秒检查残留后面基本不会出什么意外。如果你照着一步步操作完还有问题第一件事永远是看日志journalctl -u docker -n 100和docker logs YOUR_CONTAINER这两个命令比任何“万能重启”都更能告诉你真相。
返回列表