3. 容器化基础

聊到编解码器部署,Docker 几乎是绕不开的工具。我最早接触 Docker 是在 2016 年,那时候还在用笨重的虚拟机跑 FFmpeg 转码服务。说实话,第一次用 Docker 跑起一个容器时,那种「秒级启动」的感觉确实震撼。今天我们就从零开始,把 Docker 的安装、核心概念和 Dockerfile 编写过一遍。

Docker 安装与配置

不同操作系统安装方式略有差异。我个人习惯在 Linux 上做生产部署,但开发调试用 macOS 或 Windows 也完全没问题。

Linux(Ubuntu/Debian 系)

# 卸载旧版本
sudo apt-get remove docker docker-engine docker.io containerd runc

# 安装依赖
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 Engine
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。退出重新登录即可生效。

macOS 与 Windows

直接下载 Docker Desktop 就行。我建议去官网下载稳定版,别用 beta 版——曾经踩过 beta 版网络栈不稳定的坑,排查了一下午才发现是 Docker 版本问题。

平台 下载地址 注意事项
macOS docs.docker.com/desktop/mac/install Apple Silicon 选 arm64 版本
Windows docs.docker.com/desktop/windows/install 需启用 WSL2 或 Hyper-V

配置镜像加速器

国内拉取镜像经常慢得让人抓狂。我一般用阿里云或中科大的加速器。配置方式很简单:

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
注意:加速器地址需要去阿里云容器镜像服务申请,每个账号有专属地址。别直接复制网上的通用地址,大概率已经失效了。

镜像与容器:理解核心概念

很多新手搞不清镜像和容器的区别。我打个比方:镜像就像 ISO 安装盘,容器就是装好系统的电脑。镜像只读,容器可写。你可以从同一个镜像启动无数个容器,每个容器都是独立的运行环境。

核心关系:

  • 镜像(Image):静态的、只读的模板,包含操作系统、依赖库、应用代码
  • 容器(Container):镜像的运行实例,有独立的文件系统、网络、进程空间
  • 仓库(Registry):存放镜像的地方,Docker Hub 是默认的公共仓库

下面这张图能帮你理清它们的关系:

Docker 镜像与容器关系图 镜像仓库 Docker Hub / 私有仓库 docker pull 镜像 只读模板 分层文件系统 docker run 容器 可写层 独立运行环境 启动/停止/删除 容器 2(同一镜像) 容器 3(同一镜像) docker commit(不推荐) Dockerfile docker build 镜像 = 只读模板,容器 = 运行实例,Dockerfile = 镜像构建说明书

常用命令速查

操作 命令 说明
拉取镜像 docker pull nginx:latest 从仓库拉取指定标签的镜像
查看镜像 docker images 列出本地所有镜像
运行容器 docker run -d --name mynginx -p 8080:80 nginx 后台运行,映射端口
查看容器 docker ps -a 列出所有容器(包括已停止的)
进入容器 docker exec -it mynginx bash 在运行中的容器内执行命令
停止容器 docker stop mynginx 优雅停止
删除容器 docker rm mynginx 删除前需先停止
我的习惯:每个容器都加 --name 参数命名,不然 Docker 会随机生成一个像 focused_curie 这样的名字,容器多了根本分不清谁是谁。

Dockerfile 编写入门

Dockerfile 就是镜像的「制作说明书」。你想想看,如果每次部署都要手动装依赖、配环境,那跟传统部署有什么区别?Dockerfile 把这些步骤自动化了。

一个简单的例子

假设我们要部署一个 FFmpeg 转码服务:

# 使用官方 Ubuntu 作为基础镜像
FROM ubuntu:22.04

# 设置环境变量,避免交互式安装
ENV DEBIAN_FRONTEND=noninteractive

# 安装 FFmpeg 和必要工具
RUN apt-get update && apt-get install -y \
    ffmpeg \
    python3 \
    python3-pip \
    && rm -rf /var/lib/apt/lists/*

# 创建工作目录
WORKDIR /app

# 复制应用代码
COPY transcoder.py .
COPY requirements.txt .

# 安装 Python 依赖
RUN pip3 install -r requirements.txt

# 暴露端口
EXPOSE 8080

# 设置启动命令
CMD ["python3", "transcoder.py"]

Dockerfile 指令详解

指令 作用 注意事项
FROM 指定基础镜像 尽量选官方镜像,alpine 版本体积小
RUN 执行命令,创建新层 多个命令用 && 连接,减少层数
COPY 从宿主机复制文件到镜像 路径相对于构建上下文
WORKDIR 设置工作目录 后续指令都在此目录下执行
EXPOSE 声明容器监听端口 仅作文档用途,实际映射需 -p
CMD 容器启动时的默认命令 可以被 docker run 参数覆盖
ENV 设置环境变量 运行时可通过 -e 覆盖
曾经踩过的坑:有一次我把 COPY . /app 写在了 WORKDIR /app 前面,结果文件复制到了根目录下的 /app,而不是工作目录。Dockerfile 的指令顺序很重要,WORKDIR 一定要在 COPY 之前。

构建与运行

# 构建镜像,-t 指定标签
docker build -t transcoder:v1 .

# 运行容器
docker run -d --name my-transcoder \
  -p 8080:8080 \
  -v /data/videos:/app/videos \
  transcoder:v1

这里 -v 是挂载卷,把宿主机的 /data/videos 目录映射到容器内的 /app/videos。编解码处理通常涉及大量视频文件,用卷挂载比直接复制文件高效得多。

镜像分层与缓存优化

Docker 镜像采用分层存储。每个 RUN、COPY 指令都会生成一个新层。构建时如果某层没变化,Docker 会直接使用缓存。

我有个优化技巧:把不常变动的指令放在前面。比如安装系统依赖放前面,复制代码放后面。这样改代码时不用重新下载 FFmpeg,构建速度能快不少。

# 推荐写法:依赖放前面
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y ffmpeg python3
COPY requirements.txt .
RUN pip3 install -r requirements.txt
COPY . .
CMD ["python3", "app.py"]

总结一下今天的内容:

  • Docker 安装后记得配镜像加速器,不然拉取慢到怀疑人生
  • 镜像是只读模板,容器是运行实例,一个镜像可以启动 N 个容器
  • Dockerfile 用 FROM 定基础,RUN 装依赖,COPY 传代码,CMD 定启动
  • 利用分层缓存优化构建速度,把稳定层放前面