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
扩展:容器停止运行后,数据也是一样能够同步过去的。
测试
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了
启动成功之后,我们在本地使用sqlyog来测试一下
sqlyog-连接到服务器的 3310— 3310和容器内的3306映射,这个时候我们就可以连接上!
测试
1、接下来我创建一个数据库,看linux虚拟机的/home/mysql/data数据库存储路径中是否会生成新创建的数据库。
2、我们在把mysql容器个删除了,看数据是否还能够保存。
总结:使用数据卷后,就是容器删除了,数据可以仍然保存,这就是实现了容器的数据持久化。
DockerFile
DockerFile介绍
DockerFile 是用来构建Docker镜像的构建文件,是由一些列命令和参数构成的脚本。
我们在这里,先体验下,后面我们会详细讲解 DockerFile !
构建步骤:
1.编写一个dockerfile 文件
2、docker build 构建成为一个镜像
3、docker run 运行镜像
4、docker push 发布镜像(DockerHub、阿里云镜像仓库!)
查看官网是怎么操作的
1、进入Docker Hub
2、拿centos为例子
3、选着对应的版本进去,就可以看到对应的Docker File
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、每一个指令都会创建一个新的镜像层,并提交!
Dockerfile是面向开发,我们以后要发布项目,做进行,就需要Dockerfile文件,这个文件时分简单!
DockerFile:它就是构建文件,定义了步骤,好比喻源代码的样子!
Dockerimages:是通过DockerFile构建生成的镜像,最终发布和运行的产品
Docker容器:容器就是镜像运行起来提供服务
Docker File指令
# from 基础镜像,一切从这里开始构建
# maintainer 镜像是谁写的,通常会有你的姓名加邮箱
# run 镜像构建的时候需要运行的命令
# add 添加其余的镜像层
# workdir 镜像的工作目录
# volume 挂载的目录
# expose 暴露端口和 -p一个意思
# cmd 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可呗替代
# entrypoint 指定这个容器启动的时候要运行的命令,可以追加
# onbuild 当构建一个被继承 DockerFile 这个时候就会运行onbuild的命令。出发命令
# copy 类似于add ,将我们文件拷贝到镜像中
# env 构建的时候设置环境变量
DockerFile的实战案例
Docker Hub中百分之99%的镜像都是从FROM scratch开始的,然后配置咋们需要的软件来进行构建
创建一个自己的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
测试
# 查看日志
[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、我们来画一个网络模
结论:tomcat1和tomcat2共用一个路由器。是的,他们使用的一个,就是docker0。任何一个容器启动默认都是docker0网络。
docker默认会给容器分配一个可用ip。
小结
Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
Docker容器网络就很好的利用了Linux虚拟网络技术,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);
Docker中的网络接口默认都是虚拟的接口。虚拟接口的优势就是转发效率极高(因为Linux是在内核中进行数据的复制来实现虚拟接口之间的数据转发,无需通过外部的网络设备交换),对于本地系统和容器系统来说,虚拟接口跟一个正常的以太网卡相比并没有区别,只是他的速度快很多。
Link
思考一个场景,我们编写一个微服务,数据库连接地址原来是使用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
所有网路模式
测试
#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
#4.这时候我们启动的时候就可以直接指使用mynet刚刚创建的网络启动了
然后在去查看网络的详细信息的时候就可以看刚刚启动服务的了
#5、使用主机名平主机名,这时候不适用link
发现,我们自定义的网络docker都已经帮我们维护好了对应的关系
所以我们平时都可以这样使用网络,不使用–link效果一样,所有东西实时维护好,直接域名 ping 通。
网络连通
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里面的网络,形成一个容器两个地址
# 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 连接