资讯动态

Ubuntu 18.04 安装 Docker 官方仓库全流程与排错指南

发布时间:2026/9/18 4:04:30 来源:尧图企业网站定制
1. 为什么 Ubuntu 18.04 上装 Docker 还值得单独写一篇Ubuntu 18.04 是个有点年头的 LTS 版本代号 Bionic Beaver很多公司的老服务器、测试机、边缘设备上还跑着它。你可能遇到这种情况机器是别人交接的系统不让随便升级上面又必须跑几个容器化服务于是如何在 Ubuntu 18.04 上安装 Docker就成了一个绕不过去的问题。这篇文章就是写给这种场景的——不是给你讲 Docker 是什么而是把从零到能跑起第一个容器之间所有会踩的坑一次性讲清楚。先把结论放前面Ubuntu 18.04 上装 Docker官方推荐的做法是通过 Docker 官方的 apt 软件仓库安装 docker-ce而不是用 Ubuntu 自带的 docker.io 包。原因很实际——系统仓库里的 docker.io 版本普遍偏低和官方最新版差着好几个小版本很多新特性比如 Compose V2 的集成、BuildKit 默认开启、日志驱动的细粒度控制都用不上而且一旦你要在多个环境保持一致版本对不齐会非常难受。docker 安装这件事本身不难难的是装机之后那一堆为什么我的容器起不来为什么每次都要 sudo为什么拉镜像慢得像蜗牛。这篇文章适合三类人第一类是刚接触容器、需要在一台干净的 Ubuntu 18.04 上把 Docker 跑起来的新手第二类是接手了老机器、需要在不破坏现有环境的前提下补装 Docker 的运维第三类是本地开发想复刻线上环境的开发者比如用 idea 打包 docker 镜像之后要本地验证部署效果。全文会覆盖环境检查、三种安装方式对比、官方仓库安装全流程、安装后必做的几项配置、第一个容器的验证、常见报错排查以及卸载和版本锁定。每一步我都会说明为什么这么做而不是只给命令让你抄。需要提前说清楚一点下面所有操作我都建议在物理机或虚拟机上先跑一遍别直接上生产。Docker 的安装本身对系统侵入性不大但 daemon.json 里的参数一旦配错可能导致所有容器起不来回滚虽然简单但耽误的是时间。2. 安装前的环境确认与准备工作2.1 系统版本与内核要求核对Docker 对内核有硬性要求不是随便一个 Linux 都能装。官方对 Ubuntu 18.04 的最低要求是 64 位系统、内核 3.10 以上但如果要用 overlay2 存储驱动这是 18.04 上的推荐驱动内核最好在 4.0 以上。18.04 默认带的 4.15 内核完全满足所以一般不用操心但如果你用的是被降级过内核的定制镜像就必须先确认。先看系统版本lsb_release -a输出里应该有Ubuntu 18.04.x LTS和Codename: bionic这两个关键信息。bionic这个词很重要因为后面添加软件源时要用到它写错了就会报 404。再看内核和架构uname -r uname -muname -m输出应该是x86_64。如果你拿到的是aarch64说明是 ARM 架构比如一些国产化环境像龙芯平台的 LoongArch 又是另一套体系那软件源的arch参数就不能写amd64得换成对应的架构名甚至部分版本需要从源码编译。这一点很多人第一次接触非 x86 机器时会忽略导致加完源 apt update 一堆报错。顺便确认一下磁盘空间Docker 的镜像和容器层默认都在/var/lib/docker空间不够会很难受df -h /var/lib/docker建议至少留 20GB。如果/var单独分区且快满了后面我会讲怎么把>sudo apt-get remove -y docker docker-engine docker.io containerd runc sudo apt-get autoremove -y注意apt-get remove不会删除/var/lib/docker里的镜像和容器数据所以如果你这台机器之前跑过容器数据还在只是不能用了——因为和官方版的数据结构、版本可能不兼容。如果你想彻底重来后面卸载章节我会讲怎么清空。清理完之后验证一下which docker docker --version如果两条命令都提示找不到说明干净了。如果还能找到可能是通过 snap 装的snap list | grep docker有的话用sudo snap remove docker卸掉。snap 版 Docker 在 18.04 上其实能跑但它的文件路径和权限模型跟官方 apt 版差异很大脚本里写死的路径经常对不上属于能用但坑多的类型不建议在生产上用。提示清理前先确认这台机器上真的没有在跑的容器业务。用docker ps -a看一下如果命令都执行不了说明本来就没装成功过可以放心清。2.3 安装必要的基础依赖官方仓库安装方式需要几个基础工具apt-transport-https让 apt 支持 https 源、ca-certificates验证证书、curl下载密钥、gnupg-agent和software-properties-common管理源和密钥。这些在最小化安装的 Ubuntu 18.04 上可能都不全。一条命令装齐sudo apt-get update sudo apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common为什么要先apt-get update因为你这台机器可能是几周前甚至几个月前初始化好的本地 apt 索引里的包地址可能已经过期直接 install 会报无法定位软件包。很多人装 Docker 卡在第一步就是这个原因看起来是 Docker 的问题其实是 apt 索引没更新。这里插一句心得apt-transport-https在较新的 Ubuntu 上其实已经内置进 apt 了18.04 上装它属于保险起见。但ca-certificates是真的必要——如果你这台机器的根证书过期了老镜像很常见下载 GPG 密钥时会报 SSL certificate problem而且报错信息很隐晦容易误判成网络问题。3. 基于官方仓库的完整安装流程3.1 三种安装方式的取舍与选择理由在动手之前值得花两分钟想清楚用哪种方式装。Ubuntu 上装 Docker 主要有三条路各自适合不同场景。安装方式命令入口版本新鲜度升级便利性适合场景系统仓库安装apt install docker.io低滞后多个版本跟随系统升级临时测试、不在乎版本官方仓库安装添加 docker 源后 apt 安装高与官方同步apt upgrade即可生产、开发统一环境官方脚本安装curl get.docker.com | sh高需重跑脚本快速体验、CI 临时环境系统仓库那条路的坑在于版本。18.04 仓库里的 docker.io 停在 20.10 附近甚至更早而官方仓库能装到更新的稳定版两者在 Compose 文件语法支持、日志驱动参数、安全补丁上有明显差距。官方脚本那条路虽然快但它会一股脑把仓库、密钥、包全装好过程不透明出问题不好排查也不方便做版本锁定——生产环境上我不敢用。所以下面的流程走的是官方仓库安装。这套流程的好处是每一步都可控出问题能精确定位到是密钥、源还是包本身的问题。3.2 添加 GPG 密钥与软件源第一步下载 Docker 官方的 GPG 公钥用来验证后面下载的软件包确实是官方签名过的curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -执行成功会输出OK。-f参数是让 curl 在 HTTP 错误时直接失败-s是静默模式-S是出错时仍然显示错误-L是跟随重定向。这几个参数组合起来才能在管道里安全使用少了任何一个都可能在下载失败时给你一个看起来成功的假象。验证一下密钥指纹这一步不是形式主义sudo apt-key fingerprint 0EBFCD88正常应该看到指纹是9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88。如果对不上说明下载过程被篡改或者拿到的是错误的密钥千万别继续。接下来添加软件源。18.04 的代号是 bionic所以sudo add-apt-repository deb [archamd64] https://download.docker.com/linux/ubuntu bionic stable这行命令的每个部分都有讲究。[archamd64]限定架构防止 apt 在多架构环境下误拉bionic必须和你的系统代号一致stable是稳定通道如果你需要尝鲜可以改成test或nightly但生产环境别这么干。如果你用的是 ARM 机器这里amd64要换成arm64源地址文件名也一致Docker 官方对 arm64 是有支持的。加完源之后更新索引sudo apt-get update这一步如果报 404八成是代号写错了或者源地址里的路径拼错了。如果报 GPG error说明密钥没加成功。注意apt-key add这种方式在新版 Ubuntu 上已经标记为废弃但在 18.04 上仍然完全可用而且是最省事的做法。如果你想用更规范的方式可以把密钥存到/etc/apt/keyrings/目录并在源里用signed-by指向它不过 18.04 的 apt 版本对这套语法支持不完整容易踩坑所以我一般还是用 apt-key。3.3 安装 docker-ce 并验证版本索引更新成功后就可以装主程序了sudo apt-get install -y docker-ce docker-ce-cli containerd.io这三个包的分工要说清楚不然装完你会疑惑为什么有这么多东西。docker-ce是服务端和客户端的主体docker-ce-cli是命令行工具独立出来是为了让客户端可以单独升级containerd.io是底层的容器运行时负责真正管理容器的生命周期。Docker 从 18.09 之后把 containerd 拆成了独立包所以必须显式安装。如果你需要指定版本比如线上统一用某个版本可以先查可用的版本列表apt-cache madison docker-ce输出会列出所有可用版本格式类似5:20.10.24~3-0~ubuntu-bionic。安装指定版本就写成sudo apt-get install -y docker-ce5:20.10.24~3-0~ubuntu-bionic docker-ce-cli5:20.10.24~3-0~ubuntu-bionic containerd.io版本号前面那个5:是 epoch必须带着漏了会报版本不存在。这个细节坑过不少人。装完立刻验证sudo docker version这个时候还没配用户组所以要用 sudo。输出分 Client 和 Server 两段Client 是命令行版本Server 是守护进程版本。如果只看到 Client 没有 Server说明守护进程没起来先别慌下一节讲怎么处理。3.4 启动服务与设置开机自启Ubuntu 18.04 用的是 systemdDocker 安装时会自动注册服务单元。正常情况下装完就已经在跑了但老机器上可能因为依赖顺序问题没起来。先看状态sudo systemctl status docker看到绿色的active (running)就对了。如果显示inactive或failed先启动sudo systemctl start docker再设成开机自启这一步对服务器特别重要——不然机器一重启所有容器全没了sudo systemctl enable docker返回Created symlink /etc/systemd/system/multi-user.target.wants/docker.service说明成功。如果启动失败用这条命令看详细日志sudo journalctl -u docker --no-pager -n 50最常见的失败原因是 daemon.json 配置语法错误或者>sudo usermod -aG docker $USER这里-aG的a是关键代表 append。如果只写-G会把用户从其他所有附加组里踢出去是个很危险的错误——有人因此把自己从 sudo 组踢出来直接锁死机器。加完之后必须重新登录才生效。因为你当前的 shell 会话已经加载了旧的组成员关系newgrp docker可以在当前会话临时生效但更稳妥的做法是退出再登录或者直接ssh重连一次。验证docker run --rm hello-world不加 sudo 也能跑说明配好了。注意把用户加进 docker 组等价于给了这个用户近乎 root 的权限因为你可以直接docker run -v /:/host挂载宿主机根目录。单人开发的机器没问题多人共用的服务器上要慎重别随便给普通账号加。4.2 镜像加速与 daemon.json 参数调优Docker 的配置文件在/etc/docker/daemon.json默认可能不存在需要自己创建。这个文件是调优的核心改错一个逗号都可能导致守护进程起不来所以每次改完记得先sudo systemctl restart docker并看状态。一个相对稳妥的配置模板{ registry-mirrors: [https://your-mirror-address], log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 }, exec-opts: [native.cgroupdriversystemd], default-ulimits: { nofile: { Name: nofile, Hard: 65536, Soft: 65536 } } }逐个说清楚每项的作用。registry-mirrors是镜像加速地址国内网络环境下直接从官方仓库拉镜像经常超时配置一个就近的加速地址能显著提升拉取速度这是很常规的优化手段具体地址向你的云服务商或运维同事索取即可。注意这个数组里的地址要有完整的https://前缀而且不要配多个来源不明的地址否则可能出现镜像层校验失败。log-driver和log-opts是防磁盘爆掉的关键。Docker 默认把容器 stdout 写到 json 文件里永久保存、无限增长一个疯狂打日志的服务一个月能吃掉几十 GB。限制成单文件 100MB、最多保留 3 个总共 300MB 上限对于绝大多数服务够用了。这个坑我踩过某次磁盘满导致数据库写不进去排查半天才发现是容器的日志文件。exec-opts里的 cgroupdriver 设成 systemd 是为了和宿主机的 systemd 保持一致。如果你后续要在这台机器上跑 K8s这个配置是必须的不然 kubelet 启动时会报 cgroup driver 不匹配的警告虽然不一定立刻出问题但迟早要改。default-ulimits提高文件描述符上限像 Nginx、Redis 这类高并发服务默认的 1024 完全不够调大省得每个容器单独配。改完重启sudo systemctl daemon-reload sudo systemctl restart docker sudo systemctl status docker4.3 存储驱动确认与数据目录迁移存储驱动决定了镜像层怎么叠加直接影响性能和磁盘占用。18.04 上推荐 overlay2用这条命令确认docker info | grep Storage Driver输出overlay2就对了。如果显示vfs说明内核不支持 overlay2性能会差一大截因为 vfs 是逐层复制一个镜像能有几个 GB 的冗余。这种情况通常是因为/var/lib/docker所在的分区是某些不支持 overlay 的文件系统比如早期的 ZFS 或某些网络文件系统。如果你的根分区空间紧张想把 Docker 数据挪到数据盘就在 daemon.json 里加一行{ data-root: /data/docker }注意路径要提前创建好并且保证属主是 rootsudo mkdir -p /data/docker sudo chmod 700 /data/docker迁移已有数据的话先停服务、用rsync -aP同步比 cp 更适合大目录支持断点续传再改配置、重启。直接用 mv 也行但几万个镜像层文件 mv 到不同分区其实也是复制加删除中途中断很难恢复。5. 跑通第一个容器验证安装真的成功5.1 hello-world 背后发生了什么docker run hello-world这条命令几乎是所有人的第一个容器但它背后发生的事值得拆开看理解了这些后面排查问题才有思路。完整流程是这样的docker 客户端把请求发给守护进程守护进程先检查本地有没有hello-world这个镜像没有就去配置的仓库拉拉下来之后创建容器并执行镜像里定义的入口程序程序打印一段说明文字后退出。手动分步执行一遍更能看清docker pull hello-world docker images docker run --rm hello-worlddocker images会列出一个非常小的镜像几十 KB。--rm参数表示容器退出后自动删除容器记录不加的话docker ps -a里会堆一堆退出状态的容器时间长了很乱。如果这一步卡在Pulling from library/hello-world很久说明镜像源不通畅回到 4.2 检查加速配置。5.2 用 Nginx 和 Redis 做真实场景验证hello-world 太简单验证不了端口映射、数据卷、后台运行这些真实能力。用 Nginx 跑一遍完整流程docker run -d --name web -p 8080:80 nginx:alpine拆解参数-d是后台运行--name web给容器起个固定名字方便后续操作-p 8080:80把宿主机的 8080 端口映射到容器内的 80前者是宿主机、后者是容器顺序别搞反这是新手最常见的错误nginx:alpine用 Alpine 基础镜像体积只有十几 MB比完整版小一个数量级。跑起来之后docker ps curl http://localhost:8080能看到 Nginx 的欢迎页 HTML 就说明端口映射、网络、进程管理全部正常。再试一个带持久化的 Redis顺便验证数据卷docker run -d --name cache -v /data/redis:/data redis:6-alpine redis-server --appendonly yes docker exec -it cache redis-cli set foo bar docker exec -it cache redis-cli get foo-v /data/redis:/data把宿主机的/data/redis挂到容器的/dataRedis 的 AOF 持久化文件就落在这里。docker exec进容器执行命令验证读写正常。之后即使docker rm -f cache把容器删掉重新用同样的命令跑起来get foo依然能拿到值这就是数据卷的价值。很多人的实际需求其实就是这么朴素——跑个 Redis、跑个依赖管理面板、跑个自己打包的 Java 服务。比如用 idea 打包出镜像之后在服务器上无非就是docker load导入镜像、docker run起服务。安装环境是这一切的地基地基不稳后面每一步都是坑。提示redis:6-alpine这种不带 registry 前缀的写法默认从 Docker Hub 的官方库拉取。如果你用的是私有仓库要写完整的地址比如registry.example.com:5000/redis:6-alpine。6. 常见问题与排查实录6.1 安装阶段报错速查把安装过程中最常撞到的错误整理成一张表遇到问题时先在这里找能省掉大量搜索时间。报错信息关键词根本原因处理方式add-apt-repository: command not found缺 software-properties-commonapt install -y software-properties-commonNO_PUBKEY 0EBFCD88GPG 密钥没导入成功重新执行 curl 导入密钥并 update404 Not Found ... bionic源里的系统代号写错改成bionic或正确的架构E: Unable to locate package docker-ce源没加成功或没 update检查源文件、执行apt-get updatedocker.io conflicts with docker-ce系统里还有旧版 docker按 2.2 节彻底卸载Cannot connect to the Docker daemon守护进程没运行systemctl start docker并看日志permission denied /var/run/docker.sock用户不在 docker 组加组后重新登录Job for docker.service faileddaemon.json 语法错误journalctl -u docker看具体行号这张表里最值得展开的是最后一条。daemon.json 是纯 JSON不允许有注释、不允许有尾随逗号而它本身又不提供语法校验守护进程只会冷冰冰地告诉你启动失败。我的习惯是每次改完先本地用python -m json.tool /etc/docker/daemon.json校验一遍通过再重启能省掉大量来回。6.2 镜像拉取慢与超时的处理思路镜像拉不动是最高频的问题表现有好几种一直卡在Pulling fs layer、报net/http: TLS handshake timeout、报context deadline exceeded。这些现象背后通常是同一个原因——到镜像仓库的连接质量差。排查顺序是这样先确认网络本身通不通ping一下加速地址的域名再确认加速地址配置生效没有docker info输出里能找到Registry Mirrors那一段看地址在不在最后再重试拉取。几个实操技巧。第一拉大镜像时加--platform明确架构避免 docker 去拉一个不存在的多架构清单导致长时间等待。第二docker pull支持断点续传网络中断后重新执行会从已下载的层继续不会从头开始所以别急着docker rmi重来。第三用docker pull -q静默模式输出干净在脚本里更好处理。如果某个镜像在某台机器上死活拉不下来可以在一台网络好的机器上 pull 完用docker save导出成 tar拷过去docker load导入。这个离线搬运的办法在隔离环境里是标准操作docker save nginx:alpine -o nginx-alpine.tar # 拷贝到目标机器后 docker load -i nginx-alpine.tar6.3 容器起来又立刻退出的排查方法这是另一类高频问题docker ps看不到容器但docker ps -a显示状态是Exited (1)。容器启动后又退出说明里面的主进程执行完或者崩了。排查第一步是看日志docker logs container_id日志里通常会有明确的错误比如配置文件路径不对、端口被占用、依赖的数据库连不上。如果日志是空的说明进程根本没输出就挂了。第二步是看退出码docker inspect能看到docker inspect container_id --format {{.State.ExitCode}} {{.State.Error}}退出码 1 一般是应用自身错误137 是被 OOM 杀掉的内存不够139 是段错误143 是被正常终止。137 这个特别值得注意如果你限制过容器的内存--memory256m而应用实际需要 512m就会反复被杀日志里还看不出来只能用docker inspect才查得到。第三步如果日志看不出问题可以覆盖入口命令进容器里手动调试docker run --rm -it --entrypoint sh nginx:alpine把默认入口换成 shell进去之后手动执行原本的启动命令错误信息会直接打在终端上比翻日志直观得多。注意调试完记得别把这个覆盖入口的写法带到生产里。有些人在 Compose 文件里留了entrypoint: [sh]结果容器跑起来挂在那儿什么都不干排查半天才发现是这行没删。7. 卸载、升级与版本锁定7.1 彻底卸载的完整步骤卸载分两个层次你要先想清楚是只卸程序保留数据还是全部清空。只卸程序sudo apt-get purge -y docker-ce docker-ce-cli containerd.io sudo apt-get autoremove -y注意是purge不是removepurge 会连配置文件一起删掉包括 daemon.json。如果你以后还要装建议先备份 daemon.json。如果要彻底清空包括所有镜像、容器、卷sudo rm -rf /var/lib/docker sudo rm -rf /var/lib/containerd sudo rm -rf /etc/docker这几条命令不可逆执行前务必确认/var/lib/docker里没有你还需要的数据。特别提醒命名卷named volume里的数据是存在/var/lib/docker/volumes下的删了就是真的没了数据库之类的容器尤其要小心。另外用户组和 socket 文件也顺手清理一下sudo groupdel docker sudo rm -f /var/run/docker.sock7.2 版本升级与锁定的取舍服务器上的 Docker 到底该不该随便升级我的经验是小版本比如 20.10.20 到 20.10.24可以升修的是安全补丁和 bug跨大版本20.10 到 24.03要谨慎运行时、存储驱动、API 版本都可能有变化尤其是你上面跑着 K8s 或者依赖特定 API 的编排工具时。升级命令很简单sudo apt-get update sudo apt-get install -y --only-upgrade docker-ce docker-ce-cli containerd.io sudo systemctl restart docker关键是升级前做什么。第一备份 daemon.json第二记录当前版本docker version的输出第三确认所有容器的重启策略是unless-stopped或always否则重启完只有部分容器会自己起来第四如果可能先在测试机上验证一遍。如果你希望某个版本稳定不被自动升级带走用 apt 的锁定机制sudo apt-mark hold docker-ce docker-ce-cli containerd.io解锁用unhold。这个做法在需要长期稳定运行的生产机上很实用。因为有些自动化运维脚本会定期跑apt-get upgrade万一它把 Docker 升上去了而新版本和你的编排系统有兼容问题那真是半夜被叫起来处理的节奏。锁上之后至少升级这件事是你主动决定而不是被动接受。验证锁定状态apt-mark showhold能看到三个包名就说明生效了。需要升级时先unhold升完再hold回去形成固定流程。我个人在实际操作中的体会是Ubuntu 18.04 这类生命周期接近尾声的系统上Docker 的版本策略比版本本身更重要。因为你能拿到的系统包会越来越少安全更新的窗口也在收窄与其每次出问题临时救火不如一开始就把版本锁死、把 daemon.json 固化下来、把安装和卸载的脚本写成可重复执行的文档。这套流程跑顺了哪怕以后换到更新的 Ubuntu 版本无非是把源里的bionic换成新代号其他步骤几乎可以原样搬过去真正值钱的是这套思路而不是那几行命令。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价