Docker镜像的分层结构
🐳 Docker核心知识与实践指南:从容器基础到镜像构建全解析
摘要:本文系统梳理了Docker的核心概念,深入剖析了镜像的分层结构与容器的运行机制,并提供了从基础命令到Dockerfile实战的完整操作手册。无论你是刚入门的新手,还是希望巩固基础的开发者,都能从中获得清晰的认知与实用的技能。
一、容器与镜像:Docker的基石
在深入实践之前,我们必须先厘清Docker最核心的两个概念:镜像(Image)**与**容器(Container)。
1. 什么是容器(Container)?
容器是镜像运行时的实例。你可以把它理解为一个轻量级的、独立的、可执行的软件包,它包含了运行某个应用所需的一切:代码、运行时环境、库、环境变量和配置文件。
- 轻量级:基于镜像启动,秒级即可完成。
- 隔离性:通过Linux的命名空间(Namespace)和控制组(cgroups)技术,实现进程、网络、文件系统的隔离,互不影响。
- 可移植:在任何支持Docker的环境中,容器都能保证一致的运行效果。
2. 什么是镜像(Image)?
镜像是一个只读的模板,它是创建容器的基石。一个镜像可以包含一个完整的操作系统环境,预装了Nginx或其他用户添加的应用程序。
- 分层结构:镜像由多个只读层(Read-only Layers)叠加而成,这是其高效的核心。
- 不可变性:镜像一旦创建,其内容就不会改变,这确保了环境的一致性。
- 可分发:镜像可以被推送到仓库(如Docker Hub)进行共享和分发。
3. 容器与镜像的关系
为了更直观地理解,我们可以通过一个表格来对比:
| 维度 | 镜像 (Image) | 容器 (Container) |
|---|---|---|
| 面向对象类比 | 类 (Class) | 对象/实例 (Instance) |
| 操作系统类比 | 程序 / 安装包 (如.iso) | 进程 (Process) |
| 生活类比 | 菜谱 / 房屋设计蓝图 | 按照菜谱做出的菜 / 建好的房子 |
| 本质属性 | 静态的、只读的模板 | 动态的、可读写的运行实体 |
| 生命周期 | 持久化存在(除非手动删除) | 临时存在(随进程启停而创建/销毁) |
一句话总结:镜像是容器的基础模板,定义了运行环境;容器是镜像的运行实例,是真正执行业务逻辑的载体。一个镜像可以同时启动多个完全隔离的容器。
二、深入理解:镜像的分层结构与容器的可写层
这是Docker最精妙的设计之一,理解它对于优化镜像和排查问题至关重要。
1. 镜像的分层结构(只读层)
镜像并非一个单一的大文件,而是由多个只读层叠加而成。
- 指令即层:Dockerfile中的每一条指令(如
FROM,RUN,COPY)都会创建一个新的镜像层。 - 资源复用:这种设计极大地提升了效率。例如,10个基于
nginx:alpine的镜像,在宿主机上只需存储一份基础层,节省了巨大的磁盘空间和网络带宽。
2. 容器的可写层(Container Layer)
当你执行docker run启动一个容器时,Docker会在所有镜像只读层的顶部,添加一个薄薄的可写层。
- 读取文件:当容器内的程序需要读取一个文件时,Docker会通过联合文件系统从上到下查找并返回。
- 写入文件(Copy-on-Write机制):当容器需要修改一个已存在于只读层的文件时,Docker会先将该文件“复制”到顶部的可写层,然后在可写层中进行修改。
核心结论:容器内的所有修改(增、删、改)都只发生在最顶部的可写层中,绝对不会影响底层的原始镜像。这也解释了为什么容器的生命周期是临时的,一旦容器被删除,其可写层也随之消失。
三、Docker容器管理常用命令速查
掌握以下命令,你就掌握了Docker日常操作的核心。
| 操作分类 | 命令示例 | 说明 |
|---|---|---|
| 帮助 | docker --help | 获取Docker命令帮助 |
| 镜像下载 | docker pull centos | 下载CentOS镜像 |
| 镜像打包 | docker save -o centos.tar centos:7 | 将本地镜像打包为tar文件 |
| 镜像导入 | docker load -i centos.tar | 将tar包导入为本地镜像 |
| 启动容器 | docker run -it --name=c1 centos:latest /bin/bash | 启动一个交互式容器 |
| 挂起容器 | Ctrl+P+Q | 在容器内按下组合键,挂起容器(Detach) |
| 停止容器 | docker stop <容器ID/名称> | 停止运行中的容器 |
| 启动容器 | docker start <容器ID/名称> | 启动已停止的容器 |
| 进入容器 | docker attach <容器ID/名称> | 重新连接到正在运行的容器 |
| 容器导出 | docker export -o centos-httpd.tar c1 | 基于现有容器打包为tar文件 |
| 导入镜像 | docker import centos-httpd.tar centos-httpd:v1 | 基于容器导出文件生成新镜像 |
| 删除容器 | docker rm c1 | 删除已停止的容器 |
| 端口映射 | docker run -it -p 8081:80 --name c100 centos-httpd:v1 /bin/bash | 将宿主机8081端口映射到容器80端口 |
| 数据卷挂载 | docker run -it -v /share:/data --name c10 centos:7 | 将宿主机目录挂载到容器,实现数据持久化 |
| 时间同步 | docker run -it -v /etc/localtime:/etc/localtime centos:7 /bin/bash | 同步容器与宿主机时间 |
| 外部执行 | docker exec <容器ID/名称> <命令> | 在容器外执行容器内的命令 |
| 容器互联 | docker run --link c100:mysql -it --name c200 centos:7 /bin/bash | 建立容器间的连接 |
查看容器IP地址的三种方法:
-
进入容器查看:
docker run -it --name=c1 centos:7 /bin/bash yum install -y iproute net-tools ip a # 或 ifconfig -
在Docker Host查看:
docker inspect c1 -
在Docker Host执行容器命令:
docker exec c1 ifconfig
四、实战:两种制作应用镜像的方法
制作自己的应用镜像是Docker的核心技能,主要有两种方式。
方法一:使用 docker commit 提交镜像
这种方法类似于给虚拟机拍快照,将容器的当前状态保存为新镜像。
-
启动基础镜像并安装服务
# 启动基础镜像 docker run -it --name c1 centos:7 /bin/bash # 在容器内执行以下操作 # 1. 备份并更换yum源(以阿里云vault源为例,解决CentOS 7源失效问题) mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak cat > /etc/yum.repos.d/CentOS-Base.repo << 'EOF' [base] name=CentOS-7-Vault-Base baseurl=https://mirrors.aliyun.com/centos-vault/7.9.2009/os/x86_64/ gpgcheck=0 enabled=1 [updates] name=CentOS-7-Vault-Updates baseurl=https://mirrors.aliyun.com/centos-vault/7.9.2009/updates/x86_64/ gpgcheck=0 enabled=1 [extras] name=CentOS-7-Vault-Extras baseurl=https://mirrors.aliyun.com/centos-vault/7.9.2009/extras/x86_64/ gpgcheck=0 enabled=1 EOF # 2. 清理并重建缓存 yum clean all && yum makecache # 3. 安装httpd服务 yum -y install httpd echo "test httpd" > /var/www/html/index.html -
提交为新镜像
# 退出容器后,在宿主机执行 docker commit c1 centos-httpd:v1 -
测试应用镜像
docker run -it --name c2 centos-httpd:v1 /bin/bash # 在容器内启动服务并测试 httpd -k start curl http://127.0.0.1
方法二:使用 Dockerfile 创建应用镜像(推荐)
Dockerfile是一个文本文件,包含了构建镜像所需的所有指令。这是更标准、更可重复、更易于维护的方式。
Dockerfile 核心关键字解析:
| 关键字 | 说明 |
|---|---|
| FROM | 指定基础镜像 |
| MAINTAINER | 指定镜像创建者信息 |
| RUN | 运行命令(构建阶段执行) |
| CMD | 设置容器启动时执行的操作 |
| EXPOSE | 指定容器需要映射到宿主机的端口 |
| ENV | 用于设置环境变量 |
| ADD | 把Docker Host的文件复制到容器中 |
| VOLUME | 指定挂载点 |
| WORKDIR | 切换目录 |
五、Dockerfile 实战案例
案例1:创建启动即运行httpd应用的镜像
-
准备工作
mkdir /test && cd /test/ -
创建启动脚本
run-httpd.sh#!/bin/bash /usr/sbin/httpd -D FOREGROUND -
创建测试网页
index.htmltest httpd service!!! -
编写
DockerfileFROM centos:7 MAINTAINER "wenteacher@163.com" RUN yum clean all RUN yum -y install httpd ADD run-httpd.sh /run-httpd.sh RUN chmod -v +x /run-httpd.sh ADD index.html /var/www/html/ EXPOSE 80 WORKDIR / CMD ["/bin/bash", "/run-httpd.sh"] -
构建并测试镜像
# 创建镜像 docker build -t centos-httpd:v1 . # 测试镜像 docker run -d --name c2 centos-httpd:v1 curl http://<容器IP地址>
案例2:创建一个启动即运行Nginx应用的镜像
-
准备工作
mkdir nginxtest && cd nginxtest/ echo 'nginx is running!!!' > index.html -
编写
DockerfileFROM centos:7 MAINTAINER "wenteacher@163.com" RUN yum clean all && \ curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo && \ yum -y install epel-release RUN yum -y install nginx ADD index.html /usr/share/nginx/html/ RUN echo "daemon off;" >> /etc/nginx/nginx.conf EXPOSE 80 CMD /usr/sbin/nginx -
制作并测试镜像
# 制作nginx应用镜像 docker build -t centos-nginx:v1 . # 测试镜像(后台运行) docker run -d centos-nginx:v1
六、底层揭秘:容器镜像在Docker Host的存储位置
了解Docker在宿主机上的存储机制,有助于我们更好地理解其工作原理。
1. 存储位置与文件系统
Docker的容器镜像和容器数据都存放在服务器的/var/lib/docker/路径下。
- Ubuntu 发行版:默认存储方式为 AUFS。
- CentOS 发行版:默认存储方式为 Overlay 或 Overlay2。
OverlayFS简介:
它是一个现代联合文件系统,将单个Linux主机上的两个目录合并成一个目录(联合挂载)。
- lowerdir:只读层,对应 Image层。
- upperdir:可写层,对应 Container层。
- merged:合并后的统一视图,对应我们看到的 Container。
2. /var/lib/docker/overlay2 目录的四个阶段变化
| 阶段 | 描述 | /var/lib/docker/overlay2 状态 |
|---|---|---|
| 阶段一 | Docker运行前 | 无docker相关目录 |
| 阶段二 | 启动Docker后 | 创建overlay2等目录,但overlay2为空 |
| 阶段三 | 下载镜像后 | 出现多个目录,存储镜像的只读层(lowerdir) |
| 阶段四 | 运行容器后 | 在原有基础上,新增目录存储容器的可写层(upperdir) |
更多推荐

所有评论(0)