DockerFile学习笔记

概念:DockerFile是用啦构建docker镜像的命令参数脚本;

基础知识:

1.DockerFile的每个关键字(指令)都必须是大写;
2.DockerFile文件从上倒下顺序执行;
3."#"表示注释;
4.每一条指令都会创建一个新的镜像层,并提交;

构建一个镜像的步骤:

1. 编写一个dockerfile文件;
2. docker build 命令构建命令使其成为一个镜像;
3. docker run 运行这个镜像;
4. docker push 发布镜像(阿里云镜像仓库、DockerHub);

指令:

docker指令.jpg
FROM                      # 基础镜像,一切从这里开始构建
MAINTAINER                # 维护者信息(姓名+邮箱)
RUN                       # 镜像构建时需要运行的命令
ADD                       # 一般是安装软件的压缩包,比如tomcat的压缩包,会自动解压;
WORKDIR                   # 镜像的工作目录
VOLUME                    # 挂载目录
EXPOSE                    # 保留端口配置
CMD                       # 指定这个容器启动的时候要执行的命令,只有最后一个生效,可被替换
ENTRYPOINT                # 指定这个容器启动的时候要执行的命令,可追加
ONBUILD                   # 当构建一个被继承DockerFile,这个时候就会运行ONBUILD命令,触发指令
COPY                      # 类似ADD,将我们的文件拷贝到镜像中
ENV                       # 设置环境变量

实战测试

可以发现dockerhub中99%的镜像都是继承自scratch,然后再增加需要的软件和配置来构建自己的镜像;


centos镜像构建文件

练习:构建一个自己的centos

1.编写dockerfile文件;

# mydockerfile_centos
FROM centos
MAINTAINER yongchao<[email protected]>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
EXPOSE 80
CMD echo $MYPATH
CMD echo ---end---
CMD /bin/bash

2.执行命令构建镜像

docker build -f ./mydockerfile_centos -t mycentos:0.1 .

# 参数解释:
# -f [--file] 是指定文件路径
# -t [--target] 是生成的镜像名:标签

最后出现这两行代码就代表成功了

Successfully built e00de874e7fe
Successfully tagged mycentos:0.1

3.测试生成的镜像


测试结果

可以看到构建的镜像已经有了vim命令,这说明我们的镜像确实构建成功了

docker history 镜像 命令

docker history命令来查看一个镜像的创建历史


创建历史

DockerFile指令详解

1.DockerFile中CMD和ENTRYPOINT指令的区别?

# 首先我们写一个dockerfile 叫dockerfile-cmd-test,文件中代码如下:
----------------------
FROM centos           |
CMD ["ls","-a"]       |
---------------------
# 然后执行 # docker build -f ./dockerfile-cmd-test -t cmdtest .
# 构建完这个镜像以后我们运行它 # docker run cmdtest
# 以下是返回结果:
[root@iZ9yfh528hy9yaZ mydockerfile]# docker run cmdtest
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
还有很多目录就不全列出来了
# 可以看到我们在运行这个镜像的时候自动执行了【ls -a】的指令
# 然后我们尝试运行这个镜像的时候在ls -a之后再追加一个-l参数
# 接下来执行 # docker run cmdtest -l
# 以下是返回结果:
[root@iZ9yfh528hy9yaZ mydockerfile]# docker run cmdtest -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.
# 可以看到报错了,这个 错误大概意思就是说执行-l报错了没有这个命令
# 造成这个结果的原因是使用cmd指令的情况下-l替换了ls -a 的指令,而-l不是命令
# 包括我们之前在构建文件中写了CMD ---end---后边还有CMD /bin/bash等多个CMD指令的时候,构建会从上倒下依次执行,但是在run这个镜像的时候,只有最后一条CMD命令执行了;

----------------------------------分割线-------------------------------------
# 以上是将CMD指令,接下来说说ENTRYPOINT指令
#还是老样子我们写一个dockerfile,叫dockerfile-cmd-entrypoint,代码如下:
--------------------------
FROM centos              |
ENTRYPOINT ["ls","-a"]   |
---------------------------
# 然后执行 # docker build -f ./dockerfile-cmd-entrypoint -t entrypoint-test .
# 构建完这个镜像以后我们运行它 # docker run entrypoint-test -l
# 以下是返回结果:
[root@iZ9yfh528hy9yaZ mydockerfile]# docker run entrypoint-test -l
total 0
drwxr-xr-x   1 root root   6 Sep  2 09:48 .
drwxr-xr-x   1 root root   6 Sep  2 09:48 ..
-rwxr-xr-x   1 root root   0 Sep  2 09:48 .dockerenv
lrwxrwxrwx   1 root root   7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x   5 root root 340 Sep  2 09:48 dev
drwxr-xr-x   1 root root  66 Sep  2 09:48 etc
drwxr-xr-x   2 root root   6 Nov  3  2020 home
lrwxrwxrwx   1 root root   7 Nov  3  2020 lib -> usr/lib
lrwxrwxrwx   1 root root   9 Nov  3  2020 lib64 -> usr/lib64
drwx------   2 root root   6 Dec  4  2020 lost+found
drwxr-xr-x   2 root root   6 Nov  3  2020 media
drwxr-xr-x   2 root root   6 Nov  3  2020 mnt
# 可以看到我们追加的指令"-l"成功执行了

我们可以发现dockerfile中很多指令都很相似,想要了解他们的区别,最好的办法就是去对比他们的测试效果;
2.RUN指令和CMD/ENTRYPOINT指令的区别:

RUN指令只在docker build 构建的时候运行,CMD/ENTRYPOINT命令在docker run启动容器的时候运行

实战:自建Tomcat镜像

  1. 首先我们要先下载好tomcat和jdk的压缩文件:


    压缩包.jpg
  2. 然后我们来写我们的dockerfile文件,官方命名:Dockerfile,如果编写的dockerfile文件叫这个名字的话,build 构建时会自动寻找这个文件,就不用-f指定了;
# 导入基础镜像
FROM centos
 # 标注作者信息
MAINTAINER ningyongchao<[email protected]>
# 从本地拷贝文件到镜像中
COPY readme.txt /usr/local/
# 添加本地软件压缩包到镜像中
ADD jdk-8u301-linux-aarch64.tar.gz /usr/local/ #
ADD apache-tomcat-10.0.10.tar.gz /usr/local/
# 安装vim软件
RUN yum -y install vim
# 定义自己的环境变量
ENV MYPATH /usr/local
# 定义工作目录
WORKDIR $MYPATH
# 定义JAVA的环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_301
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
# 定义tomcat的环境变量
ENV CATALINA_HOME /usr/local/apache-tomcat-10.0.10
ENV CATALINA_BASH /usr/local/apache-tomcat-10.0.10
# 把java和tomcat的环境变量添加到系统环境变量里
ENV PATH $PATH:$JAVA_HOME/BIN:$CATALINA_HOME/lib:$CATALINA_HOME/bin
# 暴露端口
EXPOSE 8080
# 运行linux系统命令&&表示多个命令的拼接,这里是启动tomcat并追踪日志
CMD /usr/local/apache-tomcat-10.0.10/bin/startup.sh && tail -f /usr/local/apache-tomcat-10.0.10/bin/logs/catalina.out
  1. 写好构建文件之后我们开始构建镜像,执行命令docker build -t diytomcat . 就可以构建我们自己的镜像了,我这里顺利构建完成了;
    4.构建完成之后我们要启动这个容器查看构建的是否有问题,执行命令:docker run -d --name mytomcat -p 9090:8080 -v /root/home/yongchao/build/tomcat/test:/usr/local/apache-tomcat-10.0.10/webapps/test -v /root/home/yongchao/build/tomcat/tomcatlogs:/usr/local/apache-tomcat-10.0.10/logs diytomcat


    顺利启动容器

    5.启动测试


    挂载的数据.jpg

    访问容器映射端口.jpg

    以上是查看宿主机上挂载的目录下的文件,和访问该主机映射端口,可以看到我们挂在目录下多除了tomcat的日志文件,访问主机名和端口号也能看到tomcat,这说明我们的镜像创建没有问题;
    6.部署项目

    我们在挂载的test目录下创建WEB-INF目录,然后把web.xml放入WEB-INF目录,然后在test目录下新建index.jsp文件,之后访问应该就能访问到自己写的页面;
    开发的步骤:一定要掌握dockerfile的编写,以后的项目都用docker镜像来发布运行;

发布自己的镜像

DockerHub

1.注册DockerHub账号:https://hub.docker.com/
2.在cmd界面登录自己的账号
这是登录的文档:

login.jpg

# cmd 输入命令
docker login -u xxxxx -p xxxxx
# 或者
docker login -u xxxxx # 回车
Password: xxxxxx
# 登陆成功最后会显示 Login Succeeded

3.要上传镜像到dockerhub需要给镜像加上账号id/镜像名:tag

docker tag <镜像ID> <账号ID>/<镜像名><:版本号>
  1. push镜像到自己的dockerhub仓库
docker push <账号id>/<镜像名称><:tag>
上传成功后最后一行会出现
sha256的一个密钥

发布到阿里云镜像服务上

1.登录阿里云(https://www.aliyun.com/)
2.找到容器镜像服务

容器镜像服务ACR

3.创建命名空间
命名空间创建好后

4.创建镜像仓库
创建镜像仓库

选择本地仓库

5.发布镜像到镜像仓库
这里就按照阿里云的官方文档就可以
这是官方文档截的图

注意:docker login 这里要输入密码的时候不是阿里云的密码,而是镜像服务的密码

如果不想发布到远程仓库,可以打成压缩包给别人别人解压:

# 打包成tar压缩包
docker save [目标目录] <镜像ID> [镜像ID...]
# 解压
docker load -i <镜像压缩包>

小结:

docker流程:


docker流程

Docker 网络

清空docker环境

理解Docker0

测试

image.png

问题:这里有三个网络docker是如何处理容器间网络访问的呢?
两个容器间互相访问

# 首先我们启动一个tomcat容器 docker  run -d  --name tomcat01 -P tomcat
# 然后我们看一下这个容器的内部地址 ip addr.发现容器启动的会后会得到一个eth0@if303这样的地址,这是docker给分配的
[root@iZ9yfh528hy9yaZ build]# docker exec 04ab39f56d16 ip addr
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
302: eth0@if303:  mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
# 思考:在宿主机上可以ping通这个地址吗?
[root@iZ9yfh528hy9yaZ build]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.050 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.062 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.043 ms

# 我们可以发现宿主机是可以ping通docker容器的ip的

原理:
我们每启动一个docker容器,docker就会给这个docker容器分配一个ip,我们只要安装了docker,就会有一个网卡docker0 桥接模式,使用的技术是evth-pair技术!

刚才我们在宿主机上执行命令ip addr有三个ip,现在我们再来执行一下看有没有变化

运行一个tomcat以后重新执行ip addr返回结果

可以发现我们宿主机执行ip addr之后多出来一个303: veth5d74427@if302的网卡这里303和后边302跟我们前边在容器内部执行ip addr看到的ip302: eth0@if303前后数字只是位置调换了一下
我们再启动一个容器看看,重新执行docker run -d --name tomcat02 -P tomcat 然后在宿主机执行ip addr
tomcat2

可以看到又多了一对网卡

我们发现这个网卡都是一对一对的;
veth-pair就是一对的虚拟设备接口,他们都是成对出现的,一端连着协议,一端连接着彼此;
正因为有这个特性,veth-pair充当着一个桥梁,连接各种虚拟网络设备
OpenStac,Docker容器之间的连接,OVS的连接,都是用的veth-pair的技术

现在我们试试两个容器间互相能不能ping通

# 首先看一下用容器2ping容器1

[root@iZ9yfh528hy9yaZ ~]# docker exec 6005f9aa70cf ping -c 3 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: icmp_seq=0 ttl=64 time=0.093 ms
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.074 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.073 ms
--- 172.17.0.2 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.073/0.080/0.093/0.000 ms

# 可以看到能够ping通,然后我们用容器1ping容器2

[root@iZ9yfh528hy9yaZ ~]# docker exec 04ab39f56d16 ping -c 3 172.17.0.3
PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: icmp_seq=0 ttl=64 time=0.072 ms
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.066 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.066 ms
--- 172.17.0.3 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.066/0.068/0.072/0.000 ms

# 依然能够ping通

结论:容器之间是可以互相ping通的

上传一个docker网络模型图
图片来自狂神学java的视频截图

结论:

tomcat01和tomcat02是共用一个"路由器",这个"路由器"也就是我们的docker0
所有容器在不指定网络的情况下,都是docker0分配的,docker0会给我们的容器分配一个默认的可用IP;
docker使用的是linux的桥接
图片来自狂神学java视频截图
docker中所有的网络接口都是虚拟的,虚拟的转发效率高(内网传递)
只要容器删除,对应的一对网桥也随之删除;
image.png

--link

思考一个场景:我们便写了一个微服务,database url=ip: ,项目不重启,数据库ip换掉了,我们希望处理这个问题,可以通过名字来访问容器,实现高可用;

#我们尝试了一下发现是ping不通的
[root@iZ9yfh528hy9yaZ ~]# docker exec 6005f9aa70cf ping tomcat01
ping: unknown host
# 怎么解决呢?
#我们使用--link来解决,首先我们再来启动一个tomcat03
[root@iZ9yfh528hy9yaZ ~]# docker run -d --name tomcat03 --link tomcat02 -P mytomcat:1.1
d84f1eb2e8cb01138e006cd449a891663287f1c1057b4a61fe5bd3a8c519ac4e

# 然后我们通过容器名来ping一下看看可不可以ping通
[root@iZ9yfh528hy9yaZ ~]# docker exec d84f1eb2e ping -c 3 tomcat02
PING tomcat02 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: icmp_seq=0 ttl=64 time=0.096 ms
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.072 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.066 ms
--- tomcat02 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.066/0.078/0.096/0.000 ms

#---------------------------分割线-----------------------------------------

[root@iZ9yfh528hy9yaZ ~]# docker exec 6005f9aa70cf ping -c 3 tomcat03
ping: unknown host
# 这里我们发现tomcat03中传入了--link tomcat02以后可以在tomcat03通过名字ping通tomcat02,但是tomcat02不能ping通tomcat03
探究--link到底做了什么?

我们执行docker exec tomcat03ID cat /etc/hosts查看返回结果

image.png

在这里我们就知道--linke原来是在hosts文件中配置了一条172.17.0.3 tomcat02 6005f9aa70cf,其他的没有执行--link的操作,所以host文件中没有这一条,自然也就ping不通了;
虽然可以这么实现但是现在项目开发过程中不推荐这样写,因为这种方法太笨了;

自定义网络

查看所有的docker网络


image.png

网络模式:
bridge: 桥接模式(默认,我们自己创建也用这个)
none: 不配置网络
host: 跟主机共享网络
container: 容器网络连通(局限性很大,不推荐!)

测试:

# 我们直接启动不写 --net 的话默认有一个 --net 参数,他的值就是bridge
docker run -d --name tomcat01 tomcat
docker run -d --name tomcat01 --net bridge tomcat
# 上边两个命令等价
# docker0特性:默认的;不可以使用域名访问,--link可以打通连接但是比较麻烦;
# 真实业务中我们一般都是自定义一个网络

# 创建网络命令是docker network create [options] 网络名称 
# 这里有几个参数要说一下
# --driver      网络模式
# --subnet    子网
# --geteway 网关
[root@iZ9yfh528hy9yaZ ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
# 我们家的路由器也差不多是这个配置
bf854f7584ba70d18cb80c95aaf48419a64751a74ea57a50840a7497d454a0a7
[root@iZ9yfh528hy9yaZ ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
d9adecfb67b8   bridge    bridge    local
158cf25085ee   host      host      local
bf854f7584ba   mynet     bridge    local
2dcb96737ce3   none      null      local

我们自己的网络就创建好了


# 启动一个tomcat-mynet-01使用我们自己新建的网络
[root@iZ9yfh528hy9yaZ ~]# docker run -d -P --name tomcat-mynet-01 --net mynet mytomcat:1.1
dc0e7305e8a4116bd6f1e79fcf7689c0a03cd9a45d134ad823dd73f2b83ddb96

# 再启动一个tomcat-mynet-02使用我们自己新建的网络
[root@iZ9yfh528hy9yaZ ~]# docker run -d -P --name tomcat-mynet-02 --net mynet mytomcat:1.1
d4d63cc7230249758588f0746732e03d76379caab9da185e601fa8159a9cf63d

# 然后我们再来看一下我们自己新建的网络中的信息
[root@iZ9yfh528hy9yaZ ~]# docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "bf854f7584ba70d18cb80c95aaf48419a64751a74ea57a50840a7497d454a0a7",
        "Created": "2021-09-18T15:30:45.336964997+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.0.0/16",
                    "Gateway": "192.168.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "d4d63cc7230249758588f0746732e03d76379caab9da185e601fa8159a9cf63d": {
                "Name": "tomcat-mynet-02",
                "EndpointID": "a1c8a255da9b198a02eca17b963d9822626f9076d7aab6d950f2bd906aab9616",
                "MacAddress": "02:42:c0:a8:00:03",
                "IPv4Address": "192.168.0.3/16",
                "IPv6Address": ""
            },
            "dc0e7305e8a4116bd6f1e79fcf7689c0a03cd9a45d134ad823dd73f2b83ddb96": {
                "Name": "tomcat-mynet-01",
                "EndpointID": "4c91d6c78e7ce961d162ead10e9bdfbd6711014ee1b0aaac5cbcbe632dfa6c2f",
                "MacAddress": "02:42:c0:a8:00:02",
                "IPv4Address": "192.168.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

# 这里Containers里边就能看到我们新启动的两个容器了;
# 然后我们看一下能不能通过容器名来互相ping通
[root@iZ9yfh528hy9yaZ ~]# docker ps
CONTAINER ID   IMAGE          COMMAND             CREATED         STATUS         PORTS                                         NAMES
d4d63cc72302   mytomcat:1.1   "catalina.sh run"   4 minutes ago   Up 4 minutes   0.0.0.0:49165->8080/tcp, :::49165->8080/tcp   tomcat-mynet-02
dc0e7305e8a4   mytomcat:1.1   "catalina.sh run"   4 minutes ago   Up 4 minutes   0.0.0.0:49164->8080/tcp, :::49164->8080/tcp   tomcat-mynet-01

[root@iZ9yfh528hy9yaZ ~]# docker exec d4d63cc72302 ping -c 2 tomcat-mynet-01
PING tomcat-mynet-01 (192.168.0.2): 56 data bytes
64 bytes from 192.168.0.2: icmp_seq=0 ttl=64 time=0.383 ms
64 bytes from 192.168.0.2: icmp_seq=1 ttl=64 time=0.072 ms
--- tomcat-mynet-01 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.072/0.228/0.383/0.156 ms

[root@iZ9yfh528hy9yaZ ~]# docker exec dc0e7305e8a4 ping -c 2 tomcat-mynet-02
PING tomcat-mynet-02 (192.168.0.3): 56 data bytes
64 bytes from 192.168.0.3: icmp_seq=0 ttl=64 time=0.061 ms
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.069 ms
--- tomcat-mynet-02 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.061/0.065/0.069/0.000 ms
# 可以看到这样就算不用--link也是完全可以互相通过容器名称ping通的

我们自定义的网络docker都已经帮我们维护好了对应关系,会方便很多,推荐平时开发的时候使用这样的方式

好处:
不同的集群可以创建不同的自定义网络;
互相之间是隔离的不会受到别的自定义网络的影响;
这样能够保证集群是安全和健康的;

网络连通

思考:在docker中我们有一个数据库集群放在一个网络里,我们的项目部署在另一个网络里,我们怎么使这个项目访问到这个数据库?
我们看一下docker network的帮助文档

[root@iZ9yfh528hy9yaZ ~]# docker network --help

Usage:  docker network COMMAND

Manage networks

Commands:
  connect     Connect a container to a network
  create      Create a network
  disconnect  Disconnect a container from a network
  inspect     Display detailed information on one or more networks
  ls          List networks
  prune       Remove all unused networks
  rm          Remove one or more networks

Run 'docker network COMMAND --help' for more information on a command.

这里我们看到有一个connect命令,这个命令能让一个容器访问一个网络,这个就是我们要学习的解决方式
我们来测试一下:

# 首先看一下这个命令怎么用
[root@iZ9yfh528hy9yaZ ~]# docker network connect --help

Usage:  docker network connect [OPTIONS] NETWORK CONTAINER

Connect a container to a network

Options:
      --alias strings           Add network-scoped alias for the container
      --driver-opt strings      driver options for the network
      --ip string               IPv4 address (e.g., 172.30.100.104)
      --ip6 string              IPv6 address (e.g., 2001:db8::33)
      --link list               Add link to another container
      --link-local-ip strings   Add a link-local address for the container
# 然后我们来启动一个不走mynet网络的容器
[root@iZ9yfh528hy9yaZ ~]# docker run -d -P --name tomcat01 mytomcat:1.1
e1f35c63d463fbf0bc0bb65d1122615c66febf175e1b1ef78dd4ce016b28844e

# 然后我们执行这个命令
[root@iZ9yfh528hy9yaZ ~]# docker network connect mynet tomcat01

# 然后我们看到没有报错,那应该就是可以了,我们试一下能不能互相ping通

#首先是tomcat01 ping tomcat-mynet-02
[root@iZ9yfh528hy9yaZ ~]# docker exec tomcat01 ping -c 2 tomcat-mynet-02
PING tomcat-mynet-02 (192.168.0.3): 56 data bytes
64 bytes from 192.168.0.3: icmp_seq=0 ttl=64 time=0.326 ms
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.070 ms
--- tomcat-mynet-02 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.070/0.198/0.326/0.128 ms

# 然后看一下tomcat-mynet-02能不能ping通tomcat01
[root@iZ9yfh528hy9yaZ ~]# docker exec tomcat-mynet-02 ping -c 2 tomcat01
PING tomcat01 (192.168.0.4): 56 data bytes
64 bytes from 192.168.0.4: icmp_seq=0 ttl=64 time=0.338 ms
64 bytes from 192.168.0.4: icmp_seq=1 ttl=64 time=0.069 ms
--- tomcat01 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.069/0.204/0.338/0.135 ms

# 可以看到互相都已经ping通了

虽然ping通了,但是原理是什么呢?我们看一下mynet的信息哪里发生了改变,执行命令docker network inspect mynet

# 这里我们可以看到Containers中多了一个tomcat01,
# 这样我们就理解了,docker是把这个容器放到了mynet的网络中;
# 这里我们可以理解为一个容器两个ip,
# 就像阿里云的服务器,有一个公网ip和一个私网ip

实战 部署Redis集群

image.png

首先创建一个redis的网络

docker network create --subnet 196.38.0.0/16 --gateway 196.38.0.1 redis

然后运行下面脚本批量配置我们的redis.conf

import os
for port in range(1,7):
    os.makedirs(f'/mydata/redis/node-{port}/conf')
    with open(f'/mydata/redis/node-{port}/conf/redis.conf','w',encoding='utf8') as f:
        f.write("port 6379"+'\n')
        f.write("bind 0.0.0.0"+'\n')
        f.write("cluster-enabled yes"+'\n')
        f.write("cluster-config-file nodes.conf"+'\n')
        f.write("cluster-node-timeout 5000"+'\n')
        f.write(f"cluster-announce-ip 196.38.0.1{port}"+'\n')
        f.write("cluster-announce-port 6379"+'\n')
        f.write("cluster-announce-bus-port 16379"+'\n')
        f.write("appendonly yes")

然后启动我们的脚本,用脚本启动:

import os
for port in range(1,7):
    response = os.system("docker run -d --name redis-{0} \
        -p 637{0}:6379 -p 1637{0}:16379 --net redis --ip 196.38.0.1{0} \
        -v /mydata/redis/node-{0}/conf/redis.conf:/etc/redis/redis.conf \
        -v /mydata/redis/node-{0}/data:/data \
        redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf".format(port))
    print(response)

启动之后我们进入我们的redis1容器启动集群

# 首先进入容器
docker exec -it redis-1 /bin/sh

#然后执行命令
/data # redis-cli --cluster create 196.38.0.11:6379 196.38.0.12:6379 196.38.0.13:6379 196.38.
0.14:6379 196.38.0.15:6379 196.38.0.16:6379 --cluster-replicas 1

# 以下是执行这个命令的输出
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 196.38.0.15:6379 to 196.38.0.11:6379
Adding replica 196.38.0.16:6379 to 196.38.0.12:6379
Adding replica 196.38.0.14:6379 to 196.38.0.13:6379
M: ed54210c8c09642e7ae2d50e940a56482c0be316 196.38.0.11:6379
   slots:[0-5460] (5461 slots) master
M: 588c765f07573addd98d00a7873a535a9b85f10b 196.38.0.12:6379
   slots:[5461-10922] (5462 slots) master
M: b7fe8958f8c267e14e2c5407e18a8c2efc5612cd 196.38.0.13:6379
   slots:[10923-16383] (5461 slots) master
S: f28379a5ccd541fe142a8213f4b5215c753500fe 196.38.0.14:6379
   replicates b7fe8958f8c267e14e2c5407e18a8c2efc5612cd
S: c4b498253de57cbe7fde942dbc0909b0435318de 196.38.0.15:6379
   replicates ed54210c8c09642e7ae2d50e940a56482c0be316
S: ae09c2bd1797ab7d6041f7e7c77dc512982b6d94 196.38.0.16:6379
   replicates 588c765f07573addd98d00a7873a535a9b85f10b
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
..
>>> Performing Cluster Check (using node 196.38.0.11:6379)
M: ed54210c8c09642e7ae2d50e940a56482c0be316 196.38.0.11:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: c4b498253de57cbe7fde942dbc0909b0435318de 196.38.0.15:6379
   slots: (0 slots) slave
   replicates ed54210c8c09642e7ae2d50e940a56482c0be316
S: ae09c2bd1797ab7d6041f7e7c77dc512982b6d94 196.38.0.16:6379
   slots: (0 slots) slave
   replicates 588c765f07573addd98d00a7873a535a9b85f10b
M: 588c765f07573addd98d00a7873a535a9b85f10b 196.38.0.12:6379
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
M: b7fe8958f8c267e14e2c5407e18a8c2efc5612cd 196.38.0.13:6379
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: f28379a5ccd541fe142a8213f4b5215c753500fe 196.38.0.14:6379
   slots: (0 slots) slave
   replicates b7fe8958f8c267e14e2c5407e18a8c2efc5612cd
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

从上边的输出我们可以看出我们的集群顺利启动了,然后我们来测试一下

# redis-cli -c是进入集群 不加-c是进入单个的redis
redis-cli -c
# 查看集群信息
127.0.0.1:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:922
cluster_stats_messages_pong_sent:923
cluster_stats_messages_sent:1845
cluster_stats_messages_ping_received:918
cluster_stats_messages_pong_received:922
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:1845

# 查看我们的节点 从结果可以看出4/5/6是从机,1/2/3是主机
127.0.0.1:6379> cluster nodes
c4b498253de57cbe7fde942dbc0909b0435318de 196.38.0.15:6379@16379 slave ed54210c8c09642e7ae2d50e940a56482c0be316 0 1632367729000 5 connected
ed54210c8c09642e7ae2d50e940a56482c0be316 196.38.0.11:6379@16379 myself,master - 0 1632367729000 1 connected 0-5460
ae09c2bd1797ab7d6041f7e7c77dc512982b6d94 196.38.0.16:6379@16379 slave 588c765f07573addd98d00a7873a535a9b85f10b 0 1632367729000 6 connected
588c765f07573addd98d00a7873a535a9b85f10b 196.38.0.12:6379@16379 master - 0 1632367730621 2 connected 5461-10922
b7fe8958f8c267e14e2c5407e18a8c2efc5612cd 196.38.0.13:6379@16379 master - 0 1632367730000 3 connected 10923-16383
f28379a5ccd541fe142a8213f4b5215c753500fe 196.38.0.14:6379@16379 slave b7fe8958f8c267e14e2c5407e18a8c2efc5612cd 0 1632367729000 4 connected

# 然后我们设置一个值,可以看到这个值在节点3上
127.0.0.1:6379> set a 1
-> Redirected to slot [15495] located at 196.38.0.13:6379
OK

# 然后我们打开一个新的窗口,把节点3停掉
[root@iZ9yfh528hy9yaZ ~]# docker stop redis-3
redis-3
# 回到集群重新连接一下
/data # redis-cli -c

# 然后我们取一下刚才设置的a,可以看到这个时候a是从节点4返回的
127.0.0.1:6379> get a
-> Redirected to slot [15495] located at 196.38.0.14:6379
"1"
# 我们看一下现在的节点信息,发现节点3故障了,然后节点4从从机变成了主机
196.38.0.14:6379> cluster nodes
588c765f07573addd98d00a7873a535a9b85f10b 196.38.0.12:6379@16379 master - 0 1632368175000 2 connected 5461-10922
c4b498253de57cbe7fde942dbc0909b0435318de 196.38.0.15:6379@16379 slave ed54210c8c09642e7ae2d50e940a56482c0be316 0 1632368175447 5 connected
ed54210c8c09642e7ae2d50e940a56482c0be316 196.38.0.11:6379@16379 master - 0 1632368174445 1 connected 0-5460
b7fe8958f8c267e14e2c5407e18a8c2efc5612cd 196.38.0.13:6379@16379 master,fail - 1632368129963 1632368127553 3 connected
ae09c2bd1797ab7d6041f7e7c77dc512982b6d94 196.38.0.16:6379@16379 slave 588c765f07573addd98d00a7873a535a9b85f10b 0 1632368174000 6 connected
f28379a5ccd541fe142a8213f4b5215c753500fe 196.38.0.14:6379@16379 myself,master - 0 1632368174000 7 connected 10923-16383

到这里docker基础就差不多学完了

你可能感兴趣的:(DockerFile学习笔记)