HelloWorld Docker 实战教程

Docker HelloWorld 的实战入门其实是一条非常直接的路线:安装 Docker 引擎,运行 docker run hello-world,观察镜像拉取与容器启动的输出;接着用一个极简 Dockerfile 构建自定义镜像、运行带端口映射和卷挂载的容器,理解镜像层、容器与宿主机资源的映射以及网络模型。本文以一步步实操为主线,解释每条命令的本质和常见故障,帮助你从“看见输出”到“理解原理并能排查问题”。

HelloWorld Docker 实战教程

为什么先做 HelloWorld?先弄清楚目的

如果你刚接触 Docker,直接跳到复杂应用(微服务、CI/CD)会被细节吓到。HelloWorld 是一种“最小可运行单元”验证手段:它能告诉你 Docker 是否安装正确、网络是否可用、镜像仓库是否可访问、以及容器能否启动与输出预期信息。更重要的是,做完 HelloWorld 后,你会对镜像拉取、容器启动流程有一个清晰的心理模型,后面所有概念都可以在这个模型上扩展。

准备工作:环境与安装要点

支持的平台

  • Linux(推荐 Ubuntu、Debian、CentOS 等发行版)
  • macOS(使用 Docker Desktop)
  • Windows(Windows 10/11 Pro 使用 Docker Desktop;Windows Server 有专门安装方式)

快速安装要点(概述)

  • Linux:使用官方仓库安装 docker-ce,安装后启动并加入 docker 组以便无 sudo 运行。
  • macOS / Windows:安装 Docker Desktop,注意开启虚拟化(HyperKit / WSL2 for Windows)。
  • 网络:如果在公司或国内网络,可能需要配置镜像加速器或代理。

典型安装命令(Ubuntu 示例)

sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] \
  https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io
sudo usermod -aG docker $USER

安装细节会随系统版本变化,上面只是一个常见流程;如果遇到问题,参考 Docker 官方文档或你所在发行版的社区说明。

第一步:运行 HelloWorld 镜像并观察发生了什么

运行命令

docker run hello-world

典型输出解析

  • 如果本地没有 hello-world 镜像,Docker 会向 Docker Hub 发起拉取请求。
  • 镜像拉取完成后,Docker 会基于该镜像创建容器并启动,容器会输出一段信息,然后退出(这是一个短生命周期容器示例)。
  • 输出包含:“Hello from Docker!” 类型的信息,说明引擎、镜像仓库访问与容器运行都正常。

如果没有输出或报错,先检查

  • Docker 服务是否启动:sudo systemctl status docker
  • 用户权限:是否需要 sudo 或是否添加到 docker 组
  • 网络访问:能否访问 Docker Hub(公司网络可能被防火墙或代理限制)
  • DNS 问题:容器能否解析域名,可临时使用镜像加速器

从 HelloWorld 到自定义镜像:编写一个最小示例

真正学会 Docker,不只是能运行别人写好的镜像,而是能把应用打包成镜像、配置运行时。下面我们用一个极简的 Python Web 应用演示从代码到镜像再到运行的全流程。

示例目录结构

hello-docker/
├── app.py
└── Dockerfile

app.py(极简 Flask 示例)

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello():
    return "Hello, Docker!"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Dockerfile(逐行解释)

FROM python:3.10-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["python", "app.py"]
  • FROM:基于官方基础镜像,形成镜像层的起点。
  • WORKDIR:设定容器内部工作目录,后续命令都会基于此目录执行。
  • COPY:把代码拷贝进镜像,产生新的镜像层。
  • RUN:在镜像构建阶段执行命令(如安装依赖),结果写入镜像层。
  • EXPOSE:声明容器监听端口(文档作用),运行时需用 -p 映射到宿主机端口。
  • CMD:容器启动时执行的默认命令,可被 docker run 后的参数覆盖。

构建与运行

# 构建镜像
docker build -t my-hello:1.0 .

# 运行容器并映射端口
docker run -d -p 8080:5000 --name my-hello-container my-hello:1.0

之后在浏览器访问 http://localhost:8080 就能看到 “Hello, Docker!”。如果是在远程服务器,注意安全组/防火墙设置。

深入理解:镜像、容器、层与存储

这些名词常被混用,但理解它们之间的区别很重要。

  • 镜像(Image):只读模版,由多个只读层组成(每次 RUN/COPY 等会产生新层)。镜像不运行。
  • 容器(Container):镜像的一个可写实例,运行时为镜像添加可写层,容器有生命周期(创建、启动、停止、退出、删除)。
  • 层(Layers):镜像由层叠加构成,重复利用相同层可以节省空间和拉取时间。
  • 卷(Volumes):用于持久化数据,独立于容器生命周期,适合数据库或日志存储。

典型命令速览表

操作 命令 说明
列出容器 docker ps -a 查看运行和已停止的容器
查看镜像 docker images 列出本地镜像
删除容器 docker rm <container> 移除停止状态的容器
删除镜像 docker rmi <image> 删除本地镜像

常见问题与排查技巧(基于 HelloWorld 和最小应用)

1. docker run 报错:permission denied

通常是因为当前用户没有访问 Docker socket 的权限。临时用 sudo,长期方案是把用户加入 docker 组并重新登录:

sudo usermod -aG docker $USER

2. 无法拉取镜像(超时、DNS 解析失败)

  • 确认宿主机能 ping registry-1.docker.io(或使用 curl 测试)。
  • 在国内环境常用镜像加速器(阿里云、DaoCloud 等),也可配置 /etc/docker/daemon.json 设置 registry-mirrors。

3. 端口映射后无法访问

  • 检查容器内服务是否监听 0.0.0.0 而非 127.0.0.1(app.run(host=’0.0.0.0′))。
  • 确认宿主机防火墙或云安全组已开放对应端口。
  • 使用 docker logs <container> 查看容器输出。

4. 镜像构建慢或失败

  • 把不常变动的依赖安装步骤放在 Dockerfile 前面,利用缓存加速。
  • 使用 .dockerignore 排除不必要的文件(如 node_modules、.git)。
  • 读懂失败信息,常见是 pip/npm 安装过程中的网络或编译依赖问题。

扩展:把 HelloWorld 变成可复用的开发流程

上面的示例是“单镜像单容器”。工程化通常需要考虑:多环境(dev/prod)配置、镜像安全扫描、CI/CD 构建与镜像推送、以及容器编排(Docker Compose 或 Kubernetes)。这里给出一些实际可用的建议,便于把简单流程推广到团队使用。

1. 使用 docker-compose 管理多服务

version: '3.8'
services:
  web:
    build: .
    ports:
      - "8080:5000"
    volumes:
      - .:/app
    environment:
      - FLASK_ENV=development

Compose 在开发阶段非常方便:代码改动可通过卷挂载实时生效,配置变更也更集中。

2. 镜像版本管理与镜像仓库

  • 使用语义化标签(如 v1.0.0、latest)并在 CI 中自动打标签。
  • 推送到私有仓库或公有仓库:docker tagdocker push

3. 安全与最小化镜像

  • 尽量使用瘦身基础镜像(alpine 或 slim),但注意兼容性和二进制依赖的问题。
  • 扫描镜像漏洞(例如使用 Trivy、Clair 等工具)。

调试技巧与进阶命令

  • docker logs <container>:查看容器输出日志。
  • docker exec -it <container> /bin/sh:进入正在运行的容器交互式调试(对于没有 shell 的最小镜像需提前准备调试工具)。
  • docker inspect <container|image>:查看容器或镜像的底层元数据,例如挂载点、网络设置、环境变量等。
  • docker stats:查看容器资源占用实时统计。

几个容易被忽视的小细节(实践中会踩的坑)

  • 镜像中使用相对路径时,确认 WORKDIR 与 COPY 的目标一致。
  • 不要在镜像里写入敏感信息(密码、密钥),使用环境变量或 secret 管理。
  • 开发环境用卷挂载非常方便,但在生产环境不要把源码直接挂载到容器里。
  • 注意容器时钟和宿主机的时区差异,日志时间不一致会很迷惑。

参考阅读(书名与工具名,方便后续深挖)

  • 《Docker — 从入门到实践》
  • Docker 官方文档(Docker Engine、Dockerfile、Compose)
  • Trivy(容器镜像扫描工具)

说到这里,可能你已经在机器上试过 docker run hello-world,也构建并运行了那台小小的 Flask 服务。实操是关键:当遇到问题,回到“谁在做什么”这个问题就能把错误一步步拆解——镜像是不是存在?容器里服务有没有监听?端口是不是映射?权限是不是受限?慢慢你会发现,Docker 的很多抽象背后都是很朴素的系统调用与文件映射。好了,我先放下键盘去再跑一遍示例(顺便检查下那个忘记加到 .dockerignore 的 node_modules),你要是想看一个更完整的 CI/CD 示例或者 Kubernetes 部署,我可以再接着写。