文章目录
-
- [2. docker容器管理与镜像操作](#2. docker容器管理与镜像操作)
-
- [1. 什么是镜像](#1. 什么是镜像)
- [2. docker镜像原理](#2. docker镜像原理)
-
- [1. 镜像分层 (Layered Image)](#1. 镜像分层 (Layered Image))
- [2. 写时复制 (Copy-on-Write, CoW)](#2. 写时复制 (Copy-on-Write, CoW))
- [3. 联合挂载 (UnionFS / OverlayFS)](#3. 联合挂载 (UnionFS / OverlayFS))
- [4. 内容寻址 (Content-addressable Storage)](#4. 内容寻址 (Content-addressable Storage))
- [3. docker镜像关键概念](#3. docker镜像关键概念)
-
- [1. Registry](#1. Registry)
- [2. Repository](#2. Repository)
- [3. Image](#3. Image)
- [4. Layer](#4. Layer)
- [5. Manifest](#5. Manifest)
- [6. Dockerfile](#6. Dockerfile)
- [4. 镜像管理命令](#4. 镜像管理命令)
- [5. 镜像仓库命令](#5. 镜像仓库命令)
- [6. dockerfile](#6. dockerfile)
-
- [1. Dockerfile 是什么?](#1. Dockerfile 是什么?)
- [2. 它解决了什么问题?](#2. 它解决了什么问题?)
- [3. docker build 构建流程](#3. docker build 构建流程)
- [4. Dockerfile 常用关键字](#4. Dockerfile 常用关键字)
- [5. 案例](#5. 案例)
- [6. dockerfile高级](#6. dockerfile高级)
- [7. 数据卷(volume)](#7. 数据卷(volume))
-
- [1. 概念与思想](#1. 概念与思想)
- [2. 数据卷的产生背景](#2. 数据卷的产生背景)
- [3. 数据卷的使用场景](#3. 数据卷的使用场景)
- [4. 数据卷常用命令](#4. 数据卷常用命令)
2. docker容器管理与镜像操作
1. 什么是镜像
容器解决应用开发、测试和部署的问题,而镜像解决应用部署环境问题。镜像是一个只读的容器模板,打包了应用程序和应用程序所依赖的文件系统以及启动容器的配置文件,是启动容器的基础。镜像所打包的文件内容就是容器的系统运行环境------rootfs(根文件系统或根目录)。容器与镜像类似对象与类的关系
2. docker镜像原理
1. 镜像分层 (Layered Image)
Docker 镜像由多个只读层(read-only layers)组成,每一层是上一个层的增量变化。
例如:
ubuntu:22.04 基础层(系统环境)
apt-get install python 生成新层
pip install flask 再生成一层
优点:
共享:不同镜像可以复用相同层(节省空间)
缓存:构建时如果某一层没变,Docker 会直接复用缓存层,加快构建速度
2. 写时复制 (Copy-on-Write, CoW)
镜像层都是 只读的,当运行容器时,Docker 在镜像层上面加一个 可写层(Container Layer)。
容器修改文件时:
如果文件在镜像层 → 复制到容器层再修改(Copy-on-Write)
如果是新文件 → 直接写在容器层
好处:
保证镜像不可变
多个容器可以共享同一镜像层
3. 联合挂载 (UnionFS / OverlayFS)
Docker 使用 联合文件系统(Union File System)把多个层"叠加"起来,表现为一个统一的文件系统。
底层常见实现:
AUFS
OverlayFS / Overlay2(现代 Docker 默认)
btrfs / zfs(少见)
原理:多个层联合挂载,最上层为可写层,下面是只读层。
4. 内容寻址 (Content-addressable Storage)
镜像的每一层由 哈希值(SHA256)标识,而不是文件名。
这样保证:
唯一性:内容变 → 哈希变
不可篡改:内容校验自动完成
Docker Hub 拉镜像时就是基于内容哈希校验
Docker Container (运行时)
Docker Image (只读层)
Layer 1: Ubuntu Base
Layer 2: apt-get install python
Layer 3: pip install flask
Writable Layer (容器层,可写)
3. docker镜像关键概念
1. Registry
定义:镜像仓库服务(类似代码托管的 GitHub)。
例子:Docker Hub、阿里云镜像仓库、私有 Harbor。
作用:存放和分发镜像。
2. Repository
定义:仓库中的镜像集合(相当于代码仓库的一个项目)。
命名格式://
特点:一个 repository 里可能有多个 tag,比如:
nginx:1.25
nginx:latest
3. Image
定义:可执行软件包,包含代码、运行时、库、环境变量、配置。
组成:由多个只读 Layer 叠加而成。
特点:
不可变(immutable)
通过内容寻址唯一标识(哈希 digest)
4. Layer
定义:镜像的构建单元,每条 Dockerfile 指令会生成一层 Layer。
类型:
只读层(镜像层)
可写层(容器运行时的顶层)
优化:
层可复用(不同镜像共享相同层)
写时复制(Copy-on-Write,修改时才复制)
5. Manifest
定义:描述镜像的元数据文件(JSON 格式),存放于 Registry。
内容:
镜像使用的 Layer 列表(哈希值)
镜像配置(环境变量、Entrypoint 等)
多架构支持(不同平台对应的镜像列表)
例子:docker manifest inspect nginx:latest
6. Dockerfile
定义:镜像的构建脚本,声明如何从基础镜像一步步生成目标镜像。
常见指令:
FROM:指定基础镜像
RUN:执行命令
COPY / ADD:拷贝文件
CMD / ENTRYPOINT:容器启动命令
作用:可复现性构建。
概念关系图
+-------------------+ push/pull +--------------------+
| Dockerfile | ------------------> | Registry |
| (镜像构建脚本) | | (镜像仓库服务) |
+---------+---------+ +-----+--------------+
| |
v v
+-------------------+ 包含多个镜像 +--------------------+
| Image | <----------------------- | Repository |
| (镜像: tag/digest)| | (nginx, redis ...) |
+---------+---------+ +--------------------+
|
v
+-------------------+ 由多个层组成
| Layers | ----------------------> [ Layer 1 ]
| (只读 + 可写层) | [ Layer 2 ]
+---------+---------+ [ Layer N ]
|
v
+-------------------+
| Manifest | (JSON: 描述镜像结构、层的哈希、架构信息)
+-------------------+
一句话:
Dockerfile 定义了如何构建 Image,Image 由多个 Layer 组成,Manifest 描述 Image 结构。Image 存放在 Repository 中,而 Repository 托管在 Registry 上。
4. 镜像管理命令
shell
# 1. 命令用于使用 Dockerfile 创建镜像
docker build
# 后面能跟的参数:
# 1. -t, --tag
# 给镜像打标签(<name>:<tag>),默认 latest。
docker build -t myapp:1.0 .
# 常用于版本管理,比如 myapp:v1, myapp:v2。
# 2. -f, --file
# 指定 Dockerfile 路径(默认是 ./Dockerfile)。
docker build -f ./docker/Dockerfile -t myapp:dev .
#场景:一个项目里有多个 Dockerfile,分别构建不同环境。
# 3. --build-arg
# 传递构建参数(只能在 Dockerfile 中使用 ARG 取值)。
docker build --build-arg APP_ENV=prod -t myapp:prod .
#Dockerfile 示例:
ARG APP_ENV=dev
RUN echo "Building for $APP_ENV"
# 场景:根据不同环境传递参数(开发 / 生产)。
# 4. --no-cache
# 忽略缓存,强制重新构建所有层。
docker build --no-cache -t myapp:clean .
# 场景:避免旧层缓存,确保拉取最新依赖。
# 5. --pull
# 强制拉取最新的基础镜像。
docker build --pull -t myapp:latest .
# 场景:保证 FROM ubuntu:20.04 总是使用最新版本。
# 6. --target
#指定构建到某个阶段(用于多阶段构建)。
docker build --target builder -t myapp:builder .
# Dockerfile 示例:
FROM golang:1.22 AS builder
WORKDIR /app
RUN go build -o main .
FROM alpine:3.18
COPY --from=builder /app/main /usr/local/bin/
CMD ["main"]
# 场景:只想构建 builder 阶段(例如调试)。
# 7. --progress
# 设置构建日志样式:
#auto(默认,TTY 终端时显示进度条)
#plain(纯文本输出,适合日志采集)
docker build --progress=plain -t myapp .
# 8. --buildkit
#使用 BuildKit 构建(性能更好,支持并行和缓存优化)。
DOCKER_BUILDKIT=1 docker build -t myapp .
# 里面.表示当前目录,可以替换成指定目录
# 2. docker images
# 作用:查看本地已经存在的镜像。
docker images
# 3. docker rmi
# 作用:删除镜像(remove image)。
docker rmi ubuntu:22.04
docker rmi 47b19964fb50
# 可以用 镜像名:tag 或 IMAGE ID 删除。
# 如果镜像正被容器使用,需要先 docker rm 容器再删。
# -f 强制删除。
# 4. docker tag
# 作用:给镜像打标签,创建一个别名。
docker tag ubuntu:22.04 myrepo/myubuntu:1.0
# 原镜像不会被复制,只是多了一个引用。
# 常用于上传到私有仓库或改名。
# 5. docker save
# 作用:把镜像导出成一个 .tar 包。
docker save -o ubuntu.tar ubuntu:22.04
# save 保存的是 完整镜像(含所有层和元数据)。
# 用于镜像迁移或离线传输。
# 6. docker load
# 作用:加载 docker save 导出的镜像。
docker load -i ubuntu.tar
# 会恢复原始的 REPOSITORY:TAG。
# 常用于在没有网络的环境里导入镜像。
# 7. docker import
# 作用:从一个文件系统快照创建镜像。
cat ubuntu.tar | docker import - myubuntu:latest
# 和 load 的区别:
# import 不保留镜像的历史和层信息,只是一个新的镜像。
# save/load 才能完整保留历史。
# 8. docker commit
# 作用:把容器的当前状态保存为镜像。
docker commit mycontainer myubuntu:debug
# 类似于 "容器拍快照 → 镜像"。
# 常用于 debug 或临时保存,但不推荐代替 Dockerfile
5. 镜像仓库命令
shell
# 1. docker login
# 作用:登录 Docker 镜像仓库(默认是 Docker Hub)。
docker login
#它会提示输入:
# Username: your_dockerhub_id
# Password: ******
# 登录成功后,凭据会存到 ~/.docker/config.json。
# 也可以指定私有仓库:
# docker login myregistry.com
# 2. docker logout
# 作用:退出镜像仓库。
docker logout
docker logout myregistry.com
# 会清除本地保存的登录凭据。
# 3. docker pull
# 作用:从远程仓库拉取镜像到本地。
docker pull ubuntu:22.04
docker pull nginx
# 说明:
# 默认从 Docker Hub 拉取。
# 不写 tag 默认是 :latest。
# 也可以指定私有仓库:
# docker pull myregistry.com/myrepo/myimage:1.0
# 4. docker push
# 作用:把本地镜像推送到远程仓库。
docker push myrepo/myimage:1.0
# 注意:
# 必须先 docker login。
# 镜像名必须带仓库前缀(例如 username/repo:tag)。
# 推送到私有仓库示例:
# docker tag ubuntu:22.04 myregistry.com/myrepo/ubuntu:22.04
# docker push myregistry.com/myrepo/ubuntu:22.04
# 5. docker search
# 作用:在 Docker Hub 上搜索镜像。
docker search ubuntu
# 输出示例:
# NAME DESCRIPTION STARS OFFICIAL
# ubuntu Ubuntu is a Debian-bas... 15000 [OK]
# ubuntu/nginx Nginx on Ubuntu 200
# 说明:
# NAME:镜像名字
# STARS:社区星级,表示热度
# OFFICIAL:是否为官方镜像
6. dockerfile
1. Dockerfile 是什么?
Dockerfile 是一个 文本文件,里面写着一系列 构建镜像的指令。
每条指令都会生成镜像的一层。
相当于一份 镜像的配方/脚本。
简单理解:
如果镜像是蛋糕,Dockerfile 就是食谱,告诉 Docker 怎么一步一步做出来。
2. 它解决了什么问题?
在 Dockerfile 出现之前,构建镜像常用两种方法:
docker commit:进入容器手动安装环境,然后保存成镜像。
缺点:不可重复、不可追溯、不可版本管理。
别人发一个 .tar 镜像包,直接 docker load。
缺点:黑箱,不知道里面有什么。
有了 Dockerfile:
构建过程自动化,可复现。
配置透明、可审计、可维护。
能放进 Git 仓库进行版本管理。
3. docker build 构建流程
执行:
shell
docker build -t myapp:1.0 .
流程大致如下:
读取构建上下文(. 当前目录,包含 Dockerfile 和代码)。
解析 Dockerfile,逐行执行指令。
每条指令生成一层 Layer,缓存到本地。
最终合成一个镜像,打上标签 myapp:1.0。
4. Dockerfile 常用关键字
| 指令 | 作用 | 示例 |
|---|---|---|
FROM |
指定基础镜像 | FROM ubuntu:22.04 |
RUN |
执行命令(生成新层) | RUN apt-get update && apt-get install -y curl |
COPY |
复制本地文件到镜像 | COPY . /app |
ADD |
类似 COPY,但支持解压 tar、下载 URL | ADD app.tar.gz /app |
WORKDIR |
设置工作目录 | WORKDIR /app |
ENV |
设置环境变量 | ENV PORT=8080 |
EXPOSE |
声明容器监听的端口(仅文档作用) | EXPOSE 8080 |
CMD |
容器启动时执行的命令(可被覆盖) | CMD ["python3","app.py"] |
ENTRYPOINT |
容器启动入口(不易被覆盖) | ENTRYPOINT ["nginx","-g","daemon off;"] |
VOLUME |
定义挂载点 | VOLUME ["/data"] |
5. 案例
shell
# 案例 1:运行一个简单的 Python Web 应用
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 python:3.10-slim:选择官方 Python 轻量镜像作为基础。
# WORKDIR /app:在容器内创建 /app 目录并进入。
# COPY requirements.txt .:先复制依赖文件。
# RUN pip install ...:安装依赖,这样 分层缓存 能够避免每次改代码都重新安装依赖。
# COPY . .:复制当前目录的所有文件到容器的 /app。
# EXPOSE 5000:声明容器对外暴露 5000 端口。
# CMD ["python", "app.py"]:容器运行时执行 python app.py
shell
# 案例:分阶段构建
# 第一阶段:编译阶段
FROM gcc:12 AS builder
WORKDIR /app
# 复制源文件
COPY hello.cpp .
# 编译生成可执行文件
RUN g++ -O2 -o hello hello.cpp
# 第二阶段:运行阶段
FROM debian:stable-slim
WORKDIR /app
# 仅复制编译好的二进制文件
COPY --from=builder /app/hello .
# 设置容器启动命令
CMD ["./hello"]
# FROM gcc:12 AS builder:第一阶段使用 gcc 镜像编译 C++。
# RUN g++ -O2 -o hello hello.cpp:编译生成 hello。
# 第二阶段 FROM debian:stable-slim:使用一个轻量的 Debian 镜像作为运行环境。
# COPY --from=builder ...:把第一阶段的产物复制过来。
# 最终镜像里 只有一个可执行文件和最小运行环境,体积更小。
shell
# 案例 3:使用 ENV、ENTRYPOINT、VOLUME
# 模拟一个 Python 应用,支持自定义参数和数据挂载)
FROM python:3.10-slim
WORKDIR /app
# 复制代码
COPY app.py .
# 设置环境变量(默认日志目录)
ENV LOG_DIR=/logs
# 声明一个数据卷
VOLUME ["/logs"]
# 设置入口点(默认执行 app.py)
ENTRYPOINT ["python", "app.py"]
# 设置默认参数(可被覆盖)
CMD ["DockerUser"]
# 运行容器(使用默认参数和日志目录):
docker run --rm myapp
# 输出:
Message written to /logs/output.log
# 自定义名字(覆盖 CMD 参数):
docker run --rm myapp li
# 输出:
Message written to /logs/output.log
# 挂载日志目录到主机:
docker run --rm -v $(pwd)/mylogs:/logs myapp hit
# 在主机的 mylogs/output.log 里会看到:
Hello, hit!
#ENV LOG_DIR=/logs:设置默认环境变量。
#VOLUME ["/logs"]:声明容器的数据目录,可以挂载到主机。
#ENTRYPOINT ["python", "app.py"]:入口点固定为运行 Python 程序。
#CMD ["DockerUser"]:默认参数,可以被覆盖。
# 组合效果:用户既能固定入口点(app.py),也能灵活传参数(名字),同时还能挂载日志。
6. dockerfile高级
- ARG --- 构建参数
作用:在构建镜像时传递可变参数
特点:
只在 docker build 过程中可用
构建完成后不会保留在镜像里(不像 ENV)
语法:
ARG [=]
RUN echo "Building with ARG=$MYARG"
构建时传递参数:
shell
docker build --build-arg MYARG=dev -t myapp .
案例:
shell
FROM ubuntu:22.04
ARG BUILD_TYPE=dev
RUN echo "Build type is $BUILD_TYPE"
docker build --build-arg BUILD_TYPE=prod -t myapp .
# 输出: Build type is prod
2️. TARGET --- 多阶段构建目标
作用:指定构建的阶段(multi-stage build)
特点:
可以只构建中间阶段而不生成最终镜像
节约时间和空间
语法:
shell
FROM ubuntu:22.04 AS builder
RUN echo "This is builder"
FROM ubuntu:22.04 AS final
RUN echo "This is final"
构建中间阶段:
shell
docker build --target builder -t mybuilder .
只会构建 builder 阶段,不会继续构建 final 阶段
3️. --cache-from --- 利用已有镜像加速构建
作用:从已有镜像中加载缓存层,加速构建
特点:
常用于 CI/CD,尤其是远程构建
如果缓存命中,步骤不会重新执行
用法:
shell
docker build --cache-from myapp:latest -t myapp:dev .
场景:
CI/CD 环境里每次构建都干净,但可以用之前的镜像做缓存
避免每次从零安装依赖
注意:
只有 完全匹配的 Dockerfile 步骤 才能命中缓存
COPY 或 ADD 改变内容会打破缓存
- ONBUILD --- 构建触发器
作用:在 子镜像构建时 自动执行某些命令
特点:
父镜像定义的 ONBUILD 指令,会在以它为 FROM 的 Dockerfile 中被触发
常用于 基础镜像模板,让使用者不用重复写某些步骤
语法:
shell
# base.Dockerfile
FROM ubuntu:22.04
ONBUILD COPY . /app
ONBUILD RUN echo "ONBUILD triggered"
使用示例:
shell
# 子镜像 Dockerfile
FROM mybase:latest
RUN echo "Subimage building"
构建子镜像时,会自动执行父镜像的 ONBUILD COPY 和 ONBUILD RUN
适合做 模板镜像,比如 Python 或 C++ 项目基础镜像
7. 数据卷(volume)
1. 概念与思想
容器本质:容器里的文件系统是临时的,当容器删除后,数据会丢失。
问题:
容器删除,数据丢失(不可持久化)。
多个容器间数据无法共享。
容器和宿主机间缺乏方便的数据交互方式。
解决方案:数据卷(Volume)
数据卷是 容器与宿主机之间的一个共享目录。
特点:
数据持久化(容器删除数据还在)。
多容器共享和复用数据。
宿主机与容器之间的数据同步。
2. 数据卷的产生背景
容器只适合运行,不适合存数据。
数据需要:
- 持久化(日志、数据库)。
- 共享(例如:多容器访问同一个数据库目录)。
- 移植(把一个容器的数据迁移到另一个容器)。
于是,Docker 提供了三种存储方式: - Volume(数据卷) → Docker 管理,推荐方式。
- Bind mount(绑定挂载) → 直接映射宿主机目录。
- Tmpfs mount → 内存挂载,容器删除数据消失。
3. 数据卷的使用场景
数据库存储:MySQL 的数据目录 /var/lib/mysql 放在数据卷中,避免容器删除时数据丢失。
日志持久化:应用日志存储在宿主机目录。
多容器共享数据:例如多个 Web 容器共享静态资源。
4. 数据卷常用命令
- 创建数据卷
shell
# 创建数据卷
docker volume create mydata
# 查看所有数据卷
docker volume ls
# 查看数据卷详细信息
docker volume inspect mydata
数据卷一般存储在宿主机路径:
/var/lib/docker/volumes/<volume_name>/_data
- 挂载数据卷
shell
#挂载到容器(Volume 挂载)
docker run -d --name mynginx -v mydata:/usr/share/nginx/html nginx
# mydata → 数据卷名
#/usr/share/nginx/html → 容器内挂载点
#绑定挂载(Bind mount)
docker run -d --name mynginx -v /home/user/web:/usr/share/nginx/html nginx
#左边 /home/user/web → 宿主机路径
#右边 /usr/share/nginx/html → 容器路径
- 共享数据卷
多个容器可以挂载同一个卷:
shell
docker run -d --name nginx1 -v mydata:/data nginx
docker run -d --name nginx2 -v mydata:/data nginx
两个容器共享 /data,数据实时同步。
- 删除数据卷
shell
# 删除单个数据卷
docker volume rm mydata
# 删除所有未使用的数据卷
docker volume prune
- 备份与迁移数据卷
shell
# 备份数据卷
# 使用临时容器打包卷里的数据
docker run --rm -v mydata:/data -v /backup:/backup alpine \
tar czf /backup/mydata.tar.gz -C /data .
mydata:/data → 挂载数据卷
/backup:/backup → 宿主机目录
#5.2 恢复数据卷
docker run --rm -v mydata:/data -v /backup:/backup alpine \
tar xzf /backup/mydata.tar.gz -C /data