容器数据卷
我们考虑一个问题,当我们在使用 Docker 的时候,数据是存放在容器中的,如果我们把容器删除掉,那么数据就会丢失,这肯定是不科学的,在正常情况下,我们肯定得考虑做一下持久化,把数据存储到本地。又或者说,我们现在需要容器之间进行数据的共享,这个功能 Docker 可以实现嘛?答案自然是可以的,这其实就是卷技术,实现了目录的挂载,将我们容器内的目录,挂载到了 Linux 上面。
使用数据卷的格式如下:
docker run -it -v 主机目录:容器内目录 -p 主机端口:容器内端口
我们测试一下,将主机 home 目录下的 test 文件夹映射到 centos 容器中的 /home 下,这时两个文件夹就可以实现数据同步了。
docker run -it -v /home/test:/home centos /bin/bash
我们在 centos 容器中的 /home 下创建了一个 test.java 文件,然后发现这个文件已经被同步到了主机的 /home/test 目录下,证明我们的数据卷技术实现成功。
当我们把容器删除之后,可以发现挂载到本地的数据卷没有丢失,这就实现了容器数据持久化功能。
挂载方式
数据卷一共有三种挂载方式,分别为匿名挂载、具名挂载和指定路径挂载。
-v 容器内路径 #匿名挂载
-v 卷名:容器内路径 #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载
匿名挂载的实现:
[root@VM-0-4-centos test]# docker run -d --name test01 -v /home centos
查看一下所有卷的情况:
[root@VM-0-4-centos test]# docker volume ls
DRIVER VOLUME NAME
local 522ec66631d0f3f3808db304ca3808551da882eef8743845a72eb355f5b1ef37
显然,这是没有卷名的,也就是匿名挂载。
具名挂载的实现:
[root@VM-0-4-centos test]# docker run -d --name test02 -v vo:/home centos
我们再查看所有卷的情况,可以发现多了一个 vo 名字,这便是具名挂载。
Docker 容器内的卷,如果没有指定目录,都是存放在 /var/lib/docker/volumes/自定义的卷名/_data 下的。
Dockerfile
Dockerfile 是用来构建 docker 镜像的文件。我们可以通过下面这个脚本来生成镜像,由于镜像是一层一层的,而脚本的命令是一个一个的,所以其实每个命令都是镜像的一层。
我们先创建一个 dockerfile 文件,命名可以随意,不过一般推荐使用 Dockerfile。
[root@VM-0-4-centos /]# vim Dockerfile
脚本内容如下:
FROM centos # 当前这个镜像是以centos为基础的
VOLUME ["volume01","volume02"] # 挂载卷的卷目录列表(多个目录)
CMD echo "-----end-----" # 输出一下用于测试
CMD /bin/bash # 默认走bash控制台
然后我们通过脚本构建出镜像
[root@VM-0-4-centos test-docker]# docker build -f Dockerfile -t test/centos .
-f 可选项指当前文件的地址,-t 指目标目录,. 表示生成在当前目录下。
多个容器同步数据
如果我们想让多个容器之间同步数据,可以让容器挂载数据卷。
我们先创建一个 docker01 容器
[root@VM-0-4-centos ~]# docker run -it --name docker01 test/centos
查看一下文件
然后我们创建 docker02,并让其继承 docker01
[root@VM-0-4-centos ~]# docker run -it --name docker02 --volumes-from docker01 test/centos
然后我们查看一下其内容
然后我们在 docker02 容器的 /volume01 下创建一个文件
打开 docker01 容器的 /volume01 ,发现文件已被同步
如果我们删除 docker01 容器,数据依然存放在 docker02 中,并不会被删除。
DockerFile 构建过程
每个指令必须是大写字母,会从上往下顺序执行,每一条指令都会创建并提交一个新的镜像层。
常用的 DockerFile 指令如下:
FROM # from:基础镜像,一切从这里开始构建
MAINTAINER # maintainer:镜像是谁写的, 姓名+邮箱
RUN # run:镜像构建的时候需要运行的命令
ADD # add:步骤,tomcat镜像,这个tomcat压缩包!添加内容 添加同目录
WORKDIR # workdir:镜像的工作目录
VOLUME # volume:挂载的目录
EXPOSE # expose:保留端口配置
CMD # cmd:指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT # entrypoint:指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD # onbuild:当构建一个被继承DockerFile这个时候就会运行onbuild的指令,触发指令
COPY # copy:类似ADD,将我们文件拷贝到镜像中
ENV # env:构建的时候设置环境变量!
发布镜像
首先我们登录阿里云
[root@VM-0-4-centos ~]# docker login --username=geffin registry.cn-hangzhou.aliyuncs.com
然后将其发布
[root@VM-0-4-centos ~]# docker tag a3cb8117fbbe registry.cn-hangzhou.aliyuncs.com/docker-test-ling/docker-test:latest
[root@VM-0-4-centos ~]# docker push registry.cn-hangzhou.aliyuncs.com/docker-test-ling/docker-test:latest
Docker 网络
我们执行 ip addr 命令,可以发现有三个地址
可以看到有三个地址,其中第一个为本机回环地址,第二个为腾讯云内网地址,第三个为 Docker0 地址。
我们启动一个 tomcat
[root@VM-0-4-centos ~]# docker run -d -P --name tomcat01 tomcat
然后查看容器内部网络地址
[root@VM-0-4-centos ~]# docker exec -it 4d3543f98b9d ip addr
可以发现容器启动的时候会得到一个 eth0@if47 IP 地址,这是 docker 进行分配的。
其实,我们每启动一个 docker 容器,docker 就会给 docker 容器分配一个 ip,原理是 docker0 的桥接模式,使用的技术是 veth-pair 技术。
我们再启动一个容器测试,可以发现又多了一对网络,而且它们可以互相 ping 通,其网络模型图如下所示:
显然 tomcat01 和 tomcat02 共用一个路由器 docker0,当所有的容器不指定网络的情况下,都是 docker0 路由的,docker 会给我们的容器分配一个默认的可用 ip。
自定义网络
看起来 docker0 很优秀,但它也存在一些问题,例如它不支持容器名连接访问,所以我们需要自定义网络。
[root@VM-0-4-centos ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
然后我们启动两个 tomcat
[root@VM-0-4-centos ~]# docker run -d -P --name t01 --net mynet tomcat
c7a8e9ec4b727c0b1823a792b56c7b5586db516a64a5a48e34a952444e773949
[root@VM-0-4-centos ~]# docker run -d -P --name t02 --net mynet tomcat
54cd1bb02015078beee94fda0c62bc3d37cde415dda39323ba856b908916cb69
发现在自定义的网络下,服务之间可以互相 ping 通
自定义网络有什么好处呢?我们可以让不同的集群使用不同的网络,从而保证集群是安全和健康的。
网络连通
我们启动一个 tomcat ,使用默认网络 docker0
[root@VM-0-4-centos ~]# docker run -d -P --name t0033 tomcat
然后让新建的 tomcat 去 ping t01,发现 ping 不通。
[root@VM-0-4-centos ~]# docker exec t0033 ping t01
ping: t01: Name or service not known
其实,我们想让新建的 tomcat 连通 t01,需要将其加入 mynet 网络,其原理为一个容器使用两个 ip。
[root@VM-0-4-centos ~]# docker network connect mynet t0033
可以看到此时新建的 tomcat 是可以连通 t01 的,可见,如果我们要跨网络操作,就需要使用 docker network connect 进行连通。