☰
Ubuntu安装Docker全指南:从apt源到Compose部署与排错
2026/10/3 3:39:18 网站建设 项目流程

最近帮朋友折腾服务器,又在Ubuntu上装了一轮Docker。说实话,这东西装起来不算难,但网上教程一堆,有的让你用脚本,有的让你用apt,有的直接让你下载deb包,新手很容易看晕。尤其是你手上这台机器是Ubuntu 22.04还是20.04,内核版本到了几,之前有没有装过旧版Docker,这些都会直接影响你的安装方式和后续体验。我打算把这些年踩过的坑整理成一套实操流程,从安装前准备、三种安装方式对比、装完后的必要配置,到Compose部署、问题排查,尽量讲清楚每一步背后的原因,而不是光丢几条命令。

这篇文章特别适合刚接触Ubuntu的初学者,也适合那些在服务器上反复安装Docker、但总被权限、网络、镜像源问题困扰的朋友。看完你至少能明白:为什么推荐用官方apt仓库而不是直接apt install docker.io,为什么装完还要配daemon.json,以及当docker run报错时应该怎么排查。

1. 安装前的准备:先搞清楚你的系统和历史残留

1.1 确认Ubuntu版本和系统架构

装Docker之前,第一步不是急着复制粘贴命令,而是确认你的Ubuntu版本和CPU架构。不同的Ubuntu版本对应不同的内核版本和service管理方式,Docker对系统版本有明确要求。我见过有人在Ubuntu 16.04上硬装新版Docker,结果内核太老,存储驱动直接起不来,那种问题排查起来非常痛苦。

先跑这两条命令:

lsb_release -a uname -m

lsb_release -a会输出发行版描述、版本号、代号,比如Ubuntu 22.04.4 LTS,代号jammy。uname -m输出架构,x86_64就是amd64,aarch64就是arm64。为什么一定要看架构?因为你添加软件源和下载deb包时要选对架构。官方源里amd64的架构标识是amd64,arm64是arm64,乱选的话,apt会报“无法定位软件包”。

下面是我实际接触到的常见版本情况:

Ubuntu版本代号内核特点Docker支持情况
20.04 LTSfocalkernel 5.4,支持overlay2、cgroups v1默认支持,但部分新特性受内核限制
22.04 LTSjammykernel 5.15,cgroups v2默认支持度高,推荐日常使用
24.04 LTSnoblekernel 6.8,cgroups v2支持度高,新版Docker体验更好

如果你的系统是老版本,比如16.04、18.04,我建议先升级系统再装Docker。不是不能装,而是老系统上很多包依赖过旧,安装过程中容易遇到各种莫名其妙的问题。博主级别的操作习惯是:先把基础环境弄干净,再动手。

1.2 清理历史残留的Docker安装

如果你之前用apt、snap或者某些脚本装过Docker,现在想重新安装,一定先看看残留。残留的旧配置、旧daemon.json、旧的网络规则,都可能导致新装成功后磁盘和网络表现异常。比如旧版本创建过docker0网桥,新版本启动时发现网桥名称冲突,直接启动失败。

先检查当前系统到底有没有装过Docker相关包:

dpkg -l | grep -i docker

如果有输出,说明之前装过。清理干净再装新版本:

sudo apt remove --purge -y docker docker-engine docker.io containerd runc sudo rm -rf /var/lib/docker sudo rm -rf /var/lib/containerd

注意一个细节:/var/lib/docker是Docker默认的数据目录,里面存着镜像、容器、卷。如果你只是想重装Docker,但还想保留现有镜像和容器数据,这个目录不能直接删。如果你是要彻彻底底重来,删掉没问题。但实际情况是,很多新手不知道这点,一删就把数据全丢了。所以执行删除前,先想清楚你到底要“重装”还是“清理”。

还有个容易被忽略的点:Ubuntu的snap也可能带着docker包。可以用snap list | grep docker检查一下,有的话sudo snap remove docker。snap版Docker路径和配置都跟官方不一样,混用会出问题。

2. 三种主流安装方式与选型分析

2.1 官方apt仓库安装:最稳妥、我最推荐的方式

为什么推荐先走官方apt仓库这条路线?因为Docker官方为Ubuntu维护了独立的软件源,里面的docker-ce、docker-ce-cli、containerd.io都是经过官方测试的版本,更新及时,依赖关系清晰。而直接用apt install docker.io装的是Ubuntu发行版仓库里的Docker,版本往往滞后,而且与官方的新版命令行工具、Compose插件可能存在兼容性差异。

从Ubuntu 22.04开始,apt源里的docker.io版本其实也能用,但版本更新缓慢。比如你想用docker compose这个新命令,旧版本docker.io可能只支持docker-compose,还得单独装Python版的compose。装官方源就没这个烦恼。

操作步骤如下。首先安装需要的依赖:

sudo apt update sudo apt install -y ca-certificates curl gnupg lsb-release

这些软件包是给后续添加源准备的。ca-certificates用于HTTPS验证,curl下载密钥,gnupg处理GPG钥匙,lsb-release读取发行版名称。

然后添加Docker官方的GPG密钥:

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 a+r /etc/apt/keyrings/docker.gpg

这里用install -m 0755 -d先创建目录,是为了确保目录存在且权限正确。把GPG密钥去armor化后存成二进制的.gpg文件,这是新版apt的推荐做法。

接着添加软件源。Ubuntu不同版本代号不同,所以我推荐用变量自动适配:

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

这条命令里几个关键点:

  • dpkg --print-architecture自动输出当前架构,不会写死。
  • lsb_release -cs输出系统代号,比如jammy、focal。
  • 注意仓库类型是stable,如果你所在区域访问docker.com很慢,建议先配置镜像加速源,这个后面单讲。很多人卡在这一步是因为网络问题,curl下载GPG key超时,就以为是命令写错了。

更新索引并安装:

sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

这里装的不只是docker引擎,还包含了Buildx插件和Compose插件。Buildx用于多架构镜像构建,Compose用于编排多容器应用。一次性装齐,能省掉后续很多麻烦。

安装完成先看版本确认成功:

docker --version docker compose version

装完官方仓库后,默认情况下docker命令需要root权限。先别急,后面有专门的用户组配置章节。

2.2 官方脚本安装:图快但不够透明

很多教程会推荐一条命令安装:

curl -fsSL https://get.docker.com | sh

官方脚本的好处是傻瓜式,自动检测系统、添加源、安装依赖和Docker。但坏处是它不够透明,脚本会在你不知情的情况下改系统源。另外如果脚本下载失败或断在中间,你很难排查它到底执行到哪一步。

我的建议是:临时测试环境可以用脚本,生产环境、公司服务器、需要长期维护的机器,还是老老实实用手动apt仓库的方式。原因很简单,手动方式你知道自己做了什么,出了问题也知道从哪里查。那种“一条命令搞定”的安装,如果哪天Docker起不来,你连系统被改过什么都没概念。

脚本安装示范:

curl -fsSL https://get.docker.com | sudo sh

脚本跑完后,同样验证一下版本。脚本安装的Docker也是官方软件源里的docker-ce,本质上跟手动添加源是一样的,只是省去了index步骤。如果你已经用脚本装好了,后续想换回手动管理,其实也不太必要,因为体系一致。

2.3 离线安装:面向内网环境的方案

如果你的机器完全不能访问外网,或者公司内网有合规要求,那上面基于curl和apt源的方式全都不适用。这时候需要用deb包离线安装。

首先要在一台可以联网的同版本Ubuntu机器上下载对应deb包:

cd /tmp sudo apt download docker-ce docker-ce-cli containerd.io

apt download只下载不安装。下载下来的文件是.deb包。把它们传到目标机器后执行:

sudo dpkg -i docker-ce*.deb docker-ce-cli*.deb containerd.io*.deb

但dpkg安装时很可能报依赖缺失,比如需要libicu、libseccomp等。这时候你还需要同时下载这些依赖包,或者配置好内网apt源。说白了,离线安装最麻烦的不是Docker本身,而是依赖链。

如果你不是重度离线需求,我更推荐在能联网的机器上先生成一个离线包目录,把所有依赖一次性下齐,再拷贝到内网用apt install /path/*.deb安装。这属于额外的工程化技巧了,本期先不展开。

3. 安装后的系统级配置:让Docker用得更顺手

3.1 用户组配置:不想每次sudo就做这一步

Docker安装完成后,立刻会遇到权限问题。直接跑docker ps会提示:

docker: permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: dial unix /var/run/docker.sock: connect: permission denied

这是因为Docker守护进程绑定的是Unix socket,默认只有root用户和docker用户组的成员有权限访问。解决方法一是每次都加sudo,二是把当前用户加入docker组。

执行:

sudo usermod -aG docker $USER

注意,这条命令只是把用户加入docker组,需要重新登录或执行newgrp docker才能生效。很多新手执行完立刻又试docker ps,发现还是permission denied,以为是没生效,其实是没有刷新会话。更彻底的做法是退出当前SSH会话重新登录一次。

另外,加入docker组等于把这个用户提升到了与root相当的特权。因为用户可以操作Docker创建特权容器,进而访问宿主机文件系统。所以生产服务器上要谨慎决定哪些用户能加入docker组,这不是一个无伤大雅的权限操作。

3.2 配置开机自启和daemon.json参数

安装官方版本时,systemd服务文件一般已经就位。但为了保证重启后Docker能自动运行,建议手动启用:

sudo systemctl enable docker sudo systemctl start docker

如果Docker已经运行,systemctl start不会重复启动,放心执行。状态可以用systemctl status docker查看,按下q退出详情页。

接下来是重点:修改/etc/docker/daemon.json。这个是Docker守护进程的配置文件,很多高级配置都写在这里。常见的痛点有两个:国内镜像拉取慢、容器日志无限增长。

如果没有这个文件,手动创建:

sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<'EOF' { "registry-mirrors": ["https://docker.m.daocloud.io"], "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" }, "storage-driver": "overlay2" } EOF

逐项解释:

  • registry-mirrors:镜像加速地址。国内直连Docker Hub很慢,换成可用的镜像加速器能显著提升拉取速度。注意,不同时间段、不同地域可用的镜像源不同,需要自己实测。
  • log-driver和log-opts:限制容器日志大小。默认情况下,一个容器如果不加限制,日志文件可以无限增长直到占满磁盘。我踩过这个坑,一个简单的测试容器半年没管,日志居然吞掉了几十GB磁盘空间。
  • storage-driver:设置为overlay2。这是现代Ubuntu上推荐的存储驱动,比老的aufs更稳定高效。不过如果内核足够新,Docker默认会自动选择overlay2,不写也没问题。

修改完配置需要重启Docker才能生效:

sudo systemctl restart docker

重启后可以用docker info查看当前使用的存储驱动和日志配置有没有生效。

4. Docker Compose 安装与项目部署实例

4.1 Compose插件安装方式

很多人还在用docker-compose这套老的工具链。新版Docker更推荐把Compose作为Docker CLI的一个子命令集成进来,也就是docker compose。如果安装第2节推荐的官方apt仓库方式,并且装了docker-compose-plugin,那docker compose直接可用。

验证:

docker compose version

如果你的环境没有Compose插件,可以单独安装:

sudo apt install -y docker-compose-plugin

或者在GitHub上下载二进制包。这里我就不贴下载链接了,重点说一下Compose文件的结构。因为Compose让你可以把多个容器定义在一个YAML文件里,然后一次性启动,非常适合MySQL、Redis、Nginx这类多服务场景。比如你搜“docker安装mysql8.0并使用”这样的需求,用Compose搭一台MySQL加一个管理面板就非常舒服。

4.2 实战案例:用docker compose部署MySQL 8.0

我先写一个最小可用的docker-compose.yml:

version: "3.8" services: mysql: image: mysql:8.0 container_name: my_mysql restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: rootP@ssw0rd MYSQL_DATABASE: mydb ports: - "3306:3306" volumes: - mysql_data:/var/lib/mysql command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci volumes: mysql_data:

保存文件后启动:

docker compose up -d

解释一下关键点:

  • image: mysql:8.0表示使用MySQL 8.0官方镜像。
  • container_name自定义容器名,否则Compose会自动生成带前缀的容器名。
  • restart: unless-stopped表示容器非手动停止时,Docker重启或系统重开都会自动拉起这个容器。
  • environment里设置了root密码和初始数据库名。
  • ports把宿主机的3306映射到容器的3306。注意如果宿主机自己已经装了3306端口服务,这里会冲突。
  • volumes使用命名卷mysql_data持久化数据,容器删除后数据还在。
  • command追加MySQL启动参数,指定字符集为utf8mb4。

启动后检查状态:

docker compose ps docker logs my_mysql

如果你只是想用数据库,不用进入容器。在宿主机上用客户端连接即可:

mysql -h127.0.0.1 -P3306 -uroot -p

这里容易踩的坑是MySQL8默认认证插件是caching_sha2_password,一些老的客户端程序连接时会报认证不支持。解决办法是在Compose的command里加一行--default-authentication-plugin=mysql_native_password,或者在创建用户时指定认证插件。但新客户端一般没这个问题,不用盲目改。

Compose的真正优势在于多服务联动。比如一边是MySQL,一边是Redis,再加个Nginx反代,一个YAML文件全部搞定。以后我会专门写一篇更复杂的Compose编排文章,这里先确保你能跑通基础。

5. 常见问题与排查技巧实录

5.1 拉取镜像慢或超时

网上一搜“docker拉取镜像慢”,大多数回答都是让你配加速。上面我已经给出了daemon.json的写法。但如果配了加速还是慢,建议换个镜像加速地址。很多镜像加速本质上是代理,时好时坏,可以备两个地址,一个挂了换另一个。

拉取镜像失败时,先区分是DNS问题还是网络问题。用docker pull报EOF、timeout这种,多半是网络阻断。先试curl https://registry-1.docker.io/v2/,看能否连通,再逐级排查。

5.2 docker run报“network not found”或“iptables”错误

比较常见的错误是:

docker: Error response from daemon: create network ... network not found

这种一般是你手动删除了默认的bridge网络,或者误删了docker_gwbridge。解决办法是重建网络:

docker network prune

这个命令会清理掉所有没有被容器使用的网络,注意先确认没有正在使用的自定义网络。

另外就是iptables相关报错。Ubuntu上自带的ufw防火墙和Docker的iptables规则有可能会冲突。最直接的表现是:容器能启动,但宿主机的某些端口访问不到容器里的服务。这通常是ufw防住了Docker映射的端口,或者是Docker直接把规则写进了INPUT链,导致你的ufw配置失效。我的处理习惯是,生产环境如果不需要Docker完全绕过防火墙,就把容器端口映射到具体接口上,同时在ufw里放行对应端口。比如:

sudo ufw allow 3306/tcp

别小看这个,我见过有人折腾一晚上,最后发现是ufw开着但没放行端口。

5.3 Docker服务启不来:daemon.json写错的典型场景

改完daemon.json后docker服务无法启动,这是高频问题。大多数原因是JSON语法错误。也许你觉得这里不就一个逗号吗,但就是这一个小逗号,systemd会让整个服务起不来。

排查方法:

sudo systemctl status docker

如果显示Failed,再看具体日志:

journalctl -u docker -n 50

同时也可以先手动验证 daemon.json 的语法。用Python的json模块:

python3 -m json.tool /etc/docker/daemon.json

如果输出object不存在或报ParseError,那说明JSON格式确实错了。检查引号、逗号、括号。这个问题在运维群里的出现频率极高,写配置时一定养成先校验再重启的习惯。

5.4 Ubuntu特有的AppArmor权限问题

Ubuntu默认启用了AppArmor,而Docker的容器会被加载默认的AppArmor profile。偶尔你运行某些特权操作容器时会遇到奇怪的权限拒绝,比如operation not permitted。这时先别怀疑Docker,考虑是不是AppArmor在拦截。

临时绕过方法是给容器加上:

docker run --security-opt apparmor=unconfined --rm -it ubuntu bash

如果问题解决,确实和AppArmor有关。生产环境不建议直接全禁,而是根据需要写一条宽松的AppArmor profile。

还有一个Ubuntu上常见的坑是cgroup v2。新版Docker完全支持cgroup v2,一般没问题。但如果你在WSL2或者某些虚拟机里跑Ubuntu,会出现资源限制不生效的问题。检查方式:

stat -fc %T /sys/fs/cgroup

输出cgroup2fs说明是cgroup v2,输出tmpfs则是v1。Docker 20.10以上版本对v2支持已经非常成熟,如果还是遇到问题,优先升级Docker版本。

5.5 卸载Docker时保留数据?还是删干净?

最后顺手提一下卸载。有些朋友装完发现怎么老出问题,想退回或者彻底删除。如果你确认不再使用,干净卸载的完整流程:

sudo apt purge -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin sudo rm -rf /var/lib/docker sudo rm -rf /etc/docker sudo rm -rf /var/lib/containerd

如果你只是出问题想重装,留数据的话就别删/var/lib/docker。先把镜像容器导出来,再操作。这是我的经验:卸载这种操作,宁可多留个目录,也别为了省那点磁盘空间把重要容器永久丢失。

最后,我自己的一点实操体会

安装Docker这件事,单看命令似乎五六步,但当你真的在Ubuntu上一步步操作下来,会发现细节非常多。我后来习惯的做法是:装之前先花十分钟确认系统状态、清理残留,装完立刻把用户组、daemon.json、日志限制、开机自启全部配好。这样能避免后续90%的坑。

再补一句,很多人喜欢用脚本一把梭,但服务器上我还是建议手动走官方apt仓库的流程。脚本适合实验,不适合稳定环境。毕竟Docker装好后,你要在上面跑数据库、服务、定时任务,如果系统底子没打好,后面的问题都是加倍放大。希望这篇文章能帮你少走弯路,装完直接上手用起来。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询