容器是隔离环境,容器内程序的文件、配置、运行时产生的容器都在容器内部,我们要读写容器内的文件非常不方便。大家思考几个问题:

  • 如果要升级MySQL版本,需要销毁旧容器,那么数据岂不是跟着被销毁了?

  • MySQL、Nginx容器运行后,如果我要修改其中的某些配置该怎么办?

  • 我想要让Nginx代理我的静态资源怎么办?

因此,容器提供程序的运行环境,但是 程序运行产生的数据、程序运行依赖的配置都应该与容器解耦。

数据卷(volume)

是一个虚拟目录,是容器内目录与宿主机目录之间映射的桥梁。

以Nginx为例,我们知道Nginx中有两个关键的目录:

  • html:放置一些静态资源

  • conf:放置配置文件

如果我们要让Nginx代理我们的静态资源,最好是放到html目录;如果我们要修改Nginx的配置,最好是找到conf下的nginx.conf文件。

但遗憾的是,容器运行的Nginx所有的文件都在容器内部。所以我们必须利用数据卷将两个目录与宿主机目录关联,方便我们操作。

因为容器当中的目录,我们不能操作我们要是想修改内容的话需要

通过数据卷来进行我们创建数据卷的时候

他也会自动的在宿主机当中会在指定的目录下创建出对应的目录

这个目录会和我们的数据卷进行绑定

一般这个目录他会在/var下面进行创建然后

第二部的时候我们可以在创建容器的时候我们要绑定的那个数据卷

通过数据卷建立  创建出来目录的映射

步骤

容器与数据卷的挂载要在创建容器时配置,对于创建好的容器,是不能设置数据卷的。而且创建容器的过程中,数据卷会自动创建。

(一)

nginx的html目录挂载

1.首先创建容器并指定数据卷,注意通过 -v 参数来指定数据卷

docker run -d --name nginx -p 80:80 -v html:/usr/share/nginx/html nginx:1.20.2

2.然后查看数据卷

docker volume ls

3.查看数据卷详情

docker volume inspect html

4.查看/var/lib/docker/volumes/html/_data目录

ll /var/lib/docker/volumes/html/_data

5.进入该目录,并随意修改index.html内容

cd /var/lib/docker/volumes/html/_data

vi index.html

6.打开页面,查看效果

7.进入容器内部,查看/usr/share/nginx/html目录内的文件是否变化

docker exec -it nginx bash

本地目录挂载

MySQL的匿名数据卷

# 1.查看MySQL容器详细信息

docker inspect mysql

# 关注其中.Config.Volumes部分和.Mounts部分

可以发现这个容器声明了一个本地目录,需要挂载数据卷,但是数据卷未定义。这就是匿名卷。

然后,我们再看结果中的.Mounts部分:

可以发现,其中有几个关键属性:

  • Name:数据卷名称。由于定义容器未设置容器名,这里的就是匿名卷自动生成的名字,一串hash值。

  • Source:宿主机目录

  • Destination : 容器内的目录

上述配置是将容器内的/var/lib/mysql这个目录,与数据卷29524ff09715d3688eae3f99803a2796558dbd00ca584a25a4bbc193ca82459f挂载。于是在宿主机中就有了/var/lib/docker/volumes/29524ff09715d3688eae3f99803a2796558dbd00ca584a25a4bbc193ca82459f/_data这个目录。这就是匿名数据卷对应的目录,其使用方式与普通数据卷没有差别。

接下来,可以查看该目录下的MySQL的data文件:

ls -l /var/lib/docker/volumes/

29524ff09715d3688eae3f99803a2796558dbd00ca584a25a4bbc193ca82459f/_data

当我们切换到mysql宿主机目录里面的时候
这个就是mysql数据库的数据文件这个就是匿名的数据卷速做的事情
当我们创建容器的时候他内部会自动为我们创建一个
他就起到了一个数据备分的作用
挂载本地目录或文件

可以发现,数据卷的目录结构较深,如果我们去操作数据卷目录会不太方便。在很多情况下,我们会直接将容器目录与宿主机指定目录挂载。挂载语法与数据卷类似:

案例

删除并重新创建mysql容器,并完成本地目录挂载:

  • 挂载/root/mysql/data到容器内的/var/lib/mysql目录

  • 挂载/root/mysql/init到容器内的/docker-entrypoint-initdb.d目录(初始化的SQL脚本目录)

  • 挂载/root/mysql/conf到容器内的/etc/mysql/conf.d目录(这个是MySQL配置文件目录)

在课前资料中已经准备好了mysql 的init目录、conf目录、data目录,可以直接将其上传到Linux服务器中的 /root/mysql 目录下。

最终执行的指令如下:

docker run -d \
 --name mysql \
 -p 3307:3306 \
 -e MYSQL_ROOT_PASSWORD=123 \
 -e TZ=Asia/Shanghai \
 -v /root/mysql/data:/var/lib/mysql \
 -v /root/mysql/init:/docker-entrypoint-initdb.d \
 -v /root/mysql/conf:/etc/mysql/conf.d \
 mysql:8

这里我们要挂载在三个目录

第一个目录是数据目录这个是为了进行数据备份即使将容器删掉数据也能保留下来,

第二个是配置文件例如我们想修改mysql配置文件我们可以修改这个  ,

第三个是初始化脚本我们在容气创建好了启动了MySQL

 例如我们想初始化一些数据库比如我们像把项目的数据库表结构创建好我们可以把这个脚本放到 这个目录下借于这些目录在哪里存放的,我们要去官方文档去查找

自定义镜像

我们将来部署项目是基于Docker来部署的这时候我们就需要他的印象这个java应用的镜像这个时候我们要自己来制作这个Docker镜像,这个时候我们要清楚他的结构包含四个部分

程序运行需要的系统函数库、环境、配置、依赖。

然后打包镜像分为四个步骤

  • 准备Linux运行环境(java项目并不需要完整的操作系统,仅仅是基础运行环境即可)

  • 安装并配置JDK

  • 拷贝jar包

  • 配置启动脚本

上述步骤中的每一次操作其实都是在生产一些文件(系统运行环境、函数库、配置最终都是磁盘文件),所以镜像就是一堆文件的集合。

但需要注意的是,镜像文件不是随意堆放的,而是按照操作的步骤分层叠加而成,每一层形成的文件都会单独打包并标记一个唯一id,称为Layer(层)。这样,如果我们构建时用到的某些层其他人已经制作过,就可以直接拷贝使用这些层,而不用重复制作

例如,第一步中需要的Linux运行环境,通用性就很强,所以Docker官方就制作了这样的只包含Linux运行环境的镜像。我们在制作java镜像时,就无需重复制作,直接使用Docker官方提供的CentOS或Ubuntu镜像作为基础镜像。然后再搭建其它层即可,这样逐层搭建,最终整个Java项目的镜像结构如图所示:

Dockerfile

由于制作镜像的过程中,需要逐层处理和打包,比较复杂,所以Docker就提供了自动打包镜像的功能。我们只需要将打包的过程,每一层要做的事情用固定的语法写下来,交给Docker去执行即可。而这种记录镜像结构的文件就称为Dockerfile。

其中的语法比较多,比较常用的有:

指令

说明

示例

FROM

指定基础镜像

FROM centos:7

ENV

设置环境变量,可在后面指令使用

ENV key value

COPY

拷贝本地文件到镜像的指定目录

COPY ./xx.jar /tmp/app.jar

RUN

执行Linux的shell命令,一般是安装过程的命令

RUN yum install gcc

EXPOSE

指定容器运行时监听的端口,是给镜像使用者看的

EXPOSE 8080

ENTRYPOINT

镜像中应用的启动命令,容器运行时调用

ENTRYPOINT java -jar xx.jar

制作镜像的时候首先要创建一个目录,

然后切换到这个目录,

然后准备相关的JDK和java 的jar包然后再准备一个Dockerfile这个文件,

然后进入编写里面的内容,

首先第一步指定的基础进项然后

第二部拷贝JDK 然后去运行一条指令进行解压JDK 解压完之后把这个解压删掉,

第三部设置环境变量配置相关的JAVA_HOME 和相关的PATH 相关的目录要配置成解压出来的名字

第四部你要创建应用的目录,就是那个你刚刚创建出来的那个目录,然后切换到这个目录下面,

第五部复制应用JDK 文件将你的JDK文件放到这个目录当中,

第六部将那个端口暴露出来,

最后一步运行一条命令启动这个jar 包

然后将这些文件都上传上来上传之后呢,

我们要执行一条命令docker build -t后面跟上镜像的名字

例如,要基于 centos:7 镜像来构建一个Java应用,其Dockerfile内容如下:

# 使用 CentOS 7 作为基础镜像
FROM centos:7 
# 添加 JDK 到镜像中 
COPY jdk17.tar.gz /usr/local/ 
RUN tar -xzf /usr/local/jdk17.tar.gz -C /usr/local/ && rm /usr/local/jdk17.tar.gz 
# 设置环境变量 
ENV JAVA_HOME=/usr/local/jdk-17.0.10 
ENV PATH=$JAVA_HOME/bin:$PATH 
# 创建应用目录 
RUN mkdir -p /app 
WORKDIR /app 
# 复制应用 JAR 文件到容器 
COPY app.jar app.jar 
# 暴露端口 
EXPOSE 8080 
# 运行命令 
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app/app.jar"]

Dockerfile文件编写好了之后,就可以使用如下命令来构建镜像了。

docker build -t 镜像名 .

  • -t :是给镜像起名,格式依然是repository:tag的格式,不指定tag时,默认为latest

  • . :是指定Dockerfile所在目录,如果就在当前目录,则指定为"."

docker build -t app1.0 .

当你敲下这条命令时,Docker 实际流程是:

① 找 Dockerfile
② 读取 FROM / RUN / COPY / CMD 等指令
③ 一层一层创建镜像层
④ 每一层都会缓存
⑤ 最终生成一个完整镜像
⑥ 给它打标签 app1.0

📦 镜像是“分层”的
这也是 Docker 快、节省空间的原因。
 

用“当前目录”里的 Dockerfile,制作(构建)一个 Docker 镜像,
并给这个镜像起名叫 app1.0。

现实世界    Docker
软件名    app
版本号    1.0
安装包    镜像

最后的 .(重点‼️)

.

👉 表示“当前目录”

这个点非常关键,它的含义是:

构建上下文(build context)

Docker 会做什么?
Docker 会:
    1.    读取当前目录里的:
    •    Dockerfile
    •    代码文件
    •    配置文件
    2.    把这些文件打包发送给 Docker 引擎
    3.    按 Dockerfile 里的步骤一层一层构建镜像

创建并构建这个容器

总结

更多推荐