Docker的精髓(容器数据卷、Dockerfile、Docker网络)

Docker的精髓(容器数据卷、Dockerfile、Docker网络)

容器数据卷

什么是容器数据卷

docker的理念 :

将应用和运行的环境打包形成容器运行,运行可以伴随着容器,但是我们对于数据的要求,是希望能够持久化的!
        就好比,你安装一个MySQL,结果你把容器删了,就相当于删库跑路了,这TM也太扯了吧!
        所以我们希望容器之间有可能可以共享数据,Docker容器产生的数据,如果不通过docker commit 生成新的镜像,使得数据作为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了!这样是行不通的!
        为了能保存数据在Docker中我们就可以使用卷!让数据挂载到我们本地!这样数据就不会因为容器删除 而丢失了!

作用:

卷就是目录或者文件,存在一个或者多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过 Union File System , 提供一些用于持续存储或共享数据的特性:卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷。
特点:
1、数据卷可在容器之间共享或重用数据
2、卷中的更改可以直接生效
3、数据卷中的更改不会包含在镜像的更新中
4、数据卷的生命周期一直持续到没有容器使用它为止
总结: 就是容器的持久化,以及容器间的继承和数据共享!

使用数据卷
方式一:容器中直接使用命令来添加

挂载

# 命令 
docker run -it -v 宿主机绝对路径目录:容器内目录 镜像名 
# 测试 
 docker run -it -v /home/ceshi:/home centos /bin/bash    #ceshi文件夹会自己生成不需要特意去创建

此时:容器内部的文件/home,和虚拟机上/home/ceshi就已经相关联了,我们可以测试一下。
在虚拟机的/home/ceshi创建一个LH.txt,看容器内部的/home中是否会生成这个文件

#在虚拟机上
[root@slaves2 ~]# cd /home/ceshi/
[root@slaves2 ceshi]# ll
总用量 0
[root@slaves2 ceshi]# touch LH.txt
#查看容器内部
[root@64760dd67074 /]# cd /home/
[root@64760dd67074 home]# ls
LH.txt

测试方式二:
查看数据卷是否挂载成功 docker inspect 容器id

#1、查看运行的容器
docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED         STATUS         PORTS     NAMES
64760dd67074   centos    "/bin/bash"   6 minutes ago   Up 6 minutes             determined_yonath
#2、查看容器的详细信息
docker inspect 647

www.zeeklog.com  - Docker的精髓(容器数据卷、Dockerfile、Docker网络)


扩展:容器停止运行后,数据也是一样能够同步过去的。
测试
1、你可以先将容器停止
2、修改虚拟机上的挂载目录
3、使用docker ps -a查看刚停止的容器
4、启动容器docker start 容器id
5.、进入容器docker exec -it 容器id /bin/bash(或者docker attach 容器ID)

总结:使用容器数据卷的好处,以后我们修改文件就直接可以在虚拟机上操作了,不需要进入容器内部了。

容器数据卷的实战案例

实战mysql数据的持久化问题

[root@slaves2 ~]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED         SIZE
tomcat                latest    feba8d001e3f   3 weeks ago     649MB
nginx                 latest    ae2feff98a0c   4 weeks ago     133MB
centos                latest    300e315adb2f   5 weeks ago     209MB
portainer/portainer   latest    62771b0b9b09   5 months ago    79.1MB
elasticsearch         7.6.2     f29a1ee41030   9 months ago    791MB
hello-world           latest    bf756fb1ae65   12 months ago   13.3kB
[root@slaves2 ~]# docker pull mysql:5.7
5.7: Pulling from library/mysql
a076a628af6f: Pull complete 
f6c208f3f991: Pull complete 
88a9455a9165: Pull complete 
406c9b8427c6: Pull complete 
7c88599c0b25: Pull complete 
25b5c6debdaf: Pull complete 
43a5816f1617: Pull complete 
7065aaa2655f: Pull complete 
b4bc531db40f: Pull complete 
8c3e9d7c9815: Pull complete 
fadfb9734ed2: Pull complete 
Digest: sha256:e08834258fcc0efd01df358222333919df53d4a0d9b2a54da05b204b822e3b7b
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7
[root@slaves2 ~]# systemctl status mysqld
Unit mysqld.service could not be found.
[root@slaves2 ~]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED         SIZE
mysql                 5.7       cc8775c0fe94   2 days ago      449MB
tomcat                latest    feba8d001e3f   3 weeks ago     649MB
nginx                 latest    ae2feff98a0c   4 weeks ago     133MB
centos                latest    300e315adb2f   5 weeks ago     209MB
portainer/portainer   latest    62771b0b9b09   5 months ago    79.1MB
elasticsearch         7.6.2     f29a1ee41030   9 months ago    791MB
hello-world           latest    bf756fb1ae65   12 months ago   13.3kB
[root@slaves2 ~]# docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql_kuangre mysql:5.7
f32f2fdaf1daa6bf561805cf2309a93adde27fa058bad57a96c284d6c87d5f18
#参数讲解
#-d 后台运行
#-p 端口映射
#-v 数据卷配置
#-e 环境配置
--name 容器名字

此时怎么就可以使用mysql连接工具去连接mysql了

www.zeeklog.com  - Docker的精髓(容器数据卷、Dockerfile、Docker网络)


启动成功之后,我们在本地使用sqlyog来测试一下
sqlyog-连接到服务器的 3310— 3310和容器内的3306映射,这个时候我们就可以连接上!
测试
1、接下来我创建一个数据库,看linux虚拟机的/home/mysql/data数据库存储路径中是否会生成新创建的数据库。

www.zeeklog.com  - Docker的精髓(容器数据卷、Dockerfile、Docker网络)


2、我们在把mysql容器个删除了,看数据是否还能够保存。

www.zeeklog.com  - Docker的精髓(容器数据卷、Dockerfile、Docker网络)


总结:使用数据卷后,就是容器删除了,数据可以仍然保存,这就是实现了容器的数据持久化。

DockerFile

DockerFile介绍

DockerFile 是用来构建Docker镜像的构建文件,是由一些列命令和参数构成的脚本。
我们在这里,先体验下,后面我们会详细讲解 DockerFile !
构建步骤:
1.编写一个dockerfile 文件
2、docker build 构建成为一个镜像
3、docker run 运行镜像
4、docker push 发布镜像(DockerHub、阿里云镜像仓库!)
查看官网是怎么操作的
1、进入Docker Hub

www.zeeklog.com  - Docker的精髓(容器数据卷、Dockerfile、Docker网络)


2、拿centos为例子

www.zeeklog.com  - Docker的精髓(容器数据卷、Dockerfile、Docker网络)


3、选着对应的版本进去,就可以看到对应的Docker File

www.zeeklog.com  - Docker的精髓(容器数据卷、Dockerfile、Docker网络)


www.zeeklog.com  - Docker的精髓(容器数据卷、Dockerfile、Docker网络)


Docker File文件参数讲解

FROM scratch    #从最低成的镜像开始,百分九十都是从这个最低成镜像开始
ADD centos-7-x86_64-docker.tar.xz /    #添加了一个centos7

LABEL \                   #添加一些centos的基本标签
    org.label-schema.schema-version="1.0" \
    org.label-schema.name="CentOS Base Image" \
    org.label-schema.vendor="CentOS" \
    org.label-schema.license="GPLv2" \
    org.label-schema.build-date="20201113" \
    org.opencontainers.image.title="CentOS Base Image" \
    org.opencontainers.image.vendor="CentOS" \
    org.opencontainers.image.licenses="GPL-2.0-only" \
    org.opencontainers.image.created="2020-11-13 00:00:00+00:00"

CMD ["/bin/bash"]  #使用/bin/bas去运行这个容器

很多官网的镜像都是基础包,很多功能都没有,通常需要我们搭建自己的镜像!

DockerFile构建过程

基础知识
1、每个保留关键字(指令)都必须是大写字母
2.、执行从上到下
3、# 这个表示注释
4、每一个指令都会创建一个新的镜像层,并提交!

www.zeeklog.com  - Docker的精髓(容器数据卷、Dockerfile、Docker网络)


Dockerfile是面向开发,我们以后要发布项目,做进行,就需要Dockerfile文件,这个文件时分简单!
DockerFile:它就是构建文件,定义了步骤,好比喻源代码的样子!
Dockerimages:是通过DockerFile构建生成的镜像,最终发布和运行的产品
Docker容器:容器就是镜像运行起来提供服务

Docker File指令

# from 基础镜像,一切从这里开始构建
# maintainer  镜像是谁写的,通常会有你的姓名加邮箱
# run  镜像构建的时候需要运行的命令
# add  添加其余的镜像层
# workdir  镜像的工作目录
# volume  挂载的目录
# expose  暴露端口和 -p一个意思
# cmd 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可呗替代
# entrypoint 指定这个容器启动的时候要运行的命令,可以追加
# onbuild  当构建一个被继承 DockerFile 这个时候就会运行onbuild的命令。出发命令
# copy  类似于add ,将我们文件拷贝到镜像中
# env   构建的时候设置环境变量
www.zeeklog.com  - Docker的精髓(容器数据卷、Dockerfile、Docker网络)

DockerFile的实战案例

Docker Hub中百分之99%的镜像都是从FROM scratch开始的,然后配置咋们需要的软件来进行构建

www.zeeklog.com  - Docker的精髓(容器数据卷、Dockerfile、Docker网络)


创建一个自己的centos

1、创建一个属于自己的目录
[root@slaves2 home]# mkdir /home/DockerFile
[root@slaves2 home]# cd DockerFile/

2、编写DockerFile文件
[root@slaves2 DockerFile]# vim mydockerfile
#从最基础镜像开始
FROM centos
#这个镜像是kuangre写的
MAINTAINER kuangre<[email protected]>
#进入之后的目录在哪
ENV MYPATH /usr/local
#工作目录在哪
WORKDIR $MYPATH
#运行安装相应的依赖
RUN yum -y install vim
RUN yum -y install net-tools
#暴露80端口
EXPOSE 80
#打印输出
CMD echo $MYPATH
CMD echo "---end-----"
#启动之后需要进入的命令行
CMD /bin/bash

3、通过文件创建镜像
[root@slaves2 DockerFile]# docker build -f mydockerfile  -t mycentos:5.7 .
Successfully built d93a6adb466b
Successfully tagged mycentos:5.7

4、测试运行
[root@slaves2 DockerFile]# docker run -it mycentos:5.7
[root@d9d56672d89f local]# pwd
/usr/local
#发现现在容器内部已经可以使用ifconfig了
[root@d9d56672d89f local]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 8  bytes 656 (656.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

对比原来的centos,现在多了vim、ifconfig命令
扩展:docker history 镜像id

#便可以知道这个镜像是如何一步一步做起来的
[root@slaves2 DockerFile]# docker history d93a6adb466b
IMAGE          CREATED             CREATED BY                                      SIZE      COMMENT
d93a6adb466b   About an hour ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "/bin…   0B        
7b3c8e76df9c   About an hour ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B        
024ff2518b73   About an hour ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B        
d60498f5d87f   About an hour ago   /bin/sh -c #(nop)  EXPOSE 80                    0B        
64d2306fe153   About an hour ago   /bin/sh -c yum -y install net-tools             23.4MB    
7aacd8238732   About an hour ago   /bin/sh -c yum -y install vim                   58.1MB    
a92078845896   2 hours ago         /bin/sh -c #(nop) WORKDIR /usr/local            0B        
7c43647373d2   2 hours ago         /bin/sh -c #(nop)  ENV MYPATH=/usr/local        0B        
e7a8bf262bbb   2 hours ago         /bin/sh -c #(nop)  MAINTAINER kuangre<lh1457…   0B        
300e315adb2f   5 weeks ago         /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B        
<missing>      5 weeks ago         /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B        
<missing>      5 weeks ago         /bin/sh -c #(nop) ADD file:bd7a2aed6ede423b7…   209MB  

CMD和ENTRYPOINNT的区别

我们这里直接代码来展现它之间的区别

测试CMD

[root@slaves2 DockerFile]# vim dockerfile_cmd_test
FROM centos
CMD ["ls","-a"]

[root@slaves2 DockerFile]# docker build -f dockerfile_cmd_test -t cmd_test:1.0
"docker build" requires exactly 1 argument.
See 'docker build --help'.

Usage:  docker build [OPTIONS] PATH | URL | -

Build an image from a Dockerfile
#构建镜像
[root@slaves2 DockerFile]# docker build -f dockerfile_cmd_test -t cmd_test:1.0 .
Sending build context to Docker daemon  3.072kB
Step 1/2 : FROM centos
 ---> 300e315adb2f
Step 2/2 : CMD ["ls","-a"]
 ---> Running in 7b99c98d936c
Removing intermediate container 7b99c98d936c
 ---> a8f8644acaa3
Successfully built a8f8644acaa3
Successfully tagged cmd_test:1.0
[root@slaves2 DockerFile]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED          SIZE
cmd_test              1.0       a8f8644acaa3   19 seconds ago   209MB
#通过run运行
[root@slaves2 DockerFile]# docker run -it cmd_test:1.0
启动后去执行了ls -a
.   .dockerenv	dev  home  lib64       media  opt   root  sbin	sys  usr
..  bin		etc  lib   lost+found  mnt    proc  run   srv	tmp  var


#此时我们追加一个- l
[root@slaves2 DockerFile]# docker run a8f8644acaa3 -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:370: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.
#这是因为使用CMD需要使用完全的路径
[root@slaves2 DockerFile]# docker run a8f8644acaa3  ls  -al
total 0
drwxr-xr-x   1 root root   6 Jan 16 09:57 .
drwxr-xr-x   1 root root   6 Jan 16 09:57 ..
-rwxr-xr-x   1 root root   0 Jan 16 09:57 .dockerenv
lrwxrwxrwx   1 root root   7 Nov  3 15:22 bin -> usr/bin
drwxr-xr-x   5 root root 340 Jan 16 09:57 dev

测试完后发现它需要添加全部的指令才能执行,不直接去进行追加

测试ENTRYPOINT

[root@slaves2 DockerFile]# vim dockerfile_entrypoint__test
FROM centos
ENTRYPOINT  ["ls","-a"]

[root@slaves2 DockerFile]# docker build -f dockerfile_entrypoint__test  -t entrypoint_test:1.0 .
Successfully built 085015516401
Successfully tagged entrypoint_test:1.0

[root@slaves2 DockerFile]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED          SIZE
entrypoint_test       1.0       085015516401   18 seconds ago   209MB
cmd_test              1.0       a8f8644acaa3   13 minutes ago   209MB
mycentos              5.7       d93a6adb466b   2 hours ago      291MB
<none>                <none>    6d251b9333eb   2 hours ago      0B
mysql                 5.7       cc8775c0fe94   4 days ago       449MB
tomcat                latest    feba8d001e3f   4 weeks ago      649MB
nginx                 latest    ae2feff98a0c   4 weeks ago      133MB
centos                latest    300e315adb2f   5 weeks ago      209MB
portainer/portainer   latest    62771b0b9b09   5 months ago     79.1MB
elasticsearch         7.6.2     f29a1ee41030   9 months ago     791MB
hello-world           latest    bf756fb1ae65   12 months ago    13.3kB
[root@slaves2 DockerFile]# docker run -it 085015516401
.   .dockerenv	dev  home  lib64       media  opt   root  sbin	sys  usr
..  bin		etc  lib   lost+found  mnt    proc  run   srv	tmp  var
[root@slaves2 DockerFile]# docker run -it 085015516401 -l
total 0
drwxr-xr-x   1 root root   6 Jan 16 10:04 .
drwxr-xr-x   1 root root   6 Jan 16 10:04 ..
-rwxr-xr-x   1 root root   0 Jan 16 10:04 .dockerenv
lrwxrwxrwx   1 root root   7 Nov  3 15:22 bin -> usr/bin
drwxr-xr-x   5 root root 360 Jan 16 10:04 dev
drwxr-xr-x   1 root root  66 Jan 16 10:04 etc

可以发现entrypoint可以直接进行命令的追加,不需要去写全命令了

实战测试tomcat(制作一个竟然然后自己在进行发布)

1、创建Dockerfile文件
mkdir /home/Dockerfile

2、cd进入文件夹自定义Dockerfile
[root@slaves2 Dockerfile]# vim Dockerfile
FROM centos
MAINTAINER kuangren
#把宿主机当前上下文的read.txt拷贝到容器/usr/local/路径下 
COPY read.txt /usr/local/cincontainer.txt
#把java与tomcat添加到容器中
ADD jdk-8u261-linux-x64.tar.gz  /usr/local/
ADD apache-tomcat-8.5.9.zip  /usr/local/   
#安装vim编辑器 
RUN yum -y install vim
#设置工作访问时候的WORKDIR路径,登录落脚点 
ENV MYPATH /usr/local WORKDIR
WORKDIR $MYPATH
#配置java与tomcat环境变量 
ENV JAVA_HOME /usr/local/jdk1.8.0_261
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-8.5.9
ENV CATALINA_BASE /usr/local/apache-tomcat-8.5.9 
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#容器运行时监听的端口 
EXPOSE 8080
#启动时运行tomcat 
# ENTRYPOINT ["/usr/local/apache-tomcat-8.5.9/bin/startup.sh" ] 
# CMD ["/usr/local/apache-tomcat-8.5.9/bin/catalina.sh","run"] 
CMD /usr/local/apache-tomcat-8.5.9/bin/startup.sh && tail -F /usr/local/apache-tomcat-8.5.9/bin/logs/catalina.out
[root@slaves2 Dockerfile]# touch read.txt

3、构建镜像
#在自己的Dockerfile文件夹中构建自己的镜像
[root@slaves2 Dockerfile]# docker build -t mykuangren_tomcat .
#查看自己构建的镜像
[root@slaves2 Dockerfile]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED         SIZE
mykuangren_tomcat     latest    455121727328   6 seconds ago   630MB

4、运行启动
[root@slaves2 Dockerfile]# docker run -d -p 9090:8080 --name kuangrenromcat -v /home/kuangren/tomcat/test:/usr/local/apache-tomcat-8.5.9/webapps/test -v /home/kuangren/tomcat/tomcat8logs:/usr/local/apache-tomcat-8.5.9/logs --privileged=true mykuangren_tomcat
b1e79423c63c8ef1bba3f6c8284976b955bfdbdaa5511be898abcb12ea1e5852

5、测试访问
curl localhost:9090

6、结合前面学习的容器卷将测试的web服务test发布
cd  /home/kuangren/tomcat/test
mkdir WEB-INF
cd WEB-INF
vim web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>test</display-name> </web-app>

vim  a.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>hello,kuangshen</title> </head> <body> -----------welcome------------ <%=" my docker tomcat,kuangshen666 "%> <br> <br> <% System.out.println("-------my docker tomcat-------");%> </body> </html> 12345678

测试
www.zeeklog.com  - Docker的精髓(容器数据卷、Dockerfile、Docker网络)
# 查看日志
 [root@ tomcat]# cd tomcat9logs/ 
 [root@ tomcat9logs]# ll 
 total 24 -rw-r----- 1 root root 6993 May 12 12:50 catalina.2020-05-12.log 
 [root@ tomcat9logs]# cat catalina.out .... -------my docker tomcat------- # 搞定

发布镜像

首先:注册dockerhub https://hub.docker.com/signup,需要有一个账号

# 1、查看登录命令
[root@ tomcat]#docker login --help
# 2、登录
[root@ tomcat]#docker login -u kuangshen
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials- store 
Login Succeeded
# 3、将镜像发布出去
[root@ tomcat]# docker push kuangshen/diytomcat:1.0
0f02399c6fdf: Preparing e79ea0c3a34e: Preparing
# 拒绝:请求的资源访问被拒绝 
denied: requested access to the resource is denied
# 问题:本地镜像名无帐号信息,解决加 tag即可
docker tag 251ca4419332 仓库名/diytomcat:1.0

# 再次 push, ok

[root@ tomcat]# docker push kuangshen/diytomcat:1.0 The push refers to repository [docker.io/kuangshen/diytomcat] 0f02399c6fdf: Pushing [========> ]

Docker 网络讲解

理解Docker0
准备工作:清空所有的容器,清空所有的镜像

docker rm -f $(docker ps -a -q) # 删除所有容器 
docker rmi -f $(docker images -qa) # 删除全部镜像

我们先来做个测试

1、查看本地ip

[root@slaves2 Dockerfile]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> 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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:05:dc:1f brd ff:ff:ff:ff:ff:ff
    inet 192.168.100.23/24 brd 192.168.100.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::c430:edec:23cf:3a7a/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
    inet6 fe80::a706:851c:ac8d:e0c/64 scope link tentative noprefixroute dadfailed 
       valid_lft forever preferred_lft forever
    inet6 fe80::4522:17f2:ee54:eabe/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:5b:b5:33:a3 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:5bff:feb5:33a3/64 scope link 
       valid_lft forever preferred_lft forever

这里我们分析可得,有三个网络:

lo 127.0.0.1 # 本机回环地址 
eth0 172.17.90.138 # 阿里云的私有IP 
docker0 172.18.0.1 # docker网桥 # 
问题:Docker 是如何处理容器网络访问的?

我们之前安装ES的时候,留过一个问题,就是安装Kibana的问题,Kibana得指定ES的地址!或者我们实际场景中,我们开发了很多微服务项目,那些微服务项目都要连接数据库,需要指定数据库的url地
址,通过ip。但是我们用Docker管理的话,假设数据库出问题了,我们重新启动运行一个,这个时候数据库的地址就会发生变化,docker会给每个容器都分配一个ip,且容器和容器之间是可以互相访问的。我们可以测试下容器之间能不能ping通过:

# 启动tomcat01
[root@slaves2 Dockerfile]# docker run -d -P --name tomcat01 tomcat
 # 查看tomcat01的ip地址,docker会给每个容器都分配一个ip
[root@slaves2 Dockerfile]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> 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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:05:dc:1f brd ff:ff:ff:ff:ff:ff
    inet 192.168.100.23/24 brd 192.168.100.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::c430:edec:23cf:3a7a/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
    inet6 fe80::a706:851c:ac8d:e0c/64 scope link tentative noprefixroute dadfailed 
       valid_lft forever preferred_lft forever
    inet6 fe80::4522:17f2:ee54:eabe/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:5b:b5:33:a3 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:5bff:feb5:33a3/64 scope link 
       valid_lft forever preferred_lft forever
109: veth0777c28@if108: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether de:a9:7f:60:98:33 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::dca9:7fff:fe60:9833/64 scope link 
       valid_lft forever preferred_lft forever


测试,我们的linux服务器能否ping通容器内的tomcat

[root@~]# ping 172.18.0.2 
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data. 64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.070 ms 
# 可以ping通

原理
1、每一个安装了Docker的linux主机都有一个docker0的虚拟网卡。这是个桥接网卡,使用了veth-pair技术!

[root@slaves2 Dockerfile]# docker run -d -P --name tomcat02 tomcat
#默认为桥接模式:
[root@slaves2 Dockerfile]# docker run -d -P --name tomcat02 --net bridge tomcat

刚启动了一个服务,我们在查看一下ip adrr

[root@slaves2 Dockerfile]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> 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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:05:dc:1f brd ff:ff:ff:ff:ff:ff
    inet 192.168.100.23/24 brd 192.168.100.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::c430:edec:23cf:3a7a/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
    inet6 fe80::a706:851c:ac8d:e0c/64 scope link tentative noprefixroute dadfailed 
       valid_lft forever preferred_lft forever
    inet6 fe80::4522:17f2:ee54:eabe/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:5b:b5:33:a3 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:5bff:feb5:33a3/64 scope link 
       valid_lft forever preferred_lft forever
109: veth0777c28@if108: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether de:a9:7f:60:98:33 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::dca9:7fff:fe60:9833/64 scope link 
       valid_lft forever preferred_lft forever
111: veth484d751@if110: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 96:6b:6e:2a:78:2e brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::946b:6eff:fe2a:782e/64 scope link 
       valid_lft forever preferred_lft forever

发现:本来我们有三个网络,我们在启动了个tomcat容器之后,多了一个!123的网络!
2、每启动一个容器,linux主机就会多了一个虚拟网卡。

# 我们启动了一个tomcat01,主机的ip地址多了一个 123: vethc8584ea@if122
# 然后我们在tomcat01容器中查看容器的ip是 122: eth0@if123

# 我们再启动一个tomcat02观察
[root@~]# docker run -d -P --name tomcat02 tomcat
# 然后发现linux主机上又多了一个网卡 125: veth021eeea@if124:
# 我们看下tomcat02的容器内ip地址是 124: eth0@if125:
[root@~]# docker exec -it tomcat02 ip addr
# 观察现象: 
# tomcat --- linux主机 vethc8584ea@if122 ---- 容器内 eth0@if123 
# tomcat --- linux主机 veth021eeea@if124 ---- 容器内 eth0@if125 
# 相信到了这里,大家应该能看出点小猫腻了吧!只要启动一个容器,就有一对网卡
# veth-pair 就是一对的虚拟设备接口,它都是成对出现的。一端连着协议栈,一端彼此相连着。
# 正因为有这个特性,它常常充当着一个桥梁,连接着各种虚拟网络设备!
# “Bridge、OVS 之间的连接”,“Docker 容器之间的连接” 等等,以此构建出非常复杂的虚拟网络 结构,比如 OpenStack Neutron。

3、我们来测试下tomcat01和tomcat02容器间是否可以互相ping通

[root@~]# docker exec -it tomcat02 ping 172.18.0.2 
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data. 64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.110 ms
 # 结论:容器和容器之间是可以互相访问的。

4、我们来画一个网络模

www.zeeklog.com  - Docker的精髓(容器数据卷、Dockerfile、Docker网络)


结论:tomcat1和tomcat2共用一个路由器。是的,他们使用的一个,就是docker0。任何一个容器启动默认都是docker0网络。
docker默认会给容器分配一个可用ip。
小结
Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。

www.zeeklog.com  - Docker的精髓(容器数据卷、Dockerfile、Docker网络)


Docker容器网络就很好的利用了Linux虚拟网络技术,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);
Docker中的网络接口默认都是虚拟的接口。虚拟接口的优势就是转发效率极高(因为Linux是在内核中进行数据的复制来实现虚拟接口之间的数据转发,无需通过外部的网络设备交换),对于本地系统和容器系统来说,虚拟接口跟一个正常的以太网卡相比并没有区别,只是他的速度快很多。

思考一个场景,我们编写一个微服务,数据库连接地址原来是使用ip的,如果ip变化就不行了,那我们能不能使用服务名访问呢?
jdbc:mysql://mysql:3306,这样的话哪怕mysql重启,我们也不需要修改配置了!docker提供了 --link的操作!

# 我们使用tomcat02,直接通过容器名ping tomcat01,不使用ip
[root@slaves2 Dockerfile]# docker exec -it tomcat01 ping tomcat02
ping: tomcat02: Name or service not known
# 我们再启动一个tomcat03,但是启动的时候连接tomcat02
[root@slaves2 Dockerfile]# docker run -d -P --name tomcat03 --link tomcat02 tomcat

# 这个时候,我们就可以使用tomcat03 ping通tomcat02 了
[root@slaves2 Dockerfile]# docker exec -it tomcat03 ping tomcat02 PING tomcat02 (172.18.0.3) 56(84) bytes of data. 64 bytes from tomcat02 (172.18.0.3): icmp_seq=1 ttl=64 time=0.093 ms

# 再来测试,tomcat03 是否可以ping tomcat01 失败 
[root@slaves2 Dockerfile]#  docker exec -it tomcat03 ping tomcat01 
ping: tomcat01: Name or service not known

# 再来测试,tomcat02 是否可以ping tomcat03 反向也ping不通
[root@slaves2 Dockerfile]#docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known

这个原理是什么呢?我们进入tomcat03中查看下host配置文件

[root@slaves2 Dockerfile]# docker exec -it tomcat03 cat /etc/hosts
 172.18.0.3 tomcat02 b80da266a3ad # 发现tomcat2直接被写在这里 
 172.18.0.4 a3a4a17a2b70

所以这里其实就是配置了一个 hosts 地址而已!
原因:–link的时候,直接把需要link的主机的域名和ip直接配置到了hosts文件中了。
link早都过时了,我们不推荐使用!我们可以使用自定义网络的方式

自定义网络

基本命令查看

[root@slaves2 Dockerfile]# 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.

查看所有网络

[root@slaves2 Dockerfile]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
4964fce76cae   bridge    bridge    local
00675ff91463   host      host      local
7ce903856463   none      null      local

所有网路模式

www.zeeklog.com  - Docker的精髓(容器数据卷、Dockerfile、Docker网络)


测试

#1、创建一个网卡
[root@slaves2 Dockerfile]# docker run -d -P --name tomcat01 --net bridge tomcat
# docker0网络的特点 1.它是默认的 2.域名访问不通 3.--link 域名通了,但是删了又不行
#2、创建一个桥接网络
[root@slaves2 Dockerfile]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
404d8de5cf0225c1e134a0588bcbdf088847c6486780183163f3b5fd3e803abf
#3、查看创建网络的基本信息
[root@slaves2 Dockerfile]#  docker network inspect 4eb2182ac4b2
[root@slaves2 Dockerfile]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
4964fce76cae   bridge    bridge    local
00675ff91463   host      host      local
404d8de5cf02   mynet     bridge    local
7ce903856463   none      null      local

docker network inspect mynet

www.zeeklog.com  - Docker的精髓(容器数据卷、Dockerfile、Docker网络)


#4.这时候我们启动的时候就可以直接指使用mynet刚刚创建的网络启动了

www.zeeklog.com  - Docker的精髓(容器数据卷、Dockerfile、Docker网络)


然后在去查看网络的详细信息的时候就可以看刚刚启动服务的了

www.zeeklog.com  - Docker的精髓(容器数据卷、Dockerfile、Docker网络)


#5、使用主机名平主机名,这时候不适用link

www.zeeklog.com  - Docker的精髓(容器数据卷、Dockerfile、Docker网络)


发现,我们自定义的网络docker都已经帮我们维护好了对应的关系
所以我们平时都可以这样使用网络,不使用–link效果一样,所有东西实时维护好,直接域名 ping 通。

网络连通

www.zeeklog.com  - Docker的精髓(容器数据卷、Dockerfile、Docker网络)


docker0和自定义网络肯定不通,我们使用自定义网络的好处就是网络隔离:
大家公司项目部署的业务都非常多,假设我们有一个商城,我们会有订单业务(操作不同数据),会有订单业务购物车业务(操作不同缓存)。如果在一个网络下,有的程序猿的恶意代码就不能防止了,所以我们就在部署的时候网络隔离,创建两个桥接网卡,比如订单业务(里面的数据库,redis,mq,全部业务 都在order-net网络下)其他业务在其他网络。
那关键的问题来了,如何让 tomcat-net-01 访问 tomcat1?

# 启动默认的容器,在docker0网络下 
[root@slaves2 Dockerfile]]# docker run -d -P --name tomcat01 tomcat bcd122e0dcf6bf8c861eaa934911f98a5497a4954f3fde9575e496160bd23287 
[root@slaves2 Dockerfile]# docker run -d -P --name tomcat02 tomcat 6183aaeca003a3e5a3549a37f9c1040551320ae358807b4aaad547a986afb887

# 我们来测试一下!打通mynet-docker0 
# 命令 docker network connect [OPTIONS] NETWORK CONTAINER
[root@slaves2 Dockerfile]# docker network connect mynet tomcat01 
[root@slaves2 Dockerfile]# docker network inspect mynet
此时我们查看的mynet网络,发现里面竟然有tomcat01里面的网络,形成一个容器两个地址
www.zeeklog.com  - Docker的精髓(容器数据卷、Dockerfile、Docker网络)
# tomcat01 可以ping通了
 [root@kuangshen ~]# docker exec -it tomcat01 ping tomcat-net-01
  PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data. 
  64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.071 ms 
  64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.067 ms
# tomcat02 依旧ping不通,大家应该就理解了
 [root@kuangshen ~]# docker exec -it tomcat02 ping tomcat-net-01 
  ping: tomcat-net-01: Name or service not known

结论:如果要跨网络操作别人,就需要使用 docker network connect [OPTIONS] NETWORK CONTAINER 连接