Docker学习笔记02

本文详细介绍了Docker镜像的加载原理,包括UnionFS和分层结构,强调了镜像的轻量级和高性能特性。Docker通过容器数据卷实现数据持久化,支持容器间的共享和继承。此外,文章还探讨了容器的网络互联,包括新建网络、容器连接和不同网络间通信。最后,提到了Springboot项目如何打包为Docker镜像。
摘要由CSDN通过智能技术生成

Docker镜像详解

UnionFS(联合文件系统)

我们下载的时候看到的一层层就是这个!
UnionFS (联合文件系统): Union文件系统( UnionFS )是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtualfilesystem)。Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性∶一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录

Docker镜像加载原理

docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootis(boot file system)主要包含bootloader和kernel,bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
黑屏±–开机进入系统
rootfs (root fle system),在boots之上。包含的就是典型Linux系统中的/dev, /proc, /bin, /etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu , Centos等等。

在这里插入图片描述

为什么每个容器都很小呢?

对于一个精简的OS , rootfs可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直接用Host的kerne|T自己只需要提供rootfs就可以了。由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别,因此不同的发行版可以公用bootfs。

分层理解

可以观察一下下载一个镜像的时候的日志输出,会发现镜像资源是一层一层的在下载的。

在这里插入图片描述

为什么Docker镜像要采用这种分层的结构呢?
最大的好处莫过于是资源共享了。比方说有多个镜像都从相同的 base 镜像构建而来,那么宿主机只需要在磁盘上保留一份 base 镜像,同时内存中也只需要加载一份 base 镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。(只需要去下载没有的层。)
我们可以通过 docker inspect命令从 查看镜像分层
在这里插入图片描述

  • 所有的 Docker 镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上创建新的镜像层。
  • Docker 镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部
  • 这一层就是我们通常说的容器层,容器之下的都叫镜像层

commit 镜像

创建镜像有两种方式,一种是再由镜像创建的容器的基础上做了修改后(通常是增加更多东西),然后讲该容器commit提交成一个镜像,之后就可以根据这个新的镜像直接创建容器。还有一种是根据Dockerfile来创建镜像,这个后面讲。

docker commit 提交容器成为一个新的副本

docker commit -m=“提交的描述信息” -a=“作者” 容器id 目标镜像名[tag]

  • 案例:

    • 问题:在 tomcat 容器的 webapps 下是没有文件的 ,每次启动的时候都要将 webapps.dist 目录下的内容拷贝到 webapps 目录下(cp -r webapps.dist/* webapps/)
    • 解决方案:自己打包一个镜像,方便以后使用

    之前的实战中已经将webapps.dist 目录下的内容拷贝到 webapps 目录下了,现在只需要将该容器commit成一个镜像之后使用就可以了。

    在宿主机上执行命令:docker commit -a=“yh” -m=“add webappps content” 9179ed315114 yh/tomcat:v2

    实践如下:

    [root@muyi ~]# docker commit -a="yh" -m="add webappps content" 9179ed315114 yh/tomcat:v2
    sha256:18e6806965319e6ad7860afaf8a7b3226b30aa433ade2c253a8b9744826d9bfe
    [root@muyi ~]# docker images
    REPOSITORY            TAG       IMAGE ID       CREATED         SIZE
    yh/tomcat             v2        18e680696531   6 seconds ago   673MB
    tomcat                9.0       710ec5c56683   3 days ago      668MB
    nginx                 latest    08b152afcfae   2 weeks ago     133MB
    mysql                 5.7       8cf625070931   2 weeks ago     448MB
    portainer/portainer   latest    580c0e4e98b0   4 months ago    79.1MB
    hello-world           latest    d1165f221234   5 months ago    13.3kB
    centos                latest    300e315adb2f   8 months ago    209MB
    elasticsearch         7.6.2     f29a1ee41030   16 months ago   791MB
    

到了这里常用的操作基本都会了,剩下的还有一些比较复杂的内容:

容器数据卷、DockersFile、Docker网络

容器数据卷

什么是容器数据卷

docker的理念将运行的环境打包形成容器运行,运行可以伴随容器,但是我们对数据的要求是希望持久化,容器之间可以共享数据,Docker容器产生的数据,如果不通过docker commit生成新的镜像,使得数据作为容器的一部分保存下来,那么当容器被删除之后,数据也就没了,为了能够保存数据,在docker容器中使用卷。卷就是目录或者文件,存在于一个或者多个容器中,但是不属于联合文件系统,因此能够绕过Union File System提供一些用于持久化数据或共享数据的特点

作用

卷的设计目的就是数据的持久化,完全独立与容器的生命周期,因此Docker不会在容器删除时删除其挂载的数据卷。
特点:
  1. 数据卷可以在容器之间共享和重用数据。
  2. 卷的更改可以直接生效。容器的配置就可以直接在主机中编写而不需要进入容器了。
  3. 数据卷的更改不会包含在镜像的更新中。
  4. 数据卷的生命周期一直持续到没有容器使用它为止。
容器的持久化
容器间继承+共享数据

使用

指定路径挂载

docker run -it -v /宿主机绝对路径目录:/容器内目录 镜像名

eg:

docker run -it -v /home/ceshi:/home centos /bin/bash

在/home/目录下新创建一个文件夹ceshi,然后与centos镜像新建的容器的/home目录双向绑定。一方修改后会立即同步,即使容器停止了,我们在主机中做了修改也会同步。

查看数据卷是否挂载成功。

docker inspect 容器ID,其中有Binds信息就成功了,

在这里插入图片描述

实战安装mysql5.7

查看数据卷用dockers volume ls

[root@muyi home]# docker volume ls
DRIVER    VOLUME NAME
local     97443f8a2f7d76036e354fa3efcc624ffa1cfa59748002cf1d0f8fc2bb329396

使用docker inspect VOLUME NAME 能够查看该卷挂载在哪里。

[root@muyi home]# docker inspect  97443f8a2f7d76036e354fa3efcc624ffa1cfa59748002cf1d0f8fc2bb329396 
[
    {
        "CreatedAt": "2021-08-10T20:04:38+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/97443f8a2f7d76036e354fa3efcc624ffa1cfa59748002cf1d0f8fc2bb329396/_data",
        "Name": "97443f8a2f7d76036e354fa3efcc624ffa1cfa59748002cf1d0f8fc2bb329396",
        "Options": null,
        "Scope": "local"
    }
]

默认路径挂载

匿名挂载

-v 容器内路径

docker run -d -P --name nginx01 -v /etc/nginx nginx

安装后通过 docker volume ls 查看所有数据卷的情况

具名挂载 (挂载时写上卷名与容器内路径)

docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx

docker volume ls时就会会先卷名

查看挂载目录

方式一:

通过docker inspect+容器名 nginx02,查看宿主机juming-nginx 的完整路径

方式二:

也可以 docker volume inspect +宿主机挂载路径 juming-nginx 就能直接看到完整路径

所有的docker容器内的卷,没有指定目录的情况下都是在/var/lib/docker/volume/xxx/_data

我们通过具名挂载可以方便的找到我们的一个卷,大多数情况都使用具名挂载

#如何确定是具名挂载还是匿名挂载,还是指定路径挂载
-v 容器内路径 #匿名挂载
-v 卷名:容器内路径 #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载

卷的权限

通过 -v 容器路径:ro rw 改变读写权限

ro #只读
rw #可读可写

docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx

只要看到ro 就说明这个路径智能通过宿主机来操作,容器 内部都是无法操作.(-P大写P表示的是匿名端口映射)

从容器上挂载,这样会更加方便 ,新创建的容器和之前的容器共享一个容器数据卷。

docker run -d -P --name nginx03 --volume-from nginx02 nginx

以上方式是在命令行中执行的,可以在dockerfile中写volume,这样就会直接创建了。

Dockerfile

可以在dockerhub中搜索一些镜像,然后点击其版本会跳转到github上对应的Dockerfile,可以参考他们的格式。

Docker Dockerfile | 菜鸟教程 (runoob.com)

构建镜像的方式有两种:一种是基于容器制作,另一种就是通过Dockerfile。

Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。

dockerfile命令

命令作用
FROM指令用于指定其后构建新镜像所使用的基础镜像。FROM 指令必是 Dockerfile 文件中的首条命令
RUN在镜像的构建过程中执行特定的命令,并生成一个中间镜像。
COPY将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的<目标路径>位置。
ADDADD 指令和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能。比如<源路径>可以是一个 URL,这种情况下,Docker 引擎会试图去下载这个链接的文件放到<目标路径>去。
ENV设置环境变量
EXPOSE为构建的镜像设置监听端口,使容器在运行时监听
VOLUMEOLUME用于创建挂载点,即向基于所构建镜像创始的容器添加卷:
WORKDIR通过WORKDIR设置工作目录后,Dockerfile 中其后的命令 RUN、CMD、ENTRYPOINT、ADD、COPY 等命令都会在该目录下执行。
USERUSER 用于指定运行镜像所使用的用户:可以使用用户名、UID 或 GID,或是两者的组合。
CMD用于指定在容器启动时所要执行的命令
ENTRYPOINTENTRYPOINT 用于给容器配置一个可执行程序。ENTRYPOINT 与 CMD 非常类似,不同的是通过docker run执行的命令不会覆盖 ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给 ENTRYPOINT。
LABELLABEL用于为镜像添加元数据,元数以键值对的形式指定:
ONBUILDONBUILD用于设置镜像触发器:当所构建的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被钥触发。

使用 Dockerfile 定制镜像

编写Dockerfile

在一个空目录下,新建一个名为 Dockerfile 文件,并在文件内添加以下内容:



From centos
MAINTAINER yh<515294355@qq.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 80

CMD echo $MYPATH
CMD echo "---end---"
CMD /bin/bash

LABEL version="version01"

RUN指令每次都会构建一个中间层镜像

开始构建镜像

docker build -f Dockerfile -t mycentos:0.1 .

其中-f指定dockerfile文件,如果dockerfile文件名就是Dockerfile ,那么可以省略-f Dockerfile。

-t是给构建的镜像设置tag。

. 代表本次执行的上下文路径,

之后我们就可以查看我们自己构建的镜像了。

[root@muyi dockerfile]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED         SIZE
mycentos              0.1       76af58bb2371   8 minutes ago   303MB

现在使用我们自己的镜像创建容器

docker run -it mycentos:0.1

查看镜像构建的步骤

docker history 镜像id

Docker网络连接原理:

在这里插入图片描述

只要安装docker,使用ip addr查看ip时就会看见docker0这个网卡。

docker守护进程就是通过docker0为docker容器提供网络连接的各种服务。docker0 就是Linux的虚拟网桥。网桥是OSI七层模型中的数据链路层的东西。

docker守护进程在一个容器启动时,实际上它要创建网络连接的两端。一端是在容器中的网络设备,而另一端是在运行docker守护进程的主机上打开一个名为veth*的一个接口,用来实现docker这个网桥与容器的网络通信。

在同一宿主机下,docker的容器是通过虚拟网桥来进行连接的。那么在默认情况下,在同一宿主机中运行的容器都是可以互相连接的

Docker 容器互联

第一部分学习的端口映射相当于是容器和外部环境互联,使得容器能被外部访问。

这部分要学习的是容器之间相互访问。

默认情况下,在同一宿主机中运行的容器都是可以互相连接的。但是要基于ip,如果想要基于容器名来ping通,则需要使用其它方式,最开始的方式是在创建容器时使用–link 容器1Id 给创建的这个容器连接 容器1,但是使用link方式的话,实际上就是创建这个容器的时候在其host文件中添加了对容器1的映射,如果ip地址一换就不行了。

随着 Docker 网络的完善,强烈建议大家将容器加入自定义的 Docker 网络来连接多个容器,而不是使用 --link 参数。

新建网络

下面先创建一个新的 Docker 网络。

$ docker network create -d bridge my-net

查看所有网络

docker network ls

在这里插入图片描述

这里面有个bridge名字的网络,该网络实际上就是docker01所在的网络,如果如果我们创建容器时不声明其所属网络,则默认会加到这个默认网络中。

新建容器连接到该网络

新建两个容器:tomcat01,tomcat02

docker run -itd  --name tomcat01 --network my-net  tomcat:9.0 /bin/bash
docker run -itd  --name tomcat02 --network my-net  tomcat:9.0 /bin/bash

进入tomcat01,然后ping tomcat02,检验是否连接成功

docker exec -it tomcat01 /bin/bash
ping tomcat02

在这里插入图片描述

发现ping成功。

这里我又新创建了tomcat03,tomcat04并加到该网络my-net中,然后使用docker network inspect my-net命令可以查看my-net中的所有容器网络信息:

在这里插入图片描述

发现他们都在一个网段内,ip地址从该网段内的2开始,因为1被分给网关了。

好处:

不同的集群创建不同的网络,保证容器间网络隔离。

如mysql集群一个网络,redis集群一个网络。

不同网络间联通

既然会为容器创建不同的网络,那么不同的网络间如何通信呢?

首先,由于不同网络内的容器属于不同的网段,不能直接相连

这里我创建一个新的容器tomcat05,不指定其network,这样就会加入到默认网络bridge中,和docker01一个网段内,它和tomcat01-04就属于不同网段,不能直接通信。

docker run -itd --name tomcat05 tomcat:9.0 /bin/bash

然后进入该容器,ping 容器tomcat02的ip :172.18.0.2,结果如下,证实不同network内的容器不能直连。

在这里插入图片描述

要想相连需要以下命令:

docker network connect [OPTIONS] NETWORK CONTAINER

实践:现在我们将tomcat05连接到my-net中,

docker network connect my-net tomcat05

然后再ping就发现ping通了,而且我们inspect tomcat05容器,会发现其network一栏中同时包括两个网络,相当于这个容器同时处于两个网络中。

在这里插入图片描述

Springboot项目打包Docker镜像

1.编写springboot项目

2.打包应用

maven里面的package打包,然后该目录下生成jar文件。

3.编写Dockerfile(根目录编写Dockerfile文件)

FROM java:8
COPY *.jar /app.jar
CMD ["--server.port=8080"]
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]

4.构建镜像()

然后将Dockerfile文件和jar包放在一个空目录下,执行

docker build . t my-image .

之后就创建了这个镜像。

5.发布运行

docker run -d - P --name my-web-app my-image

运行之后查看该容器的IP地址

docker ps

然后根据ip地址去访问。如果是容器所在主机访问就直接curl localhost:容器映射端口即可

所以学习docker之后,交付给别的项目可以就是一个镜像。

多个镜像如何处理?Docker Compose | 菜鸟教程 (runoob.com)](https://www.runoob.com/docker/docker-compose.html)

集权部署Swarm:Swarm 集群管理 | 菜鸟教程 (runoob.com)

参考

https://www.runoob.com/docker/docker-container-connection.html
https://www.bilibili.com/video/BV1og4y1q7M4?p=39

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值