拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Docker新手完全指南:从镜像容器到Compose实战避坑

简介这份《Docker新手完全指南从入门到实战万字大全》面向零基础初学者与有一定经验的技术人员尤其适合对容器化技术感兴趣的开发者、运维人员和架构师。内容从容器与虚拟机的本质差异讲起系统梳理镜像、容器、仓库三大核心概念并覆盖Linux、Windows、macOS跨平台安装配置及镜像加速避坑要点。资源包为1个PDF文件大小约1004KB结构清晰便于按章节检索学习。文档深入解析容器生命周期管理、镜像管理与诊断调试命令通过多阶段构建等Dockerfile实践指导镜像优化同时讲解数据卷持久化、网络模式选择与Docker Compose多容器编排并附常见问题排错指南与进阶学习路径。已有201人学习适合希望从零掌握容器化应用开发、测试与部署全流程的读者系统研读。1. Docker新手完全指南从入门到实战万字大全.pdf 到底该从哪下手很多人第一次打开一份叫《Docker新手完全指南从入门到实战万字大全.pdf》的文档翻到第三页就卡住了——镜像、容器、仓库、Dockerfile、Docker Compose 一堆名词砸过来每个字都认识连起来不知道先装哪个。我见过太多人卡在“docker安装教程”这一步反复重装系统也见过有人照着“docker安装mysql8.0并使用”的帖子敲完命令结果容器起来三秒就退出日志里只有一行看不懂的报错。这份指南要解决的不是“Docker是什么”这种教科书问题而是让你在一台干净的 Linux 或 Windows 机器上从零把镜像拉下来、把容器跑起来、把 Dockerfile 写对、把 Docker Compose 编排跑通最后能自己排查“docker网络不通”“容器目录没权限”这类真实故障。适合刚接触容器、被各种镜像源和命令绕晕的后端、运维和测试同学也适合想把手头 Java 应用容器化但一直没跑通的开发者。下面按“先立住概念、再动手复现、最后避坑”的顺序拆开讲每一步都给能直接抄的命令和参数说明。2. 镜像、容器与 Dockerfile先把三个核心概念钉死2.1 镜像不是压缩包容器也不是轻量虚拟机镜像Image本质是一个只读的层叠文件系统每一层对应 Dockerfile 里的一条指令。你执行docker pull拉下来的不是一个完整系统而是一堆按内容寻址的 layerDocker 用联合文件系统把它们挂载成一个可读的根目录。容器Container则是在这个只读镜像之上加了一个可写层再加一套命名空间namespace做资源隔离、一套控制组cgroup做资源限制。所以容器启动快因为它不需要模拟硬件、不需要跑完整内核它直接复用宿主机内核只是把进程看到的 PID、网络、挂载点、主机名换了一套。这里有个反直觉的点容器里的“根文件系统”并不是一个真实磁盘分区而是镜像层叠加后的视图。你在容器里写文件写的是最上面那个可写层容器一删可写层跟着消失镜像层纹丝不动。这就是为什么“容器里改配置重启就丢”是正常现象要持久化必须挂 volume 或 bind mount。理解这一点后面遇到“docker容器怎么赋予目录读写权限”“dockerdesktop中如何对已部署的容器增删文件夹和文件”才不会懵。镜像的构建靠 Dockerfile。Dockerfile 是一份纯文本指令清单每条指令生成一层。常见指令就那几个FROM指定基础镜像RUN在构建时执行命令COPY把宿主机文件复制进去WORKDIR设工作目录EXPOSE声明端口CMD和ENTRYPOINT定义容器启动时跑什么。新手最容易混的是RUN和CMDRUN发生在构建阶段结果固化进镜像层CMD发生在容器启动阶段每次启动都可能不同。把apt install写成CMD镜像里根本没装容器一跑就报 command not found这是血泪经验里排前三的翻车点。2.2 在 Ubuntu 上装 Docker 并跑通第一个容器先在一台 Ubuntu 22.04 上把 Docker 装好。不要用apt install docker这种老包版本太旧很多新特性没有。用官方仓库装命令如下# 更新包索引并安装基础依赖 sudo apt-get update sudo apt-get install -y ca-certificates curl gnupg lsb-release # 添加 Docker 官方 GPG 密钥 sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg # 写入软件源注意 $(lsb_release -cs) 会自动取当前系统代号 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 # 安装 Docker Engine 和 Compose 插件 sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin # 把当前用户加入 docker 组避免每次 sudo sudo usermod -aG docker $USER newgrp docker装完执行docker version和docker compose version验证。如果docker compose报docker: unknown command: docker compose说明装的是老版独立二进制docker-compose新版插件没装上回头检查docker-compose-plugin是否安装成功。接着拉一个最小镜像跑起来# 拉取 alpine 镜像体积只有几 MB docker pull alpine:3.19 # 启动一个交互式容器进去执行 shell docker run -it --rm alpine:3.19 /bin/sh # 在容器内执行 echo hello from container exit-it分配交互式终端--rm容器退出后自动删除避免留下一堆停止的容器占名字。alpine:3.19是镜像名加标签不写标签默认latest生产环境千万别用latest因为下次拉可能就变了。进去之后你看到的/就是镜像层叠加出来的根目录exit之后容器销毁可写层里的改动全部消失。2.3 写一个能跑 Java 应用的 Dockerfile热搜里“java容器”出现频率很高很多人的真实需求是把 Spring Boot 的 jar 包打成镜像。下面是一个多阶段构建的 Dockerfile能显著减小最终镜像体积# 第一阶段构建阶段用带 JDK 的镜像 FROM eclipse-temurin:17-jdk AS builder WORKDIR /build # 只复制 pom 先拉依赖利用 Docker 层缓存 COPY pom.xml . RUN mvn dependency:go-offline -B # 再复制源码编译 COPY src ./src RUN mvn clean package -DskipTests # 第二阶段运行阶段只带 JRE FROM eclipse-temurin:17-jre WORKDIR /app # 从构建阶段复制产物不把 Maven 和源码带进来 COPY --frombuilder /build/target/*.jar app.jar # 声明端口仅作文档用途 EXPOSE 8080 # 启动命令用 exec 形式避免 shell 包裹导致信号传递问题 ENTRYPOINT [java, -jar, app.jar]关键参数说明AS builder给阶段命名后面COPY --frombuilder才能引用dependency:go-offline先把依赖下到本地仓库只要 pom 不变这层缓存就一直有效改源码不会触发重新下依赖-DskipTests跳过测试加速构建CI 里通常单独跑测试ENTRYPOINT用 JSON 数组形式PID 1 直接是 java 进程能正确接收docker stop发来的 SIGTERM用 shell 形式的话信号会被 shell 吞掉容器要等超时才退出。构建命令docker build -t myapp:1.0 .最后的点表示构建上下文是当前目录别小看这个点写错路径会导致COPY找不到文件。3. Docker Compose 编排把 MySQL、Redis 和应用串起来3.1 为什么单容器命令不够用Compose 解决什么用docker run起一个 MySQL 要写一长串参数端口映射、数据卷、环境变量、网络、字符集。起第二个 Redis 又要重复一遍而且两个容器默认不在同一网络应用连不上。Docker Compose 用一个 YAML 文件描述所有服务一条docker compose up全部拉起服务之间自动在同一自定义网络里可以用服务名当主机名互相访问。热搜里“docker compose 部署nacos 3.x”“docker安装redis主从”“docker安装mysql8.0并使用”都是典型的多容器场景用 Compose 管理比手敲docker run可靠得多。Compose 文件的核心结构就四块services定义每个容器volumes定义命名卷networks定义网络顶层version在新版里已经可以省略。每个 service 下常用的键有image、build、ports、environment、volumes、depends_on、networks、restart。depends_on只保证启动顺序不保证依赖服务已经“就绪”MySQL 容器起来了但初始化还没完成应用照样连不上这是新手最容易踩的坑后面避坑章节细说。3.2 一份能直接跑的 MySQL Redis 应用 compose 文件下面这份docker-compose.yml把 MySQL 8.0、Redis 7 和一个 Java 应用串起来数据持久化到命名卷网络用自定义 bridgeservices: mysql: image: mysql:8.0 container_name: demo-mysql restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: rootpass MYSQL_DATABASE: demo MYSQL_USER: appuser MYSQL_PASSWORD: apppass TZ: Asia/Shanghai command: - --character-set-serverutf8mb4 - --collation-serverutf8mb4_unicode_ci ports: - 3306:3306 volumes: - mysql-data:/var/lib/mysql - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro healthcheck: test: [CMD, mysqladmin, ping, -h, localhost, -uroot, -prootpass] interval: 10s timeout: 5s retries: 5 networks: - demo-net redis: image: redis:7-alpine container_name: demo-redis restart: unless-stopped command: [redis-server, --appendonly, yes] ports: - 6379:6379 volumes: - redis-data:/data networks: - demo-net app: build: . container_name: demo-app restart: unless-stopped depends_on: mysql: condition: service_healthy redis: condition: service_started environment: SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/demo?useSSLfalseserverTimezoneAsia/Shanghai SPRING_DATASOURCE_USERNAME: appuser SPRING_DATASOURCE_PASSWORD: apppass SPRING_REDIS_HOST: redis ports: - 8080:8080 networks: - demo-net volumes: mysql-data: redis-data: networks: demo-net: driver: bridge逐项说明restart: unless-stopped让容器随 Docker 启动而启动除非手动 stopMYSQL_ROOT_PASSWORD等环境变量是官方镜像约定的初始化参数第一次启动时生效卷里已有数据就不会再执行command覆盖镜像默认启动参数这里强制 utf8mb4 字符集避免中文乱码./init.sql:/docker-entrypoint-initdb.d/init.sql:ro把初始化 SQL 挂进去只在数据目录为空时执行:ro表示只读挂载healthcheck用mysqladmin ping判断 MySQL 真正可用depends_on配合condition: service_healthy才能让 app 等到 MySQL 健康后再启动这是解决“应用启动比数据库快导致连接失败”的标准做法SPRING_DATASOURCE_URL里的主机名写mysql因为 Compose 自动给服务名做了 DNS 解析不用写 IP。启动命令docker compose up -d-d后台运行。查看状态docker compose ps看日志docker compose logs -f app停止并删除容器docker compose down加-v连命名卷一起删。注意down -v会清空数据库数据生产环境慎用这就是没有后悔药的操作。3.3 容器资源隔离与权限别让一个容器拖垮宿主机热搜里“容器资源隔离”“docker容器怎么赋予目录读写权限”是高频问题。默认情况下容器能用宿主机所有 CPU 和内存一个内存泄漏的容器能把整台机器拖死。在 Compose 里加限制services: app: # 限制最多使用 1.5 个 CPU 和 1G 内存 deploy: resources: limits: cpus: 1.5 memory: 1G reservations: memory: 512Mlimits是硬上限超过会被 cgroup 限制或 OOM killreservations是软预留调度时参考。注意在非 Swarm 模式下deploy部分对docker compose也生效但老版本 Compose 可能忽略用docker compose version确认是 v2 插件版。目录读写权限问题几乎每个人都遇到容器里进程的 UID 和宿主机挂载目录的属主不一致导致 Permission denied。比如 MySQL 官方镜像里 mysql 用户 UID 是 999你挂一个宿主机上 root 属主的目录进去容器里写不了。解决办法有三种一是chown 999:999 ./data把宿主机目录属主改成容器内用户二是在 Compose 里指定user: 1000:1000让容器以宿主机当前用户身份跑三是用命名卷而不是 bind mount让 Docker 自己管理权限。生产环境推荐命名卷bind mount 适合开发时挂配置文件。4. 避坑与排查那些让新手卡一整天的真实故障4.1 现象容器启动后立刻退出日志只有一行原因通常有三类。第一CMD或ENTRYPOINT里的命令在前台没有持续运行的进程比如你写CMD service nginx start这个命令执行完就返回容器认为主进程结束就退出。正确做法是CMD [nginx, -g, daemon off;]让 nginx 前台运行。第二配置文件路径写错进程启动即报错退出用docker logs 容器名看具体报错。第三依赖的服务没就绪应用连不上数据库直接退出用depends_on加healthcheck解决。排查顺序先docker ps -a找到退出容器 ID再docker logs id看最后几十行八成能定位。4.2 现象docker网络不通容器之间 ping 不通原因多半是容器不在同一网络。默认docker run起的容器挂在bridge网络但彼此只能用 IP 通信不能用容器名。Compose 会为每个项目创建独立网络服务名自动解析。如果你手动docker run两个容器想互相访问要么docker network create mynet然后两个都--network mynet要么用--link已不推荐。另一个常见原因是宿主机防火墙拦了 Docker 的转发链iptables -L FORWARD看策略Docker 默认会插自己的规则但如果之前装过其他防火墙软件可能冲突。还有docker network inspect 网络名看容器是否真的加入docker exec 容器 cat /etc/hosts看 DNS 解析有没有服务名。4.3 现象镜像拉取超时卡在 pulling 不动国内网络环境下拉 Docker Hub 镜像经常超时。解决办法是配置镜像加速器在/etc/docker/daemon.json里加{ registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com ] }改完sudo systemctl daemon-reload sudo systemctl restart docker。注意镜像加速器地址会变用之前先确认当前可用的别抄了个已经停服的地址然后怀疑人生。另外docker pull卡住时按 CtrlC 不会清理临时层磁盘空间会被占用docker system prune清理未使用的镜像和缓存但这条命令会删掉所有没在用的镜像执行前想清楚。4.4 现象Windows 上 Docker Desktop 启动报 virtualization support not detected这个报错说明 BIOS 里虚拟化没开或者和 Hyper-V/WSL2 冲突。先确认 CPU 虚拟化在 BIOS 里是 Enabled然后在 Windows 功能里勾选“虚拟机平台”和“适用于 Linux 的 Windows 子系统”重启。如果之前装过 VirtualBox 或 VMware可能和 Hyper-V 抢占需要关掉 Hyper-V 或改用 WSL2 后端。Docker Desktop 设置里 Resources 可以切 WSL2 和 Hyper-VWin11 推荐 WSL2性能更好文件挂载也快。装完在 PowerShell 里docker run hello-world验证能跑通说明后端正常。4.5 现象docker compose 命令找不到或版本不对docker: unknown command: docker compose说明装的是老版独立docker-compose新版是docker compose插件形式。检查docker compose version如果报错就装docker-compose-plugin。Ubuntu 上apt install docker-compose-pluginCentOS 上yum install docker-compose-plugin。如果两个命令都有但行为不一致注意docker-compose带横线是 v1 Python 版docker compose空格是 v2 Go 版v1 已经停止维护新项目一律用 v2。Compose 文件里version字段在 v2 里已废弃写了会有 warning删掉即可。5. 进阶技巧用健康检查和多阶段构建把镜像压到最小5.1 健康检查不只是给 Compose 看的healthcheck定义在镜像或 Compose 里Docker 会按 interval 周期执行 test 命令根据退出码标记容器 healthy 或 unhealthy。很多人以为它只服务于depends_on其实docker ps的 STATUS 列会显示(healthy)编排工具和负载均衡也能据此摘流量。写健康检查有三个参数要调interval间隔太短浪费资源太长故障发现慢一般 10 到 30 秒timeout单次检查超时要大于正常响应时间retries连续失败几次才标记 unhealthy避免网络抖动误判。start_period给容器启动留缓冲启动期间失败不计入 retries对 Java 应用特别有用因为 JVM 启动加 Spring 初始化可能要几十秒。healthcheck: test: [CMD, curl, -f, http://localhost:8080/actuator/health] interval: 15s timeout: 5s retries: 3 start_period: 60s注意test用 CMD 形式时命令必须在镜像里存在alpine 基础镜像没有 curl得先apk add curl或者改用 wget。用CMD-SHELL可以写 shell 管道但会多一层 shell 进程。5.2 多阶段构建加 .dockerignore 才是减体积组合拳多阶段构建把编译工具链留在构建阶段最终镜像只带运行时这是减体积最有效的手段。但很多人忽略了.dockerignore导致COPY . .把.git、target、node_modules、日志文件全塞进构建上下文构建慢、镜像大还可能把密钥文件打进去。在项目根目录建.dockerignore.git .gitignore target/ node_modules/ *.log .env .idea/ *.iml构建上下文变小COPY层缓存命中率也高。再配合docker image ls看镜像大小docker history 镜像名看每层占多少空间找出体积大头。常见优化基础镜像选 alpine 或 distroless合并RUN指令减少层数apt install后清理/var/lib/apt/listsJava 应用用 jre 而不是 jdk。我一般会把最终镜像控制在 200MB 以内超过就回头查哪层没清干净。5.3 一个我反复用的验证习惯每次写完 Dockerfile 或 Compose 文件我不会直接上生产而是先做三件事第一docker build后docker run一个临时容器进去手动执行ENTRYPOINT里的命令确认能跑起来第二docker compose config校验 YAML 语法和变量替换这个命令会把最终生效的配置打印出来环境变量有没有正确注入一目了然第三故意docker stop容器看它是不是在 10 秒内优雅退出如果每次都要等超时才被杀说明ENTRYPOINT信号传递有问题回去改成 exec 形式。这套习惯帮我省了无数次上线后的半夜排查。容器这东西构建时多花五分钟验证运行时就少踩一个坑。希望帮到你。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门