第一章:容器化基础——Docker核心概念与入门实践

各位同学好,我是你们这门课的老朋友。今天咱们正式开篇,聊聊容器化。说实话,我最早接触Docker是在2015年,那时候公司还在用虚拟机部署,每次上线都像拆弹一样紧张。后来我主导了一次容器化改造,才真正体会到什么叫「一次构建,到处运行」。这一章,我会把Docker最核心的东西掰开揉碎了讲给你听。

1.1 Docker核心概念:镜像、容器、仓库

这三个概念,说白了就是Docker世界的三驾马车。我见过不少新手上来就docker run,结果镜像拉不下来、容器起不来、仓库连不上,一脸懵。咱们先理清它们的关系。

镜像(Image)

镜像是什么?你可以把它理解成一个「只读的模板」。它包含了运行应用所需的一切:代码、运行时、库、环境变量、配置文件。嗯,就像你装系统用的ISO文件,但比它更轻量、更灵活。

我个人习惯把镜像比作「披萨的配方」——配方本身不能吃,但照着配方做出来的披萨(容器)才是能吃的。镜像分层存储,每一层都是只读的,这设计很巧妙。我在项目中遇到过一个问题:有人把镜像做到十几个G,拉取慢得要命。后来我们优化了分层,把基础镜像和业务代码分开,速度提升了好几倍。

核心要点:
  • 镜像是静态的、只读的
  • 镜像由多层组成,每层对应Dockerfile的一条指令
  • 镜像可以共享基础层,节省磁盘空间

容器(Container)

容器就是镜像的运行实例。你想想看,镜像就像是一个类,容器就是实例化出来的对象。容器有读写层,可以启动、停止、删除。我经常跟团队说:「镜像负责定义,容器负责运行。」

容器和虚拟机的区别,我简单说两句。虚拟机是完整的操作系统,每个VM都有自己的内核;而容器共享宿主机的内核,只隔离进程。所以容器启动快、资源占用少。但这也意味着——容器里的进程不能随便改内核参数。我曾经踩过这个坑,在容器里调sysctl,结果发现根本没权限。

注意:容器是临时性的。默认情况下,容器内的数据在容器删除后会丢失。如果你需要持久化数据,一定要用数据卷(Volume)或绑定挂载(Bind Mount)。

仓库(Registry)

仓库就是存放镜像的地方。Docker Hub是官方的公共仓库,但国内访问速度嘛……你懂的。我一般用阿里云镜像加速器,或者自建Harbor仓库。仓库的概念很简单:push上传,pull下载,tag打标签。

举个例子,你写好了Dockerfile,构建出镜像,然后推送到仓库。同事在另一台机器上pull下来就能直接运行。这就是协作的基础。

概念 类比 关键特性
镜像 披萨配方 只读、分层、可复用
容器 做好的披萨 可读写、可运行、临时性
仓库 菜谱图书馆 存储、分发、版本管理

1.2 Docker安装与配置

安装Docker其实不难,但不同系统有不同玩法。我主要讲Linux环境,毕竟生产环境99%都是Linux。Windows和Mac用户可以用Docker Desktop,但注意资源占用问题。

Linux安装(以Ubuntu为例)

# 更新包索引
sudo apt-get update

# 安装依赖
sudo apt-get install ca-certificates curl gnupg lsb-release

# 添加Docker官方GPG密钥
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

# 安装Docker引擎
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

# 验证安装
sudo docker run hello-world

安装完成后,记得把当前用户加入docker组,不然每次都要sudo,很烦人。

sudo usermod -aG docker $USER
# 退出重新登录,或者执行 newgrp docker
小技巧:我习惯安装后立刻配置镜像加速器。编辑 /etc/docker/daemon.json,加入阿里云或中科大的镜像地址。这样拉取镜像快很多,尤其是第一次部署的时候。

配置镜像加速器

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://你的加速器地址.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

为什么要配置加速器?因为Docker Hub在国外,国内网络经常抽风。我曾经在客户现场部署,网络慢到拉一个nginx镜像花了半小时。后来配了加速器,几分钟搞定。嗯,这个坑我替你们踩过了。

1.3 Dockerfile编写最佳实践

Dockerfile是构建镜像的蓝图。写得好不好,直接影响镜像大小、构建速度和安全性。我见过有人把Dockerfile写成「屎山」,一个RUN命令里塞了几百行。咱们来聊聊怎么写出优雅的Dockerfile。

基础原则

  • 选择合适的基础镜像:能用alpine就别用ubuntu。alpine只有5MB,ubuntu有200MB。我一般用python:3.11-slim,既轻量又够用。
  • 减少层数:每个RUN、COPY、ADD都会创建一层。能用&&合并命令就合并。但别过度,可读性也很重要。
  • 利用构建缓存:把不常变动的指令放在前面,经常变动的放在后面。比如先COPY requirements.txt,再RUN pip install,最后COPY代码。
  • 使用.dockerignore:排除不需要的文件,比如.git、__pycache__、.env。这能减少构建上下文大小,加快构建速度。

一个Python项目的Dockerfile示例

# 1. 选择基础镜像
FROM python:3.11-slim AS builder

# 2. 设置工作目录
WORKDIR /app

# 3. 安装系统依赖(合并RUN减少层数)
RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc \
    libpq-dev \
    && rm -rf /var/lib/apt/lists/*

# 4. 先复制依赖文件,利用缓存
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 5. 再复制代码(经常变动)
COPY . .

# 6. 多阶段构建:最终镜像只保留运行环境
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY --from=builder /app /app

# 7. 指定启动命令
CMD ["python", "app.py"]
避坑指南:我曾经在Dockerfile里直接写RUN pip install,结果每次构建都重新下载所有包,慢得离谱。后来把requirements.txt单独COPY,利用缓存机制,只有依赖变化时才重新安装。构建时间从5分钟降到了30秒。

多阶段构建

多阶段构建是Docker 17.05引入的特性。说白了,就是在一个Dockerfile里用多个FROM语句。第一个阶段用来编译、安装依赖,第二个阶段只复制产物。这样最终镜像只包含运行所需的最小文件,体积能小很多。

举个例子,编译Go程序需要gcc、go工具链,但运行时只需要一个二进制文件。用多阶段构建,最终镜像可以小到十几MB。我有个项目,用多阶段构建后镜像从800MB降到了120MB,部署速度飞起。

1.4 Docker Compose入门

Docker Compose是用来定义和运行多容器Docker应用的工具。你想想看,一个后端项目往往需要Web服务、数据库、缓存、消息队列……一个个手动docker run,累不累?Compose就是帮你一键启动所有服务。

安装Docker Compose

# 下载最新版
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 赋予执行权限
sudo chmod +x /usr/local/bin/docker-compose

# 验证
docker-compose --version

现在Docker Desktop已经内置了Compose,但Linux上还是得手动装。我个人习惯用插件版:docker compose(注意没有横杠),这是Docker官方推荐的用法。

一个简单的docker-compose.yml示例

version: '3.8'

services:
  web:
    build: .
    ports:
      - "8000:8000"
    volumes:
      - .:/app
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/mydb
    depends_on:
      - db

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

这个文件定义了两个服务:web和db。web服务从当前目录构建镜像,映射端口8000,挂载代码目录实现热重载。db服务使用PostgreSQL镜像,数据持久化到pgdata卷。

启动命令很简单:

docker-compose up -d

停止并清理:

docker-compose down
实用技巧:开发环境我习惯用docker-compose up(不加-d),这样日志直接输出到终端,方便调试。生产环境用-d后台运行。另外,depends_on只控制启动顺序,不保证服务就绪。如果数据库启动慢,web服务可能会连不上。这时候需要加个等待脚本,或者用healthcheck。

Compose常用命令

命令 作用
docker-compose up 创建并启动所有服务
docker-compose down 停止并删除所有容器、网络
docker-compose logs 查看服务日志
docker-compose ps 列出所有容器状态
docker-compose exec 在运行中的容器执行命令

好了,第一章的内容就到这里。这一章我们讲了Docker的三大核心概念、安装配置、Dockerfile编写技巧和Compose入门。这些都是容器化的基本功,就像练武要先扎马步一样。下一章我们会深入Docker网络和数据管理,到时候见。

本章总结:
  • 镜像、容器、仓库是Docker的三大基石,理解它们的关系很重要
  • 安装Docker后记得配置镜像加速器,能省很多时间
  • Dockerfile要遵循最佳实践:选小镜像、合并RUN、利用缓存、多阶段构建
  • Docker Compose让多容器管理变得简单,开发环境必备