镜像是Docker的核心

前几章我们说镜像是一个"模板",现在深入理解一下:镜像是Docker的核心,没有镜像就没有容器。

镜像的基本操作

1. 拉取镜像

从仓库下载镜像到本地:

# 基本用法
docker pull 镜像名

# 示例
docker pull nginx
docker pull python:3.11
docker pull mysql:8.0

镜像标签(Tag):

  • nginx:默认使用latest标签
  • nginx:1.24:指定版本1.24
  • python:3.11-alpine:使用alpine基础镜像(体积更小)

常用镜像源:

  • Docker Hub(默认):nginx
  • 阿里云:registry.cn-hangzhou.aliyuncs.com/library/nginx

2. 查看本地镜像

# 列出所有镜像
docker images

# 只显示镜像ID
docker images -q

# 显示完整的镜像信息(包括层信息)
docker images --digests

输出说明:

REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
nginx         latest    123456789abc   2 weeks ago    142MB
python        3.11      abcdef123456   3 days ago     1GB
mysql         8.0       123abc456def   1 month ago    542MB
  • REPOSITORY:镜像名称
  • TAG:标签(版本)
  • IMAGE ID:镜像唯一标识
  • CREATED:创建时间
  • SIZE:镜像大小

3. 删除镜像

# 删除指定镜像
docker rmi 镜像名

# 删除多个镜像
docker rmi nginx nginx:1.24 python:3.11

# 删除所有镜像(慎用)
docker rmi $(docker images -q)

# 强制删除镜像(即使有容器在使用)
docker rmi -f nginx

注意:删除镜像前要先删除基于这个镜像的容器。

4. 查看镜像详细信息

# 查看镜像详细信息
docker inspect 镜像名

# 查看镜像的层信息
docker history 镜像名

镜像的分层原理

什么是分层?

Docker镜像由多个只读层叠加而成,每层代表镜像构建的一个步骤:

┌────────────────────┐
│  应用层(你的代码)  │  ← 这层最小
├────────────────────┤
│   依赖包层         │
├────────────────────┤
│   运行环境层       │
├────────────────────┤
│   基础系统层       │  ← 这层最大
└────────────────────┘

分层的好处

1. 节省空间: 多个镜像可以共享相同的层,例如:

nginx:latest   ───┐
nginx:1.24     ───┼── 共享基础层(Alpine系统)
nginx:1.25     ───┘

2. 快速构建: 只重新构建变化的层,其他层直接复用。

3. 版本管理: 每层都有唯一的ID,可以精确回滚。

查看镜像的层

docker history nginx

输出示例:

IMAGE          CREATED       CREATED BY                                      SIZE
123456789abc   2 weeks ago   /bin/sh -c #(nop)  CMD ["nginx" "-g" "daemon…   0B
abcdef123456   2 weeks ago   /bin/sh -c #(nop) EXPOSE 80                      0B
123abc456def   2 weeks ago   /bin/sh -c #(nop)  STOPSIGNAL SIGTERM            0B
456def789abc   2 weeks ago   /bin/sh -c #(nop) COPY file:... in /etc/ngi…   5.89kB
...
  • IMAGE:层的ID
  • CREATED BY:创建这一层的命令
  • SIZE:这一层的大小

镜像的搜索

从Docker Hub搜索

# 搜索镜像
docker search 镜像名

# 示例
docker search nginx

输出说明:

NAME                         DESCRIPTION                    STARS   OFFICIAL
nginx                        Official build of Nginx.         18000   OK
bitnami/nginx                Bitnami nginx Docker Image      300
nginx-ingress-controller     Ingress controller for NGIN…    2000
  • NAME:镜像名称
  • DESCRIPTION:描述
  • STARS:星标数(越多人用越好)
  • OFFICIAL:是否官方镜像

建议优先使用官方镜像!

在Docker Hub网站搜索

访问 https://hub.docker.com,可以:

  • 查看镜像详细介绍
  • 查看Dockerfile
  • 阅读使用文档
  • 查看用户评价

构建自己的镜像

什么是Dockerfile?

Dockerfile是一个文本文件,包含构建镜像的指令:

# 基础镜像
FROM python:3.11

# 工作目录
WORKDIR /app

# 复制文件
COPY . /app

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

# 启动命令
CMD ["python", "app.py"]

构建镜像

# 基本语法
docker build -t 镜像名:标签 Dockerfile所在目录

# 示例
docker build -t myapp:v1 .
docker build -t myapp:latest ./docker

参数说明:

  • -t:指定镜像名称和标签
  • .:Dockerfile在当前目录
  • -f:指定Dockerfile路径(如果不在当前目录)

Dockerfile常用指令

# 1. FROM - 指定基础镜像
FROM python:3.11
FROM ubuntu:20.04

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

# 3. COPY - 复制文件到镜像
COPY . /app
COPY requirements.txt /app/

# 4. ADD - 复制文件(支持URL和解压)
ADD https://example.com/file.tar.gz /app/

# 5. RUN - 执行命令(构建时)
RUN pip install -r requirements.txt
RUN apt-get update && apt-get install -y curl

# 6. CMD - 容器启动时执行的命令
CMD ["python", "app.py"]

# 7. ENTRYPOINT - 容器入口点(不可被覆盖)
ENTRYPOINT ["python", "app.py"]

# 8. ENV - 设置环境变量
ENV PYTHONUNBUFFERED=1
ENV PORT=8000

# 9. EXPOSE - 暴露端口
EXPOSE 8000

# 10. VOLUME - 声明数据卷
VOLUME /data

镜像的导出和导入

导出镜像

# 导出镜像为tar文件
docker save -o myapp.tar myapp:latest

# 导出多个镜像
docker save -o images.tar nginx mysql redis

导入镜像

# 从tar文件导入
docker load -i myapp.tar

# 导入并重命名
docker load < myapp.tar

场景: 在没有网络的机器上部署,可以提前导出镜像再复制过去。

镜像的标签管理

给镜像打标签

# 给镜像打新标签
docker tag nginx:latest nginx:v1.24

# 给镜像打多个标签
docker tag nginx:latest my-nginx:stable
docker tag nginx:latest registry.cn-hangzhou.aliyuncs.com/my/nginx:latest

场景: 一个镜像可以有多个标签,方便管理不同版本。

删除镜像的所有标签

# 删除镜像的所有标签
docker rmi $(docker images --format '{{.Repository}}:{{.Tag}}' | grep 'nginx')

实战:构建一个Python镜像

准备项目文件

# 创建项目目录
mkdir my-python-app
cd my-python-app

# 创建app.py
cat > app.py << 'EOF'
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=8000)
EOF

# 创建requirements.txt
cat > requirements.txt << 'EOF'
flask==2.3.0
EOF

# 创建Dockerfile
cat > Dockerfile << 'EOF'
FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["python", "app.py"]
EOF

构建镜像

docker build -t my-python-app:latest .

运行容器

docker run -d -p 8000:8000 --name myapp my-python-app

访问验证

打开浏览器访问 http://localhost:8000,看到 “Hello, Docker!” 就成功了!

镜像优化技巧

1. 使用多阶段构建

传统方式(镜像体积大):

FROM python:3.11
COPY . /app
RUN pip install -r requirements.txt
# 最终镜像包含所有构建工具,体积大

多阶段构建(镜像体积小):

# 构建阶段
FROM python:3.11 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user -r requirements.txt

# 运行阶段
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
CMD ["python", "app.py"]

2. 使用alpine基础镜像

# 传统基础镜像(900MB)
FROM python:3.11

# Alpine基础镜像(150MB)
FROM python:3.11-alpine

注意:Alpine使用musl libc而不是glibc,某些C扩展可能不兼容。

3. 合并RUN命令

# 不好(创建多个层)
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get clean

# 好(只创建一个层)
RUN apt-get update && \
    apt-get install -y curl && \
    apt-get clean

4. 清理缓存

RUN pip install --no-cache-dir -r requirements.txt
RUN apt-get clean && rm -rf /var/lib/apt/lists/*

5. 利用构建缓存

Docker会缓存每一层,如果指令没变,就复用缓存。

优化Dockerfile顺序

# 不好的顺序(经常变化的文件放在前面)
COPY . /app
RUN pip install -r requirements.txt

# 好的顺序(不常变化的文件放在前面)
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .

常用镜像推荐

基础镜像

  • alpine:最轻量的Linux发行版(5MB)
  • ubuntu:Ubuntu系统
  • debian:Debian系统

语言运行时

  • python:Python环境
  • node:Node.js环境
  • openjdk:Java环境
  • golang:Go语言环境

数据库

  • mysql:MySQL数据库
  • postgres:PostgreSQL数据库
  • mongo:MongoDB数据库
  • redis:Redis缓存

Web服务器

  • nginx:高性能Web服务器
  • httpd:Apache HTTP Server

本章小结

  • 镜像操作:拉取、查看、删除、搜索
  • 分层原理:镜像由多层叠加,节省空间
  • 构建镜像:使用Dockerfile定义镜像
  • 镜像优化:多阶段构建、使用alpine、合并指令、利用缓存

现在已经掌握了镜像操作,下一章我们来学习容器操作!

继续学下去,马上就能实战了!