Docker实践学习笔记

1 PostgreSQL和插件的部署

需求:使用docker制作PostgreSQL的镜像并部署,同时需要为其安装postgis,pgrouting和timescaledb插件。

  1. 拉取基础镜像postgis/postgis,该镜像包含了postgrespostgis
1
docker pull postgis/postgis
  1. 编写dockerfile:这里以PostgresSQL 16为例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
FROM postgis/postgis:latest
# 设置腾讯云镜像源
RUN sed -i 's|http://deb.debian.org/debian|http://mirrors.tencentyun.com/debian|g' /etc/apt/sources.list

# 下载wget
RUN apt-get update && apt-get install wget

# 获取timescaledb的秘钥
RUN wget --quiet -O - https://packagecloud.io/timescale/timescaledb/gpgkey | apt-key add -
# 增加timescaledb的源
RUN sh -c "echo 'deb https://packagecloud.io/timescale/timescaledb/ubuntu/ focal main' > /etc/apt/sources.list.d/timescaledb.list"

# 安装timescaledb
RUN apt-get update && \
  apt-get install -y timescaledb-2-2.16.1-postgresql-16
# 安装 pgRouting
RUN apt-get update && \
  apt-get install -y postgresql-$PG_MAJOR-pgrouting

# 确保所有初始化脚本都被执行
CMD ["postgres"]

说明:

1
2
# 换源
sed -i 's|http://deb.debian.org/debian|http://mirrors.tencentyun.com/debian|g' /etc/apt/sources.list

^7c1a05

  • -i 表示直接在原文件中进行修改,而不是将结果输出到标准输出。
  • 's|old|new|g'
    • ssed 的替换命令,表示将一个字符串替换成另一个字符串。
    • | 是定界符,通常用 / 作为定界符,但在这里使用了 |,这在 URL 替换中很常见,因为 URL 中包含 /,这样可以避免冲突。
    • g 代表全局替换,表示替换行内所有出现的匹配字符串。如果省略 g,只会替换每行中第一个匹配的字符串。
  • 最后一个参数是sed操作的文件

1
sh -c "echo 'deb https://packagecloud.io/timescale/timescaledb/ubuntu/ focal main' > /etc/apt/sources.list.d/timescaledb.list"

^18d0f4

  • sh -c 是一个 shell 命令,用于执行字符串形式的命令。-c 表示后面跟随的内容是一条完整的命令,传递给 sh 来执行。

1
wget --quiet -O - https://packagecloud.io/timescale/timescaledb/gpgkey | apt-key add -

这条命令用于下载 TimescaleDB 的 GPG 公钥并将其添加到系统的受信任密钥列表中,以便 APT 包管理器能够验证从 TimescaleDB 软件源下载的软件包的真实性和完整性。

  • wget --quiet -O - https://packagecloud.io/timescale/timescaledb/gpgkey:
    • wget: 是一个用于从网络上下载文件的命令行工具。
    • --quiet: 这个选项使 wget 以静默模式运行,不输出下载过程中的信息,仅输出错误和重要消息。
    • -O -: 选项 -O 指定将下载的内容输出到某个文件,而不是默认的文件名。- 表示输出到标准输出(通常是终端)。
  • https://packagecloud.io/timescale/timescaledb/gpgkey: 这是 TimescaleDB 的 GPG 公钥的 URL。wget 从这个地址下载公钥文件。
  • apt-key add -:
    • apt-key: 是一个 APT 包管理工具,用于管理 APT 的受信任密钥列表。
    • add: 是 apt-key 的一个子命令,用于添加新的密钥到系统的受信任密钥列表中。
    • -: 指定从标准输入(即管道)读取密钥数据。apt-key add - 将通过管道传递过来的 GPG 公钥添加到 APT 的受信任密钥列表中。
  1. 构建镜像:
1
docker build -t postgres:tag .
  1. 创建数据卷,并运行容器:
1
2
3
4
5
6
7
8
9
10
docker volume create pg_data
docker run -d \
--name postgres \
-e POSTGRES_USER=admin \  # 用户名
-e POSTGRES_PASSWORD=admin123 \  # 密码
-e POSTGRES_DB=airport \ # 数据库
-e TZ=Asia/Shanghai \
-p 5432:5432 \
-v pg_data:/var/lib/postgresql/data \  # 挂载到pg_data
postgres:tag

其中数据卷pg_data保存postgresql的持久化数据。注意,如果使用目录挂载,数据库、用户和密码设置不会生效。

  1. 加载插件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 进入postgres容器
docker exec -it postgres /bin/bash
# 预加载timescaledb
echo "shared_preload_libraries = 'timescaledb'" >> /var/lib/postgresql/data/postgresql.conf

# 这里需要重启容器!!!
docker restart postgres
#--------------------------------------------------------
# 再次进入postgres容器
docker exec -it postgres /bin/bash
# 连接数据库
psql -U admin -d airport
# 扩展插件
create extension pgrouting;
create extension timescaledb;
# 验证
select extname from pg_extension;

2 多模块系统部署

描述:现在有一个多模块的系统,即父模块(只有pom管理依赖)下有多个子模块,程序的入口位于子模块admin中。现在需要打成jar包,并使用docker部署在服务器中。

  • 入口模块adminpom添加:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>xxx</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<finalName>xxxx</finalName>
</build>

这里的finalName为打包后jar包的名称。

  • admin目录下执行下列命令,生成可执行jaradmin.jar
1
mvn clean package
  • 准备dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 基础镜像
FROM openjdk:8-jre

WORKDIR /app

# 设定时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# 拷贝jar包
COPY admin.jar /admin.jar

EXPOSE 8080

# 入口
ENTRYPOINT ["java", "-jar", "admin.jar"]
  • Dockerfilejar包上传至服务器的文件夹中,例如/usr/local/admin
1
2
3
docker build -t admin:tag .

docker run -d --name admin -p 8080:8080 admin:tag

3 容器的日志

容器的日志,可以在容器中查看,也可以将日志文件的目录挂载到宿主机的目录上(或数据卷),直接在宿主机上查看。

假设logback的配置文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 日志存放路径 -->
<property name="log.path" value="/usr/local/xxx/logs"/>
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />

<!-- 控制台输出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>

<!-- 文件输出 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys_info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys_info.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>

<!-- 日志级别 -->
<root level="info">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>

</configuration>

其中,日志文件的输出位置位于/usr/local/xxx/logs

  • 如果Dockerfile没有另外设置WORKDIR,则日志位于容器的上述目录,可进入容器中查看:
1
2
3
4
5
6
7
8
9
docker exec -it <container_id> /bin/bash

# 进入容器

cd /usr/local/xxx/logs

# 即可查看日志文件sys_info.log

cat sys_info.log

如果设置了WORKDIR,假设为app,则:

1
2
3
4
5
6
7
8
9
docker exec -it <container_id> /bin/bash

# 进入容器

cd app/usr/local/xxx/logs

# 即可查看日志文件sys_info.log

cat sys_info.log
  • 可以将该目录挂载到宿主机的某个目录中:
1
docker run -d --name xxxx -v /usr/local/xxx/logs:/usr/local/xxx/logs xxx:latest

则可以在宿主机中直接查看日志:

1
2
3
cd /usr/local/xxx/logs

cat sys_info.log

同样的,如果设置了WORKDIR,假设为app,则:

1
2
3
4
5
docker run -d --name xxxx -v /usr/local/xxx/logs:app/usr/local/xxx/logs xxx:latest

cd /usr/local/xxx/logs

cat sys_info.log

4 离线安装Docker

  1. 下载 Docker 安装包:Docker 官方网站下载适合 Docker 安装包(中科大镜像源

一般来说,需要下载以下文件:

1
2
3
4
containerd.io_<version>_<arch>.deb
docker-ce_<version>_<arch>.deb
docker-ce-cli_<version>_<arch>.deb
docker-compose-plugin_<version>_<arch>.deb

其中arch的查看方法详见:[[处理器架构#1 查看]]

  • 安装
1
dpkg -i # 上述所有的deb,可能会报错,解决方法详见下方
  • 启动
1
2
3
4
5
systemctl start docker

systemctl enable docker

systemctl status docker
  • 验证
1
docker --version # 或者 docker version
  1. Docker Compose 发布页面 下载 Docker Compose 二进制文件。
  • 安装
1
cp docker-compose-<version> /usr/local/bin/docker-compose
  • 赋予执行权限
1
chmod +x /usr/local/bin/docker-compose
  • 验证
1
docker-compose --version

在安装Docker的过程中,可能会出现错误:

1
groupadd:无法打开 /etc/group

该错误的原因是因为对系统的关键文件进行了锁定,防止篡改,可以通过以下命令查看是否锁定:

1
lsattr /etc/group

如果显示:

1
----i---------- /etc/group

权限 i 表示该文件不能被删除、改名、设定链接关系,同时不能写入或新增内容。

可执行下列执行暂时放开权限:

1
2
chattr -i /etc/group
chattr -i /etc/gshadow

安装完成后,可再执行以下命令恢复配置:

1
2
chattr +i /etc/group
chattr +i /etc/gshadow

5 应用更新

问题描述:Docker部署springboot应用时,怎么设置才能避免每次更新jar包时,需要重新构建镜像?

  • 提前构建一份镜像
1
2
3
4
5
6
7
8
9
# Dockerfile
FROM openjdk:8-jre

WORKDIR var/lib/app/

EXPOSE 8082

# 这里不复制 JAR 文件,而是通过挂载
CMD ["java", "-jar", "var/lib/app/application.jar"]

构建镜像:

1
docker build -t application .
  • 使用docker-compose部署多个docker容器,例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
services:
sgis-postgis:
image: postgres-timescale:15
container_name: postgis
volumes:
- "../postgres/data:/var/lib/postgresql/data/"
ports:
- "5432:5432"
networks:
- sgis_network
restart: always

rabbitmq:
image: rabbitmq:latest
container_name: rabbitmq
ports:
- "5672:5672"
- "15672:15672"
volumes:
- "../rabbitmq:/var/lib/rabbitmq" # 持久化RabbitMQ数据
environment:
- RABBITMQ_DEFAULT_USER: "fisher" # 设置默认用户名
- RABBITMQ_DEFAULT_PASS: "fisher" # 设置默认密码
networks:
- sgis_network
restart: always

redis:
image: redis:latest
container_name: redis
ports:
- "6379:6379"
networks:
- sgis_network
command:
--save 60 1
--loglevel warning
restart: always

tomcat:
image: "tomcat:latest"
container_name: tomcat
privileged: true
environment:
- TZ="Asia/Shanghai"
ports:
- "9016:8080"
networks:
- sgis_network
volumes:
- "../tomcat/webapps:/usr/local/tomcat/webapps"
restart: always

application:
image: application:latest
container_name: application
ports:
- "8082:8082"
volumes:
- "../app/application.jar:/var/lib/app/application.jar"
networks:
- sgis_network
restart: always
depends_on:
- sgis-postgis
- rabbitmq
- redis
networks:
sgis_network:
driver: bridge

其中../app/application.jar为本地的jar文件存放位置,/var/lib/app/application.jar为容器内jar的存放位置

使用命令启动多个容器:

1
docker-compose up -d

当jar更新时,首先停止并删除原来的application容器,然后替换原有的jar包,最后重启:

1
2
3
4
# 删除原来的容器
docker rm -f application

# 替换原有的jar包
1
2
# 重启
docker-compose up -d

6 Overlay2

Docker 使用了多种文件系统驱动(Storage Drivers)来管理镜像和容器的存储。这些文件系统提供了分层存储机制,使 Docker 能高效地构建和运行容器。

查看Docker的文件系统驱动:

1
2
3
docker info | grep "Storage Driver"

Storage Driver: overlay2

Overlay 文件系统(OverlayFS)是一种现代的联合文件系统(Union Filesystem),最初由 Linux 内核社区引入,用于高效管理文件和目录的分层。Docker 利用 OverlayFS 实现了镜像和容器的分层文件系统,是其默认的存储驱动之一(尤其是 overlay2 驱动)。

6.1 层(Layer)

Docker 的层是一个只读文件系统,它记录了镜像或容器的文件系统变化。每一层都建立在其下层之上,形成了分层的存储结构。

特点:

  • 增量存储:每一层只存储相对于上一层的差异。
  • 只读:所有的层均为不可变的。
  • 可共享:多个镜像或容器可以共享相同的层。

6.1.1 层的组成

基础层(Base Layer):

  • 是镜像的最底层,通常包含一个操作系统的最小安装包(如 Ubuntu、Alpine)。
  • 基础层提供了运行应用程序所需的基本环境。

中间层(Intermediate Layer):

  • 每次在 Dockerfile 中执行指令(如 RUNCOPYADD)时,都会创建一个新的层。
  • 中间层记录了该指令所引入的更改。

可写层(Writable Layer):

  • 容器启动时,Docker 在镜像层之上添加一个可写层。
  • 容器中的所有文件写操作(新增、修改或删除)都发生在这一层。

6.1.2 层的存储路径

在 Docker 中,层的实际存储取决于所使用的存储驱动:

  • OverlayFS:
    • 每一层存储在 /var/lib/docker/overlay2/ 目录下。
    • 每个层会有一个唯一的目录,包含层的元数据和文件。
  • AUFS、devicemapper 等其他驱动:
    • 每种驱动的存储方式有所不同,但都遵循分层结构。

6.1.3 Layer、Image和Container

image-20241224144040771

1
2
3
4
5
6
7
8
9
10
镜像:
Layer 1 (基础层,如操作系统)
+ Layer 2 (运行时环境,如 Python)
+ Layer 3 (应用文件)

容器:
Layer 1 (共享的基础层)
+ Layer 2 (共享的运行时环境)
+ Layer 3 (共享的应用文件)
+ Writable Layer (容器的可写层,存储运行时的动态更改)

镜像

  • 镜像是多个层的有序集合,是一种静态的文件系统快照。
  • 镜像可以被多次重用,多个容器可以基于同一个镜像创建。
  • 通过 Dockerfile 构建镜像时,每条指令(如 RUNCOPY)都会创建一个新层。

容器

  • 容器是镜像的一个实例,运行时包含镜像的内容以及一个额外的可写层。
  • 每个容器有自己的文件系统和网络环境,但共享镜像层。
  • 容器的可写层是临时的,容器删除后更改会丢失(除非通过卷或持久化存储)。
  • 容器启动时,Docker 将镜像层和容器的可写层组合在一起,形成一个联合文件系统。

6.2 工作原理

OverlayFS 将两个目录(称为下层和上层)叠加在一起,显示为一个单一的目录(称为叠加层)。

  • 下层(lowerdir):

    • 只读目录。
    • Docker 镜像的每一层通常对应下层。
  • 上层(upperdir):

    • 可写目录。

    • 容器的可写层对应上层。

  • 工作目录(workdir):

    • OverlayFS 的临时工作目录,用于存储文件系统操作(如文件的写入和删除)的中间状态。
  • 叠加层(merged):

    • 用户看到的最终文件系统视图。

    • OverlayFS 将 lowerdirupperdir 合并,提供透明的访问。

6.3 存储过程

层:直接存储。

镜像:Docker 镜像由多个只读层组成,每一层代表了一次镜像构建中的更改。OverlayFS 将这些只读层视为多个 lowerdir,通过叠加形成一个完整的文件系统视图。

容器:每个容器都会在镜像层之上添加一个可写层(upperdir)。容器运行时,所有文件的修改都发生在这个可写层中。

当使用 OverlayFS 时,Docker 的存储目录(如 /var/lib/docker/overlay2)包含以下子目录:

  1. diff/存储每个层的实际文件数据。
  2. merged/存储叠加后的文件系统视图,容器运行时可见。
  3. upper/存储容器的可写层(仅针对运行的容器)。
  4. work/用于 OverlayFS 的中间操作。

镜像的存储

  • 准备一个没有安装任何镜像的Docker环境
1
2
3
4
[root@kube1 overlay2]# ll
total 0
brw------- 1 root root 253, 0 Jan 27 22:04 backingFsBlockDev
drwx------ 2 root root 6 Jan 27 22:04 l

可以看到/var/lib/docker/overlay2目录只有backingFsBlockDevl 两个目录。

  • 拉取Nginx镜像
1
2
3
4
5
6
7
8
9
10
11
12
13
[root@kube1 overlay2]# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
2f44b7a888fa: Pull complete
8b7dd3ed1dc3: Pull complete
35497dd96569: Pull complete
36664b6ce66b: Pull complete
2d455521f76c: Pull complete
dc9c4fdb83d6: Pull complete
8056d2bcf3b6: Pull complete
Digest: sha256:4c0fdaa8b6341bfdeca5f18f7837462c80cff90527ee35ef185571e1c327beac
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

可以看到目前版本的Nginx镜像一共被分为7层拉取。

  • 进入/var/lib/docker/overlay2/目录,发现多了7个目录,对应7个层
1
2
3
4
5
6
[root@kube1 overlay2]# ls
10dd8ff4345f0387e720d5fdd1df6c6d2b73547d912d139868afd7835ff83503 backingFsBlockDev
2839c8c9efc53d0d0a89611b08d2ecead4717031e2458efe8721e2ec0007d7b1 c2f6ab870d00b7709f1745e0373fa6eb7f90cec78348d36b66ba57c3108045a0
410fc9512d1e11b714b6643ce2dcd987df56cc0025b4133afb4645f865757584 cb9d1b97aade9bd3e3a56268a8608622a86a7ac0d0ade9bbb2b0679f4c0ed620
48305d303096d54e0eea026f3366357e2c485c7d5b7c5939e5a062cc36bd03b2 l
a593596d98137556641a7376b14a4d0b00f6f2d6f05bdffe05b01d740a65e894
  • 查看Nginx镜像信息,可以看到镜像的每个层的存储位置GraphDriver.Data
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/48305d303096d54e0eea026f3366357e2c485c7d5b7c5939e5a062cc36bd03b2/diff:/var/lib/docker/overlay2/cb9d1b97aade9bd3e3a56268a8608622a86a7ac0d0ade9bbb2b0679f4c0ed620/diff:/var/lib/docker/overlay2/10dd8ff4345f0387e720d5fdd1df6c6d2b73547d912d139868afd7835ff83503/diff:/var/lib/docker/overlay2/410fc9512d1e11b714b6643ce2dcd987df56cc0025b4133afb4645f865757584/diff:/var/lib/docker/overlay2/a593596d98137556641a7376b14a4d0b00f6f2d6f05bdffe05b01d740a65e894/diff:/var/lib/docker/overlay2/c2f6ab870d00b7709f1745e0373fa6eb7f90cec78348d36b66ba57c3108045a0/diff",
"MergedDir": "/var/lib/docker/overlay2/2839c8c9efc53d0d0a89611b08d2ecead4717031e2458efe8721e2ec0007d7b1/merged",
"UpperDir": "/var/lib/docker/overlay2/2839c8c9efc53d0d0a89611b08d2ecead4717031e2458efe8721e2ec0007d7b1/diff",
"WorkDir": "/var/lib/docker/overlay2/2839c8c9efc53d0d0a89611b08d2ecead4717031e2458efe8721e2ec0007d7b1/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:571ade696b261f0ff46e3cdac4635afc009c4ed3429950cb95cd7e5f70ba0a07",
"sha256:b6c2a8d6f0ac89ef77e161532f3d9d0dc5dfe0a5f20042e0afc0ad14288405eb",
"sha256:b61d4b2cd2daf06047984c5876a35338c2beb5ae3f6bef479d25f05772a6a482",
"sha256:eddcd06e5ef9b91677526f6c55fa01a7d6963c435d5cf2bfb488d91aaa72d4a8",
"sha256:b4ad478450363f0a8020bb5552641fe6077e78fca48da4d77a979724a3ad2a72",
"sha256:fbcc9bc44d3e165e7e4f56fb189a05ea5c562a733985ec00d5e3fad309eb63cc",
"sha256:009507b8560964795eab5126f6363cb2b7403596adf370c9e95d4648c43e771f"
]
}
  • 将这7个目录展开,可以看到目录结构基本一致
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[root@kube1 overlay2]# ls */
10dd8ff4345f0387e720d5fdd1df6c6d2b73547d912d139868afd7835ff83503/:
committed diff link lower work

2839c8c9efc53d0d0a89611b08d2ecead4717031e2458efe8721e2ec0007d7b1/:
diff link lower work

410fc9512d1e11b714b6643ce2dcd987df56cc0025b4133afb4645f865757584/:
committed diff link lower work

48305d303096d54e0eea026f3366357e2c485c7d5b7c5939e5a062cc36bd03b2/:
committed diff link lower work

a593596d98137556641a7376b14a4d0b00f6f2d6f05bdffe05b01d740a65e894/:
committed diff link lower work

c2f6ab870d00b7709f1745e0373fa6eb7f90cec78348d36b66ba57c3108045a0/:
committed diff link

cb9d1b97aade9bd3e3a56268a8608622a86a7ac0d0ade9bbb2b0679f4c0ed620/:
committed diff link lower work

l/:
D6T76WE7CR4JMMPUM4NTO55AXG JMSMKE6MVY4KJ5CB5ZDDIDVPW2 SX6PROXGAB4ZJPH7HTPYRQUMH2 WCBZTXQX2YLYEZWCUYGFHKTAST
GTRRPSN3NBPKHCIMECN7X7BJEP LHNRUYWVMA3S5JGMBYRKW4BWHI TMLMOWKXKUJ4WAWMNDCJVVLMBG

可以看到c2f6ab870d00b7709f1745e0373fa6eb7f90cec78348d36b66ba57c3108045a0文件夹中不存在lower文件,说明它是最底层的,相当于是根镜像,即docker pull时下载的第一层。


总结:拉取一个镜像时,会按照镜像的层在/var/lib/docker/overlay2下新增相应的目录。

容器的存储

  • 当前环境只有一个nginx镜像,没有容器,/var/lib/docker/overlay2/目录下只有镜像层的存储目录。
  • 启动一个容器
1
2
3
4
5
[root@kube1 overlay2]# docker run -id nginx
76cd5f0f5a3f8969d3061dfc94107858f4ae4e9c5634320347c8650528434e87
[root@kube1 overlay2]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
76cd5f0f5a3f nginx "/docker-entrypoint.…" 3 seconds ago Up 2 seconds 80/tcp festive_lederberg
  • 查看/var/lib/docker/overlay2/目录,发现新增了两个目录:其中带-init的目录是只读的;没有init的容器目录才是容器的读写目录
1
2
3
4
5
6
7
8
9
10
11
12
[root@kube1 overlay2]# ll
total 0
drwx--x--- 4 root root 72 Jan 27 22:12 10dd8ff4345f0387e720d5fdd1df6c6d2b73547d912d139868afd7835ff83503
drwx--x--- 4 root root 72 Jan 28 01:10 2839c8c9efc53d0d0a89611b08d2ecead4717031e2458efe8721e2ec0007d7b1
drwx--x--- 4 root root 72 Jan 27 22:12 410fc9512d1e11b714b6643ce2dcd987df56cc0025b4133afb4645f865757584
drwx--x--- 4 root root 72 Jan 27 22:12 48305d303096d54e0eea026f3366357e2c485c7d5b7c5939e5a062cc36bd03b2
drwx--x--- 4 root root 72 Jan 27 22:12 a593596d98137556641a7376b14a4d0b00f6f2d6f05bdffe05b01d740a65e894
brw------- 1 root root 253, 0 Jan 27 22:04 backingFsBlockDev
drwx--x--- 3 root root 47 Jan 27 22:12 c2f6ab870d00b7709f1745e0373fa6eb7f90cec78348d36b66ba57c3108045a0
drwx--x--- 5 root root 69 Jan 28 01:10 cb03d50e1baaf7e40f3c981c428213cef7a3b375d7d9134cc3db932fd94b9bcb
drwx--x--- 4 root root 72 Jan 28 01:10 cb03d50e1baaf7e40f3c981c428213cef7a3b375d7d9134cc3db932fd94b9bcb-init
drwx--x--- 4 root root 72 Jan 27 22:12 cb9d1b97aade9bd3e3a56268a8608622a86a7ac0d0ade9bbb2b0679f4c0ed620

此外,容器id和该目录的名称并不一致。

  • 查看容器的详细信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@kube1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
76cd5f0f5a3f nginx "/docker-entrypoint.…" 26 minutes ago Up 26 minutes 80/tcp festive_lederberg
[root@kube1 ~]# docker inspect 76
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/cb03d50e1baaf7e40f3c981c428213cef7a3b375d7d9134cc3db932fd94b9bcb-init/diff:/var/lib/docker/overlay2/2839c8c9efc53d0d0a89611b08d2ecead4717031e2458efe8721e2ec0007d7b1/diff:/var/lib/docker/overlay2/48305d303096d54e0eea026f3366357e2c485c7d5b7c5939e5a062cc36bd03b2/diff:/var/lib/docker/overlay2/cb9d1b97aade9bd3e3a56268a8608622a86a7ac0d0ade9bbb2b0679f4c0ed620/diff:/var/lib/docker/overlay2/10dd8ff4345f0387e720d5fdd1df6c6d2b73547d912d139868afd7835ff83503/diff:/var/lib/docker/overlay2/410fc9512d1e11b714b6643ce2dcd987df56cc0025b4133afb4645f865757584/diff:/var/lib/docker/overlay2/a593596d98137556641a7376b14a4d0b00f6f2d6f05bdffe05b01d740a65e894/diff:/var/lib/docker/overlay2/c2f6ab870d00b7709f1745e0373fa6eb7f90cec78348d36b66ba57c3108045a0/diff",
"MergedDir": "/var/lib/docker/overlay2/cb03d50e1baaf7e40f3c981c428213cef7a3b375d7d9134cc3db932fd94b9bcb/merged",
"UpperDir": "/var/lib/docker/overlay2/cb03d50e1baaf7e40f3c981c428213cef7a3b375d7d9134cc3db932fd94b9bcb/diff",
"WorkDir": "/var/lib/docker/overlay2/cb03d50e1baaf7e40f3c981c428213cef7a3b375d7d9134cc3db932fd94b9bcb/work"
},
"Name": "overlay2"
}
}
  • 当进入容器创建一个文件,然后在容器相应的merged目录也会出现这个文件。
1
2
3
4
5
6
7
8
[root@kube1 ~]# docker exec -it 76 /bin/bash
root@76cd5f0f5a3f:/# ls
bin boot dev docker-entrypoint.d docker-entrypoint.sh etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var
root@76cd5f0f5a3f:/# touch a.txt
root@76cd5f0f5a3f:/# exit
[root@kube1 merged]# pwd
/var/lib/docker/overlay2/cb03d50e1baaf7e40f3c981c428213cef7a3b375d7d9134cc3db932fd94b9bcb/merged
[root@kube1 merged]# ls a.txt

总结:运行一个容器的时候,会在/var/lib/docker/overlay2下新增两个目录(-init区分),容器实际运行数据存储在该目录下的merged目录中。