ARTICLE DETAIL

资讯详情

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

Ubuntu 24.04 Docker安装与运维实战:从零到Compose部署

Ubuntu 24.04 Docker安装与运维实战:从零到Compose部署 2026年还在被Docker安装折腾的人真不在少数。我在不少团队里见过这样的情况新到了一台Ubuntu服务器或者自己虚拟机里装了个Ubuntu 24.04打算好好用Docker跑点东西结果卡在了apt源、用户组、镜像加速这些最基础的环节上。明明网上教程一搜一大把但很多文章要么版本太老要么步骤缺失关键细节照着抄经常半路翻车。这篇文章我就把Ubuntu上从零安装Docker、到日常使用、再到几个高频运维场景的完整链路整理出来全程以2026年当前最新稳定版为准踩过的坑和参数细节也都一并写上。适合刚接触Linux和容器的新手也适合装完还想把磁盘、网络、Compose这些玩明白的同学直接照着抄。1. 装之前先想清楚方案选型比动手更重要很多人上来就apt install docker装完发现是旧时代遗留的docker.io版本用起来各种别扭。在2026年的今天Docker在Ubuntu上的安装路径其实已经很成熟但仍然有几种不同走法选错后面就要多花时间收拾。1.1 Ubuntu版本与内核要求先花两分钟确认我强烈建议把系统固定在Ubuntu 22.04 LTS或24.04 LTS上2026年4月之后26.04 LTS也会陆续铺开但24.04目前依然是生态兼容性最好的一个。低于20.04的版本不建议再用了Docker新版本对老内核的支持越来越差很多新特性比如增强的socket挂载、改进的iptables处理逻辑都需要较新的内核配套。打开终端先确认三件事cat /etc/os-release # 看版本代号 uname -r # 看内核版本 uname -m # 看架构x86_64还是arm64Docker官方要求64位系统内核版本不低于3.10但那是最低线真正舒服用的是5.15以上的内核。24.04默认内核是6.8完全没问题。架构上x86_64和arm64都是日常主流Ubuntu装Docker时软件源会自动区分架构不用你干预。1.2 Docker Engine与Docker Desktop在Linux上别选错很多从Windows或macOS转过来的同学第一反应是装Docker Desktop。我先说结论在Ubuntu服务器或虚拟机这种纯Linux环境里直接装Docker Engine是对的Docker Desktop在Linux上也能装但它本质是带了一个虚拟机管理层的桌面应用更适合需要在同一台机器上同时管理Linux容器和Windows容器的场景。普通开发服务器、个人NAS、跑微服务的虚拟机用Engine就够了。如果你之前是在Windows上折腾Docker Desktop遇到各种“virtualization support not detected”、“failed to connect to the docker api at npipe”这类报错那多半是WSL2或Hyper-V虚拟化没开好。这种情况下与其反复修Windows的虚拟化配置不如直接在虚拟机里装一个纯Ubuntu再按下面的方式装Docker Engine——干净、省心、资源占用还更小。1.3 四种安装方式怎么选我整理了一下当前主流的安装路径标签解释清楚安装方式适用场景优点缺点官方apt源安装绝大多数在线环境依赖管理自动、升级方便需要网络稳定官方安装脚本快速体验、自动环境一条命令搞定黑盒操作不好控制细节下载deb包安装内网离线环境可控、可离线依赖要自己解Docker Desktop桌面开发、跨平台容器图形界面全Linux上体积大、层级重我实际装的机器里九成是用官方apt源。离线内网机则是把deb包下载好后dpkg -i一个个装。官方脚本curl -fsSL https://get.docker.com -o get-docker.sh我也用过适合快速搭临时环境但生产环境我不推荐因为你不知道脚本具体动了哪些系统文件出了问题排查起来费劲。2. 安装实战二十分钟跑通完整环境下面进入正题。以Ubuntu 24.04 LTS为例全程在root权限下操作或者用带sudo的普通用户执行。每一步我都会说明为什么这么做。2.1 清理旧版本别让残留文件误导你如果你是从老版本升级过来的或者之前用apt直接装过docker.io先把旧东西清干净sudo apt remove docker docker-engine docker.io containerd runc这一步不会删除/var/lib/docker下面的镜像和容器数据所以不用担心数据丢失。如果确定旧数据不要了后续可以手动清掉/var/lib/docker目录。我遇到过一台机器旧docker配置文件依然在/etc/docker/daemon.json里结果新版本启动后行为异常最好的做法是备份后删掉这个文件重新按需配置。2.2 配置软件源GPG密钥、仓库地址一次讲清Docker官方源用的是HTTPS安全传输apt通过一个GPG密钥来验证软件包的真实性。先把依赖装好sudo apt update sudo apt install -y ca-certificates curl gnupg lsb-release然后创建keyrings目录并下载密钥。2026年这一代安装方法已经固定为debian风格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如果你处在一个访问Docker官网不太通畅的网络环境这里可以换成国内镜像站的GPG密钥地址和官方源前缀一一对应下面统一说。接着添加软件源。我直接给两个版本官方源和国内镜像源。官方源是download.docker.com稳定但速度取决于网络连通性。国内镜像源我用的是阿里云配置方法完全一致只是把域名前缀换掉# 官方源 echo deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release echo $VERSION_CODENAME) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null如果换成阿里云镜像源就把上面命令里的https://download.docker.com/linux/ubuntu替换成https://mirrors.aliyun.com/docker-ce/linux/ubuntu其他不动。$(. /etc/os-release echo $VERSION_CODENAME)这个写法会自动读取你系统当前的版本代号比如24.04生成noble22.04生成jammy不用手写不容易错。2.3 安装docker-ce全家桶与Compose插件源配置好后执行sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin注意这里安装的是docker-ce和docker-ce-cli两个核心包containerd负责容器运行时docker-buildx-plugin是新一代镜像构建工具docker-compose-plugin提供了docker compose子命令。这些都是2026年当前官方推荐的标准组合。装完后立刻让服务自启并验证sudo systemctl enable --now docker sudo systemctl status docker sudo docker --version sudo docker compose version看到服务状态是activerunningdocker版本是28.x或更高Compose插件也有对应版本号就说明装好了。很多人装完发现docker命令不能用大概率是当前用户不在docker组里这就落到下一步。2.4 非root用户使用与镜像加速配置默认情况下操作docker需要root权限。每次都要sudo太烦把当前用户加入docker组sudo usermod -aG docker $USER newgrp docker这里有个关键点newgrp docker只是当前会话生效重开终端或者重新登录后就正常了。如果不执行newgrp直接切换到新终端窗口再测试否则会报permission denied while trying to connect to the Docker daemon socket。dokcer组用户的本质是让你能访问/var/run/docker.sock这个Unix套接字加了组之后不用root权限也能跟守护进程通信。接着配置镜像加速。2026年的网络环境下直接拉Docker Hub镜像经常会出现超时或极慢的情况。我通常会在/etc/docker/daemon.json里配置registry-mirrors。这是我常用的一个配置你根据自己的实际网络选择可用镜像站即可{ registry-mirrors: [ https://docker.m.daocloud.io ], log-driver: json-file, log-opts: { max-size: 50m, max-file: 3 }, data-root: /var/lib/docker }配置完必须重启Dockersudo systemctl daemon-reload sudo systemctl restart docker顺便解释一下log-opts这段限制每个容器的日志文件大小和数量防止容器无限输出日志把磁盘写满。这个配置我建议所有人都加上尤其是生产环境是血泪教训换来的。2.5 第一个容器hello-world的完整校验验证安装是否真正可用docker run hello-world如果本地没有这个镜像会提示Unable to find image hello-world:latest locally然后去拉取跑起来后打印一段说明文字。这一步通过说明你本机Docker守护进程、镜像拉取、容器运行整条链路都没问题。如果卡在拉取镜像阶段回到2.4检查daemon.json的registry-mirrors配置是否正确。3. 核心使用技能镜像、容器、数据卷与Compose环境跑通之后接下来这些是你日常操作里最常用的技能。不需要背所有命令但只要把这几个逻辑吃透后面无论跑什么项目都会顺很多。3.1 镜像管理拉取、查看、标记与清理镜像可以理解为容器的模板。常用操作docker pull nginx:alpine # 拉取指定标签的镜像 docker images # 查看本地所有镜像 docker image tag nginx:alpine mynginx:v1 # 给镜像打标签 docker rmi mynginx:v1 # 删除指定镜像 docker image prune # 清理悬空镜像没标签且没被引用的关于tag我多说一句。你从Docker Hub拉镜像默认latest标签只是方便不建议把latest当生产依赖版本。部署应用尽量锁定具体版本号比如redis:7.4-alpine这样环境变化时可复现。alpine变体是轻量版体积小很多构建和传输都快日常开发够用但个别运行依赖glibc的软件不能用alpine比如某些Java应用在alpine上跑会有DNS解析问题要具体情况具体分析。镜像删除失败时多半是因为有容器正在引用它。正确顺序是先停容器再删容器最后删镜像。这个顺序错了我自己也踩过报错信息大概长这样Error response from daemon: conflict: unable to remove repository reference。3.2 容器生命周期run、exec、stop与删除创建并启动容器最核心的命令docker run -d --name my-nginx -p 8080:80 -v /opt/html:/usr/share/nginx/html:ro nginx:alpine参数拆开解释-d是后台运行--name给容器起名字-p 8080:80把主机的8080端口映射到容器内的80端口-v把主机的/opt/html挂载到容器内nginx的站点目录:ro表示只读挂载防止容器内误改宿主机文件。这是我个人非常推荐的一个习惯能用只读挂载就用只读挂载减少安全隐患。查看运行状态和进入容器docker ps -a # 所有容器包括已停止的 docker logs -f my-nginx # 跟踪日志 docker exec -it my-nginx /bin/sh # 进入容器shell进入容器我建议优先用docker exec -it 容器名 命令这种方式。旧习惯里docker attach也有但它会把容器的标准输出绑到当前终端上CtrlC可能导致容器终止容易误操作。exec是独立进程方式出来的时候按exit就行不影响容器运行。容器停止和删除docker stop my-nginx docker rm my-nginx最后想强调重启策略。容器运行时如果崩溃退出Docker默认不会自动拉起。生产环境我基本都会加上--restart参数docker run -d --name my-app --restart unless-stopped my-app:latestunless-stopped表示除非手动stop否则开机或崩溃退出后都会自动拉起。在服务器重启的场景下这招尤其好用。3.3 数据卷搞懂持久化的正确姿势容器本身是无状态的容器一删容器内写的数据全没了。解决这个问题靠数据卷。Docker有三种存储方式我用一张表说清楚类型写法说明适用场景bind mount-v /宿主机路径:/容器路径直接映射宿主机目录配置文件、共享目录named volume-v mongo-data:/data/db由Docker管理存在/var/lib/docker/volumes/数据库数据、高可靠持久化tmpfs--tmpfs /容器路径内存盘数据不落盘临时缓存、敏感文件数据库这种对性能和数据安全要求高的用named volume。比如MongoDBDocker Hub的官方镜像里声明了VOLUME/data/db用named volume挂载后即使容器重建数据也不会丢。备份数据卷不需要先停容器用tar打包docker run --rm --volumes-from my-mongo -v $(pwd):/backup ubuntu:22.04 tar cvf /backup/mongo-backup.tar /data/db这段命令的原理--volumes-from把my-mongo容器挂载的卷共享给临时容器临时容器再把卷打包到宿主机当前目录。我备份MySQL、MongoDB这类数据库时一直沿用这个套路。3.4 Docker Compose从单容器迈向多容器编排单容器用docker run还凑合但一个项目里应用、数据库、缓存、队列一堆服务时再靠手敲命令就太原始了。Compose就是你用一份YAML描述整个服务栈一条命令全部启动。一个典型的compose.yaml长这样services: web: image: my-web:latest ports: - 8080:80 depends_on: - redis restart: unless-stopped redis: image: redis:7.4-alpine command: redis-server --appendonly yes volumes: - redis-data:/data restart: unless-stopped volumes: redis-data:我解释几个关键点depends_on控制启动顺序web会等redis先启动再启动但它只保证服务启动的先后不保证redis已经可用所以应用内部还得有连接重试逻辑。volumes声明在顶层Compose会自动创建命名卷数据生命周期独立于容器。启动和停止docker compose up -d docker compose ps docker compose logs -f docker compose downdocker compose down默认不会删除命名卷数据还在。如果想要彻底删干净加-v参数但要谨慎一旦加上卷里的数据就没了。我见过有人想“清理环境”结果把数据库卷一起删了整个开发库直接清空当时人都是懵的。所以down -v这条命令一定要看清楚指令再执行。4. 实战案例MySQL 8.0、Redis主从与微服务部署前面铺垫的命令和原理这里落成三个真实能直接抄作业的案例。我有意选了三个热度一直很高的场景数据库、缓存主从、微服务组合部署。4.1 一键拉起MySQL 8.0持久化加调优一次到位MySQL是我被问得最多的容器化应用。下面这条命令兼顾了持久化、字符集、时区和密码配置docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDMyStrongPass2026 \ -e MYSQL_DATABASEapp_db \ -e TZAsia/Shanghai \ -v mysql-data:/var/lib/mysql \ -v /etc/mysql/conf.d:/etc/mysql/conf.d:ro \ --restart unless-stopped \ mysql:8.0MYSQL_ROOT_PASSWORD是初始化root密码的环境变量MYSQL_DATABASE会在首次启动时自动创建数据库。真正重要的是第一个卷mysql-data:/var/lib/mysql这是数据目录不用命名卷的话容器一重建数据就全没了。第二个卷把宿主机的配置目录挂载进容器方便在宿主机上直接调整MySQL的配置文件重启容器后生效。验证是否可用docker exec -it mysql8 mysql -uroot -p能进入MySQL命令行就成功。这里有个隐藏风险容器内MySQL默认的认证插件是caching_sha2_password老版本客户端比如PHP 7.x时代的一些连接库连不上。如果遇到报错Authentication plugin caching_sha2_password cannot be loaded可以在启动时加参数--default-authentication-pluginmysql_native_password或者落库后单独改用户认证。还有一个细节2026年MySQL官方镜像已经不再自动读取/etc/mysql/conf.d里的.cnf后缀文件以外的配置所以你在宿主机挂载配置时文件名一定要是.cnf结尾否则不会生效。这个坑我排查过好几次。4.2 Redis部署从单机到主从复制先跑单节点Redis并开启持久化docker run -d \ --name redis \ -p 6379:6379 \ -v redis-data:/data \ --restart unless-stopped \ redis:7.4-alpine \ redis-server --appendonly yes这里直接把redis-server的启动参数写在镜像名后面--appendonly yes开启AOF持久化。Redis的持久化机制分RDB快照和AOF日志AOF记录每次写操作恢复时更完整代价是文件比RDB大写入性能略有损耗。开发测试环境开AOF没问题生产环境建议两种机制结合并且至少把AOF文件定期备份到宿主机之外的存储。接着搭建一主一从。主库就用上面这个容器从库再跑一个docker run -d \ --name redis-slave \ -p 6380:6379 \ -v redis-slave-data:/data \ --restart unless-stopped \ redis:7.4-alpine \ redis-server --appendonly yes --slaveof 172.17.0.2 6379注意--slaveof参数后面是主库容器的IP和端口。这里有个关键问题两个容器处于同一个默认bridge网络IP会在每次容器重建时变化。想让主从关系稳定更好的方式不是硬编码IP而是用容器网络别名。先创建一个专属网络docker network create redis-net然后两个容器都加--network redis-net主库容器名是redis从库启动时直接写--slaveof redis 6379Docker内置DNS会把redis解析成主库容器IP。这样做的好处是重启主库容器即使IP变了从库连的还是名字不用改配置。生产环境里这种基于网络别名的服务发现方式比写死IP可靠太多了。验证主从状态docker exec -it redis-slave redis-cli INFO replication看到role角色是slavemaster_link_status是up主从就通了。4.3 微服务项目的容器化部署思路最后把范围拉大一点。微服务项目部署无外乎三步把每个服务做成镜像把中间件做成可复用的服务用Compose做整体编排。先说Dockerfile。一个Java Spring Boot服务的Dockerfile核心思路是多阶段构建FROM maven:3.9-eclipse-temurin-17 AS builder WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src RUN mvn package -DskipTests FROM eclipse-temurin:17-jre WORKDIR /app COPY --frombuilder /app/target/app.jar app.jar EXPOSE 8080 ENTRYPOINT [java, -jar, app.jar]第一阶段用Maven镜像把源码编译打包第二阶段用精简的JRE镜像运行。这样最终镜像里没有编译工具链体积能小一半以上。我在项目里这么优化后镜像从800多兆降到200多兆推送和拉取都快了不少。编排层面一个典型的后端加数据库加缓存的项目compose文件结构差不多是services: gateway: build: ./gateway ports: - 8080:8080 depends_on: - user-service - order-service user-service: build: ./user-service environment: - DB_HOSTdb - REDIS_HOSTredis depends_on: db: condition: service_healthy redis: condition: service_healthy order-service: build: ./order-service environment: - DB_HOSTdb - REDIS_HOSTredis depends_on: db: condition: service_healthy db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: pass healthcheck: test: [CMD, mysqladmin, ping, -h, localhost] interval: 10s timeout: 5s retries: 5 volumes: - db-data:/var/lib/mysql redis: image: redis:7.4-alpine healthcheck: test: [CMD, redis-cli, ping] interval: 10s timeout: 3s retries: 5 volumes: db-data:这里最重要的细节是healthcheck。depends_on配合condition: service_healthyCompose会等服务健康检查通过后再启动下游服务这比单纯依赖启动顺序靠谱得多。微服务启动慢是常事数据库初始化也需要时间没有健康检查的话服务起来连不上数据库就直接崩还得手动重启体验很差。healthcheck配置里interval是检查间隔timeout是单次检查超时retries连续失败多少次标记为不健康这几个值建议根据自己服务的启动时间来定不要照抄。5. 故障排查实录那些年在Ubuntu上踩过的坑这部分是我觉得整篇最有价值的地方。下面每个问题都是我在真实环境里遇到并解决过的按出现频率从高到低排。5.1 docker守护进程起不来的排查套路你执行任何docker命令如果报Cannot connect to the Docker daemon多数情况是守护进程没跑。先看系统服务状态systemctl status docker journalctl -u docker.service -n 50journalctl是systemd的日志查看工具-n 50显示最近50行。常见的启动失败原因无非几类/etc/docker/daemon.json格式错误比如JSON里多了个逗号或者镜像加速地址写错。这类错误日志里会明确告诉你JSON解析失败检查语法即可。系统残留的旧iptables规则干扰。Docker需要操作iptables来做端口映射和网络隔离重启前最好清一遍sudo iptables -F sudo iptables -t nat -F然后重启docker。磁盘空间满。Docker数据目录在/var/lib/docker日志和镜像会把这里撑爆。用df -h /var/lib/docker检查满了就要清理空间后再启动。一个自查顺序可以记下来先看磁盘再看daemon.json最后查iptables和systemd日志。按这个顺序走绝大多数问题十分钟内定位。5.2 权限报错与镜像拉取、网络不通问题这几个问题几乎是新手必撞的。permission denied while trying to connect to the Docker daemon socket—— 这个报错我之前解释过是当前用户不在docker组。执行sudo usermod -aG docker $USER后务必重新登录或执行newgrp docker。拉镜像一直超时—— 检查/etc/docker/daemon.json里registry-mirrors是否配置正确配置后是否重启了docker。另外注意镜像加速只对Docker Hub生效如果你拉的是自建仓库或者其他公开仓库加速不生效很正常。容器内网络不通比如curl外网域名超时—— 先分清楚是DNS问题还是路由问题。在容器里执行docker exec -it my-container cat /etc/resolv.conf容器默认继承宿主机的DNS配置。如果宿主机用了systemd-resolved容器里看到的是127.0.0.53这个地址在容器网络里有可能不通。解决办法是在docker run时用--dns 8.8.8.8指定一个公共DNS或者在daemon.json里加一行dns: [8.8.8.8, 223.5.5.5]并重启。这里插一句223.5.5.5是阿里公共DNS我通常把它作为国内网络环境的首选DNS之一因为在国内网络下解析更快。5.3 Ubuntu本身与Docker的几个摩擦点cgroup版本不一致—— Ubuntu 24.04默认启用cgroup v2而Docker从20.10开始就支持v2老版本docker可能在启动时报警告。解决方案是把docker升级到最新稳定版而不是去改内核参数禁用v2。内存不足导致的假死—— Docker容器在OOM内存耗尽时如果没有任何limit它可能会拖垮整个系统。建议运行容器时加上资源限制docker run -d --memory512m --cpus0.5 my-app--memory限制内存上限--cpus限制CPU使用率。生产环境这是必须项不给容器设限就像不给员工设预算出事时谁也拦不住。磁盘被日志塞满—— 除了前面说的log-opts限制日志大小还可以定期清理无用数据docker system prune -a --volumes这条命令会把所有没有被容器使用的镜像、卷、网络全部清掉执行前务必确认没有需要保留的东西。docker system df可以查看磁盘占用分布我建议每周看一眼。5.4 安全加固不能等到出事再做Docker的安全性有几个底线要守住不要用root在宿主机上没事就敲docker exec进容器容器内默认是root但它不等于宿主机root滥用容器权限逃逸风险积累起来不是开玩笑的。不要在compose文件里把数据库端口无脑映射到0.0.0.0上如果宿主机有公网IPMySQL的3306、Redis的6379直接就暴露给全网了。要么不映射要么映射到127.0.0.1-p 127.0.0.1:3306:3306只允许本机访问。定期执行docker system prune减少被攻击面。同时关注镜像安全更新版本锁定后不要一直停在有漏洞的老版本上。有些人觉得容器安全离自己很远其实很多扫描脚本就是扫公有云上暴露的数据库端口的。把端口绑定到127.0.0.1这个习惯能挡住九成以上的扫描攻击成本却几乎为零。最后分享一点个人体会这些年我在各种机器上装Docker从最早的旧版本一路升级到2026年的当前版本最大的感受是Docker本身越来越稳定出问题的大多是环境细节和人的习惯。Ubuntu上装Docker这件事翻来覆去就是版本选型、软件源、用户组、镜像加速这几个关键点把这几个点一次配好后后续日常使用几乎不会再折腾安装层面的东西。如果你看完这篇打算动手我的建议是先把基础命令过一遍然后用第4节的MySQL和Redis案例练手再逐步上Compose和微服务。遇到报错不要慌对照第5节的排查顺序一步步拆开来定位九成问题都能自己解决。容器这条路只要把地基夯实了后面跑什么都顺。
返回列表