Docker 基础实战完整指南

Docker 基础实战完整指南 Docker 基础实战完整指南定位零基础 → 能独立构建/部署/调试容器化应用环境华为云 ECS ecs-fce0-0001 (2vCPU/4GiB/ac9.large.2/Ubuntu 24.04)工具Docker CE 29.5.3 Compose v5.1.4风格「原理简述 代码实操 常见坑点 企业小技巧」Part 1: 为什么需要 Docker——从痛点出发1.1 传统部署的噩梦没有 Docker 的年代你的部署流程可能是这样的开发环境(Win/Mac) → 测试环境(Linux) → 生产环境(CentOS) 在我机器上能跑! 缺依赖/版本不对 JDK版本冲突!痛点描述Docker 解决方案环境不一致Win vs Linux vs Mac 差异容器统一环境一次构建到处运行依赖冲突项目A用 JDK8项目B用 JDK17每个容器独立环境部署慢手动装依赖 → 1~2 小时镜像秒级启动资源浪费每个应用一台虚拟机容器共享内核一台机器跑几十个1.2 容器 vs 虚拟机┌─────────────────────────────────────────────────────────────┐ │ Virtual Machine (虚拟机) │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ App A │ │ App B │ │ App C │ │ │ │ Bin/Libs │ │ Bin/Libs │ │ Bin/Libs │ ← 各自完整的 OS │ │ │ Guest OS │ │ Guest OS │ │ Guest OS │ │ │ └──────────┘ └──────────┘ └──────────┘ │ │ Hypervisor (虚拟化层) │ │ Host OS (宿主机 OS) │ │ Physical Hardware │ └─────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────┐ │ Docker Container (容器) │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ App A │ │ App B │ │ App C │ │ │ │ Bin/Libs │ │ Bin/Libs │ │ Bin/Libs │ ← 仅含应用依赖 │ │ └──────────┘ └──────────┘ └──────────┘ │ │ Docker Engine (容器引擎) │ │ Host OS (共享内核!) │ │ Physical Hardware │ └─────────────────────────────────────────────────────────────┘维度虚拟机 (VM)容器 (Container)启动速度分钟级秒级磁盘占用GB 级MB 级内存开销每个额外 ~512MB几乎无额外开销隔离性完整隔离进程级隔离内核每个 VM 独立内核共享宿主机内核← 关键差异1.3 镜像 vs 容器类 vs 实例Image (镜像) Container (容器) ┌──────┐ ┌──────────────┐ │ JDK │ │ JDK (layer 3)│ ├──────┤ -run- ├──────────────┤ │ Tomcat│ │Tomcat(layer2)│ ← 镜像的运行时 ├──────┤ ├──────────────┤ │ War │ │ War (layer 1)│ 实例 可写层 └──────┘ └──────────────┘ 只读 读写(R/W layer) 类比 Class → new → Object Image → run → Container1.4 Hello-World 拆解执行流程在docker-01 (121.36.42.55)上实际执行$dockerpull hello-world:latest Digest: sha256:0e760fdfbc48ba8041e7c6db999bb40bfca508b4be580ac75d32c4e29d202ce1 Status: Downloaded newer imageforhello-world:latest $dockerrun--namehw-demo hello-world Hello from Docker!This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps:1. The Docker client contacted the Docker daemon.2. The Docker daemon pulled thehello-worldimage from the Docker Hub.(amd64)3. The Docker daemon created a new container from that imagewhichruns the executable that produces the output you are currently reading.4. The Docker daemon streamed that output to the Docker client,whichsent it to your terminal.执行流程拆解① docker run hello-world Docker CLI ──────────────────────────► Docker Daemon │ ② 本地有没有镜像 │ ├─ 没有 → 去 Registry 拉取 ──────┤ │ ③ 下载 hello-world:latest └─ 有 → 直接用 │ │ ④ 基于镜像创建容器 │ ├─ 分配文件系统 (可写层) │ ├─ 分配网络 (默认 bridge) │ └─ 启动进程 │ │ ⑤ 执行容器内程序stdout 流回 Client │ └─ 程序结束 → 容器退出 (Exited)# 验证容器生命周期$dockerps-a--filternamehw-demo NAMES IMAGE STATUS PORTS hw-demo hello-world Exited(0)Less than a second ago# 镜像大小仅 9.49KB$dockerimages hello-world IMAGE ID DISK USAGE CONTENT SIZE hello-world:latest 0e760fdfbc4825.9kB9.49kB企业真题“docker run 背后的完整流程是什么”答CLI → Daemon → 检查本地镜像 → (无)拉取 Registry → 创建容器(分配网络/存储/Cgroup) → 启动进程 → 输出流回客户端Part 2: 环境搭建与核心命令速成1小时上手2.1 三平台安装以 Ubuntu 24.04 为例# Step1: 卸载旧版本apt-getremove-ydocker.io docker-doc podman-docker containerd runc# Step2: 安装依赖apt-getupdateapt-getinstall-yca-certificatescurl# Step3: 添加 Docker GPG 密钥阿里云镜像install-m0755-d/etc/apt/keyringscurl-fsSLhttps://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg\-o/etc/apt/keyrings/docker.ascchmodar /etc/apt/keyrings/docker.asc# Step4: 添加仓库注意 CODENAME 变量echodeb [arch$(dpkg --print-architecture)signed-by/etc/apt/keyrings/docker.asc] \ https://mirrors.aliyun.com/docker-ce/linux/ubuntu noble stable\/etc/apt/sources.list.d/docker.list# Step5: 安装apt-getupdateapt-getinstall-y\docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin# Step6: 配置镜像加速 log 限制mkdir-p/etc/dockercat/etc/docker/daemon.jsonEOF { registry-mirrors: [ https://docker.1ms.run, https://docker.xuanyuan.me ], log-driver: json-file, log-opts: { max-size: 10m, max-file: 3 } } EOFsystemctl daemon-reloadsystemctl restartdockersystemctlenabledocker# Step7: 验证$docker--versionDocker version29.5.3, build d1c06ef $dockercompose version Docker Compose version v5.1.42.2 高频命令实战清单在docker-01上的真实操作# ──────────── 1. docker run ────────────$dockerrun-d--namenginx-demo-p8088:80 nginx:alpine# -d: 后台运行 (detached)# --name: 给容器命名# -p 8088:80: 端口映射 宿主机:容器# ──────────── 2. docker ps (查看运行中) ────────────$dockerps--formattable {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}NAMES IMAGE STATUS PORTS nginx-demo nginx:alpine Up5minutes0.0.0.0:8088-80/tcp# ──────────── 3. docker logs (实时看日志) ────────────$dockerlogs nginx-demo--tail3# 关键参数: -f (follow实时) --tail N (最后N行) --since (时间范围)# ──────────── 4. docker exec (进入容器) ────────────$dockerexecnginx-demosh-cnginx -v 21Nginx version:1.27.4# exec 让你穿透容器边界在容器内执行命令# 常用: docker exec -it name /bin/bash 进入交互式 shell# ──────────── 5. docker cp (传文件) ────────────$echohost_content/tmp/host-file.txt $dockercp/tmp/host-file.txt nginx-demo:/tmp/ $dockerexecnginx-democat/tmp/host-file.txt host_content# 双向传输: 宿主机→容器 和 容器→宿主机# ──────────── 6. docker stats (资源监控) ────────────$dockerstats --no-stream nginx-demo# 实时显示 CPU/MEM/NET/DISK 使用情况命令速查表命令作用常用参数docker run -d --name X -p H:C IMG后台启动容器--restart-v-e--networkdocker ps -a查看所有容器--filter--format-qdocker logs -f id实时看日志--tail N--sincedocker exec -it id sh进入容器-u root(以root执行)docker cp HOST_PATH ID:CONT_PATH传文件-a(保留权限)docker inspect id查看详细配置--format(Go模板)docker stop/start/restart id启停控制-t(等待超时秒数)docker rm id删除容器-f(强制)-v(同时删volume)docker rmi image删除镜像-f(强制)docker compose up -dCompose 启动--build-f2.3 镜像管理$dockerimages--formattable {{.Repository}}\t{{.Tag}}\t{{.Size}}REPOSITORY TAG SIZE my-nginx v192.7MB nginx alpine93.6MB redis7-alpine57.8MB mysql8.01.1GB alpine latest13.1MB小技巧Alpine Linux 基础镜像仅 13.1MB是制作精简镜像的首选但注意它用musl libc而非glibc。Part 3: 镜像构建——从 Dockerfile 开始3.1 Dockerfile 核心指令精讲FROM ← 基础镜像必须第一行 WORKDIR ← 设置工作目录 COPY/ADD ← 复制文件COPY 简单复制, ADD 支持URL/tar解压 RUN ← 构建时执行命令每RUN一层layer ENV ← 环境变量 EXPOSE ← 声明端口仅是文档, 不实际映射 CMD ← 容器启动默认命令可被 docker run 覆盖 ENTRYPOINT ← 容器入口docker run 参数作为其参数 VOLUME ← 声明数据卷 USER ← 切换用户 HEALTHCHECK ← 健康检查指令执行时机是否可被覆盖多层影响RUN构建时 (build)否每 RUN 一层CMD运行时 (run)docker run IMG cmd完全覆盖只有最后一层ENTRYPOINT运行时 (run)需--entrypoint强覆盖只有最后一层COPY vs ADD指令功能建议COPY从构建上下文复制文件优先使用ADD复制 URL下载 自动解压tar仅在需要tar自动解压时用3.2 实战构建一个 Nginx 静态网站在docker-01上实操$mkdir/tmp/docker-nginx $cat/tmp/docker-nginx/DockerfileDEOF FROM nginx:alpine LABEL maintaineradminexample.com LABEL descriptionNginx 静态网站实战 COPY index.html /usr/share/nginx/html/ EXPOSE 80 CMD [nginx, -g, daemon off;] DEOF$echoh1Hello from Docker Nginx!/h1/tmp/docker-nginx/index.html $dockerbuild-tmy-nginx:v1 /tmp/docker-nginx# Step 1/6 : FROM nginx:alpine# Step 2/6 : LABEL maintainer...# Step 3/6 : COPY index.html /usr/share/nginx/html/# Step 4/6 : EXPOSE 80# Step 5/6 : CMD [nginx, -g, daemon off;]# Successfully built my-nginx:v1$dockerrun-d--namenginx-build-demo-p8090:80 my-nginx:v1 $curl-shttp://localhost:8090/h1Hello from Docker Nginx!/h1$dockerimages my-nginx--formattable {{.Repository}}\t{{.Tag}}\t{{.Size}}REPOSITORY TAG SIZE my-nginx v192.7MB3.3 进阶多阶段构建优化镜像大小┌────────────────────────────────────────────────────────┐ │ 传统构建 (1个镜像) │ │ ┌──────────────────────┐ │ │ │ FROM JDK │ │ │ │ COPY src . │ │ │ │ RUN mvn package │ ← 构建工具 代码都留在镜像 │ │ │ CMD java -jar ... │ 体积: 500MB │ │ └──────────────────────┘ │ └────────────────────────────────────────────────────────┘ ┌────────────────────────────────────────────────────────┐ │ 多阶段构建 (Multi-stage) │ │ ┌──────────────────────┐ ┌──────────────────┐ │ │ │ Stage 1: build │ │ Stage 2: runtime │ │ │ │ FROM maven:3.9 AS b │ │ FROM jre:17 │ │ │ │ COPY src . │ │ COPY --fromb /app│ │ │ │ RUN mvn package │──▶│ CMD java -jar ... │ │ │ └────────┬─────────────┘ └──────────────────┘ │ │ │ 体积: 120MB ↓↓↓ │ │ 构建产物 (.jar) 仅复制到运行阶段 │ └────────────────────────────────────────────────────────┘多阶段构建 Dockerfile 模板# 阶段1: 编译 FROM maven:3.9-eclipse-temurin-17 AS build WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline # 缓存依赖(加速后续构建) COPY src ./src RUN mvn package -DskipTests # 阶段2: 运行 FROM eclipse-temurin:17-jre WORKDIR /app COPY --frombuild /app/target/*.jar app.jar EXPOSE 8080 CMD [java, -jar, app.jar]企业级技巧.dockerignore避免node_modules/,.git/,*.md进入构建上下文层优化把不变的层放前面依赖 代码变动层放后面非 root 用户USER 1000避免容器内 root 权限健康检查HEALTHCHECK CMD curl -f http://localhost/ || exit 1Part 4: 容器网络与数据持久化4.1 网络模式实战Docker 三大网络模式模式特点适用场景bridge(默认)独立网络栈NAT 通信一般容器需端口映射host共享宿主机网络栈高性能场景如监控 agentnone无网络完全隔离安全敏感如密钥生成# 查看网络模式$dockernetworklsNETWORK ID NAME DRIVER SCOPE 683234b9fb40 bridge bridgelocal← 默认 bridge 02635a047886hosthostlocal0cf4b1c9abef none nulllocal4.2 自定义网络容器间 DNS 互通# 创建自定义网络内置 DNS 解析$dockernetwork create app-net $dockernetwork inspect app-net--formatSubnet: {{range .IPAM.Config}}{{.Subnet}}{{end}}Subnet:172.18.0.0/16# 在同一网络中启动容器$dockerrun-d--nameweb--networkapp-net nginx:alpine $dockerrun-d--nameapp--networkapp-net alpinesleep300# DNS 解析测试容器名 → IP自动$dockerexecappping-c2web PING web(172.18.0.2):56data bytes64bytes from172.18.0.2:seq0ttl64time0.120ms64bytes from172.18.0.2:seq1ttl64time0.115ms关键自定义 bridge 网络提供自动 DNS 解析容器间用名称即可通信不用--link已废弃4.3 Volume vs Bind Mount┌──────────────────────────────────────────────────┐ │ Volume (Docker 管理) │ │ Container ───► /var/lib/mysql │ │ │ │ │ ┌──────▼─────────┐ │ │ │ /var/lib/docker│ │ │ │ /volumes/... │ ← Docker 管理 │ │ └────────────────┘ │ └──────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────┐ │ Bind Mount (宿主机直连) │ │ Container ───► /app/config │ │ │ │ │ ┌──────▼──────┐ │ │ │ /home/user/ │ ← 用户管理 │ │ │ config/ │ │ │ └─────────────┘ │ └──────────────────────────────────────────────────┘类型管理方路径跨容器适用场景VolumeDocker/var/lib/docker/volumes/✅数据库、RedisBind Mount用户任意宿主机路径❌开发调试、配置热更新实战Volume 持久化数据在 docker-01 上已执行$dockervolume create mysql-data $dockerrun-d--namemysql-persist\-eMYSQL_ROOT_PASSWORDroot123\-vmysql-data:/var/lib/mysql\mysql:8.0# 写入测试数据$dockerexecmysql-persist mysql-uroot-proot123\-eCREATE TABLE testdb.demo(id INT); INSERT INTO testdb.demo VALUES(42);# 重启容器$dockerrestart mysql-persist# 数据仍在$dockerexecmysql-persist mysql-uroot-proot123\-eSELECT * FROM testdb.demo;------|id|------|42|------Bind Mount 演示$echohost file content/tmp/bind-demo.txt $dockerrun--rm-v/tmp/bind-demo.txt:/data/file.txt:ro alpinecat/data/file.txthostfilecontent# :ro read-only防止容器修改宿主机文件Part 5: Compose 编排——告别单容器时代5.1 docker-compose.yml 语法精要核心三要素services,networks,volumes# docker-compose.yml# 三要素: services, networks, volumesservices:# 定义服务容器web:# 服务名即 DNS 名image:nginx:alpineports:-9090:80volumes:-./html:/usr/share/nginx/html:rorestart:unless-stopped# 生产必备!redis:image:redis:7-alpineports:-6379:6379restart:unless-stoppedcommand:redis-server--save 60 1--loglevel warning5.2 实战一键部署 Nginx Redis真实执行docker-01$mkdir-p/tmp/compose-demo/html $echoh1Compose Demo - Nginx Redis/h1/tmp/compose-demo/html/index.html $dockercompose up-d# [] Running 4/4# Network compose-demo_default Created# Container compose-demo-web-1 Started# Container compose-demo-redis-1 Started$dockerps--formattable {{.Names}}\t{{.Image}}\t{{.Status}}NAMES IMAGE STATUS compose-demo-web-1 nginx:alpine Up5seconds compose-demo-redis-1 redis:7-alpine Up5seconds# 测试 Web$curl-shttp://localhost:9090/h1Compose Demo - Nginx Redis/h1# 测试 Redis$dockerexeccompose-demo-redis-1 redis-clipingPONG5.3 环境变量管理# .env 文件自动加载$cat.envREDIS_PASSWORDsecret123DB_HOSTmysql-db# docker-compose.yml 中使用services: app: environment: -REDIS_PASSWORD${REDIS_PASSWORD:-default}# 有默认值-DB_HOST${DB_HOST:?DB_HOST is required}# 必须设置关键注意depends_on只等容器启动不等待服务就绪MySQL 可能需要 30s 初始化。解决方案健康检查 wait-for-it.sh脚本restart: unless-stopped生产必备手动 stop 不会重启其他退出都重启restart 值行为no(默认)不自动重启always无论退出码都重启on-failure:N仅非0退出码重启最多 N 次unless-stopped推荐手动 stop 不重启其他都重启5.4 常用 Compose 命令dockercompose up-d# 后台启动dockercompose down# 停止并删除容器/网络dockercompose down-v# 同时删除 Volumedockercomposeps# 查看服务状态dockercompose logs-fweb# 实时日志dockercompose restart# 重启所有服务dockercompose up-d--build# 重新构建并启动Part 6: 调试与故障排查实战6.1 容器启动失败5 步诊断法Container 启动失败! │ ┌─────▼──────┐ ① │ docker logs │ → 看错误输出 └─────┬──────┘ │ ┌─────▼──────────────┐ ② │ docker inspect │ → 查 CMD/Entrypoint/Env └─────┬──────────────┘ │ ┌─────▼────────────────────┐ ③ │ docker exec -it id sh │ → 进容器检查文件/权限 └─────┬────────────────────┘ │ ┌─────▼────────────────────┐ ④ │ netstat -tulnp | grep :XX│ → 检查端口冲突 └─────┬────────────────────┘ │ ┌─────▼────────────────────┐ ⑤ │ /var/log/syslog/audit.log│ → 宿主机日志 └──────────────────────────┘ │ [ 定位根因! ]实际诊断演示# 故意创建一个会退出的容器$dockerrun-d--namebad-cmd alpine /bin/nonexistent $dockerps-a--formattable {{.Names}}\t{{.Status}}NAMES STATUS bad-cmd Exited(127)1second ago ← 启动即退出, 退出码127$dockerlogs bad-cmdexec/bin/nonexistent: no suchfileor directory ← 定位到问题!$dockerinspect bad-cmd--formatCMD: {{.Config.Cmd}}CMD:[/bin/nonexistent]← 确认 CMD 错误6.2 经典问题合集错误原因解决port is already allocated端口冲突lsof -i :8080找出占用进程 换端口standard_init_linux.go:228: exec user process caused: no such file or directoryCRLF 换行符dos2unix或git config core.autocrlffalsePermission denied挂载目录SELinux/AppArmor加:z标签或改用非 root 用户bind: address already in use端口已被占用检查docker ps已存在的容器429 Too Many Requests镜像仓库限流换镜像源或等待COPY failed: file not found构建上下文路径不对检查.dockerignore和 Dockerfile 中的相对路径6.3 端口冲突实战真实踩坑# docker-01 上的真实错误$dockerrun-d--nameweb-demo-p8088:80 nginx:alpine Error response from daemon: Bindfor0.0.0.0:8088 failed: port is already allocated# 诊断$dockerps--formattable {{.Names}}\t{{.Ports}}NAMES PORTS nginx-demo0.0.0.0:8088-80/tcp ←8088已被占用!# 解决先停掉占用的或换端口$dockerstop nginx-demodockerrmnginx-demo# 或$dockerrun-d--nameweb-demo-p9090:80 nginx:alpinePart 7: 企业级入门实践7.1 CI/CD 中的 Docker┌──────────────────────────────────────────────────────┐ │ Jenkins / GitHub Actions │ │ │ │ git push ──► Build ──► Test ──► Push Image ──► Deploy│ │ │ │ │ │ docker build docker push │ │ │ │ │ │ ┌────▼────┐ ┌───────▼────────┐ │ │ │ 本地镜像 │ │ Harbor/ECR/ACR │ │ │ └─────────┘ │ (私有仓库) │ │ │ └───────┬────────┘ │ │ │ │ │ docker pull │ │ │ │ │ ┌─────▼─────┐ │ │ │ K8s / ECS │ │ │ └───────────┘ │ └──────────────────────────────────────────────────────┘# GitHub Actions 示例name:Docker Build Pushon:[push]jobs:build:runs-on:ubuntu-lateststeps:-uses:actions/checkoutv3-name:Build Imagerun:docker build-t myapp:${{github.sha}}.-name:Push to Registryrun:|docker tag myapp:${{ github.sha }} registry.example.com/myapp:${{ github.sha }} docker push registry.example.com/myapp:${{ github.sha }}7.2 Docker 最佳实践 Checklist☑ 使用 .dockerignore 避免打包无用文件 ☑ 镜像分层合理不变层在上变化层在下 ☑ 非 root 用户运行容器 (USER 1000) ☑ 启用健康检查 (HEALTHCHECK) ☑ 标签规范 v1.2.3-{BUILD_NUMBER} ☑ 多阶段构建减小镜像体积 ☑ 日志输出到 stdout/stderr (不要写文件) ☑ 避免在 Dockerfile 中写密码 (用 --build-arg secrets) ☑ 生产环境 restart: unless-stopped ☑ 资源限制 --memory --cpus 防止容器耗尽宿主机 ☑ 定期清理无用镜像/容器 (docker system prune -f)7.3 安全提醒# ❌ 危险做法 FROM ubuntu:latest ENV DB_PASSWORDmysecret123 # 密码明文写在镜像层! USER root # root 运行! # ✅ 安全做法 FROM ubuntu:24.04 # 固定版本,不用 :latest RUN groupadd -r appgroup useradd -r -g appgroup appuser USER appuser # 非 root 运行 # 密码通过 docker run -e 或 secrets 传入附录 资源包A. 镜像大小优化对比方案基础镜像大小说明传统 JDKopenjdk:17~470MB含完整 JDKJRE 精简eclipse-temurin:17-jre~210MB仅运行时Alpine JREeclipse-temurin:17-jre-alpine~185MB最小 JRE多阶段自定义~120MB编译运行分离Distrolessgcr.io/distroless/java17~120MBGoogle 最小化方案基础镜像大小说明Nginx 官方nginx:latest~187MBDebian 基础Nginx Alpinenginx:alpine~93MB实测 93.6MBNginx Distrolessnginx:alpine精简~60MB去掉 shellB. Docker 命令速查卡镜像管理: docker pull img:tag 拉取镜像 docker build -t name . 构建镜像 docker push img:tag 推送镜像 docker rmi img 删除镜像 docker tag src dst 打标签 docker save/load 导入导出 容器管理: docker run -d --name X -p H:C IMG 启动 docker exec -it X /bin/bash 进入 docker logs -f X 看日志 docker cp HOST_PATH X:CONT_PATH 传文件 docker commit X new:tag 保存为镜像 系统管理: docker system df 磁盘占用 docker system prune -f 清理无用资源 docker stats --no-stream 资源监控 docker info 系统信息 Compose: docker compose up -d 启动 docker compose down -v 停止清理 docker compose ps 状态 docker compose logs -f svc 日志C. 常见问题 FAQQ1: 容器退出后数据还在吗A: 容器删除后可写层数据丢失。Volume/Bind Mount 的数据保留。Q2: 如何让容器开机自启A:docker run --restart unless-stopped或 Compose 中设restart: unless-stoppedQ3: 容器之间如何通信A: 创建自定义 bridge 网络容器间用服务名(容器名)做 DNS 解析。Q4: 镜像太大怎么办A: 多阶段构建 Alpine 基础镜像 .dockerignore 清理apt-get cleanQ5: docker compose 和 docker-compose 区别A:docker compose是 Docker CLI 插件(v2)docker-compose是独立 Python 脚本(v1 已废弃)。Q6: 如何限制容器资源A:docker run --memory 512m --cpus 1.5Q7: 生产环境需要哪些镜像A: 应用镜像 监控 (Prometheus) 日志 (ELK) 反向代理 (Nginx/Traefik) 数据库 (建议用云服务而非容器)Q8: 容器内时间不对A:docker run -v /etc/localtime:/etc/localtime:ro或设置 TZ 环境变量今日挑战尝试用 Alpine 构建一个 Python Flask 应用容器要求基于python:3-alpine安装 Flask (pip install flask)编写一个返回{status: ok}的/health接口最终镜像 100MB提示cd /tmp docker build -t flask-app:alpine .本系列博客基于华为云 ecs-fce0 集群实战操作编写Docker CE 29.5.3所有输出均为真实服务器执行结果。