第一章:容器化基础——Docker核心概念与入门实践
各位同学好,我是你们这门课的老朋友。今天咱们正式开篇,聊聊容器化。说实话,我最早接触Docker是在2015年,那时候公司还在用虚拟机部署,每次上线都像拆弹一样紧张。后来我主导了一次容器化改造,才真正体会到什么叫「一次构建,到处运行」。这一章,我会把Docker最核心的东西掰开揉碎了讲给你听。
1.1 Docker核心概念:镜像、容器、仓库
这三个概念,说白了就是Docker世界的三驾马车。我见过不少新手上来就docker run,结果镜像拉不下来、容器起不来、仓库连不上,一脸懵。咱们先理清它们的关系。
镜像(Image)
镜像是什么?你可以把它理解成一个「只读的模板」。它包含了运行应用所需的一切:代码、运行时、库、环境变量、配置文件。嗯,就像你装系统用的ISO文件,但比它更轻量、更灵活。
我个人习惯把镜像比作「披萨的配方」——配方本身不能吃,但照着配方做出来的披萨(容器)才是能吃的。镜像分层存储,每一层都是只读的,这设计很巧妙。我在项目中遇到过一个问题:有人把镜像做到十几个G,拉取慢得要命。后来我们优化了分层,把基础镜像和业务代码分开,速度提升了好几倍。
- 镜像是静态的、只读的
- 镜像由多层组成,每层对应Dockerfile的一条指令
- 镜像可以共享基础层,节省磁盘空间
容器(Container)
容器就是镜像的运行实例。你想想看,镜像就像是一个类,容器就是实例化出来的对象。容器有读写层,可以启动、停止、删除。我经常跟团队说:「镜像负责定义,容器负责运行。」
容器和虚拟机的区别,我简单说两句。虚拟机是完整的操作系统,每个VM都有自己的内核;而容器共享宿主机的内核,只隔离进程。所以容器启动快、资源占用少。但这也意味着——容器里的进程不能随便改内核参数。我曾经踩过这个坑,在容器里调sysctl,结果发现根本没权限。
仓库(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
配置镜像加速器
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"]
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让多容器管理变得简单,开发环境必备