理解Dock0

image.png

  • 从上图中可以看出, 该Linux 本机有3 个网络地址
  • 问题: docker 是如何处理容器网络访问?

如下图, tomcat 容器是如何连接MySQL 容器?
image.png

测试

  1. 启动tomcat 容器

    1. docker run -d -P --name tomcat01 tomcat
  2. 查看容器内部的IP 地址 ```shell

    可以使用exec 命名后带参数执行ip addr 命令, 这样无需进入容器再去执行ip addr 命令

    发现容器启动时会得到一个eth0@if9 的ip 地址, 这是docker 分配的

    docker exec -it tomcat01 ip addr

以下是docker 返回的信息

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 inet6 ::1/128 scope host valid_lft forever preferred_lft forever 8: eth0@if9: 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 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::42:acff:fe11:2/64 scope link valid_lft forever preferred_lft forever

  1. - 问题1: 容器内没有ip addr 命令, 如何安装?
  2. - 执行以下命令:
  3. ```shell
  4. apt update&& apt install -y iproute2
  • 问题2: linux 宿主机能否ping 通容器内部?
    • 发现可以ping 通docker 容器内部

image.png

原理

  1. 每启动一个docker 容器, docker 就会给容器分配一个ip, 只要安装了docker, 就会有一个网卡 docker0, 使用的是桥接模式, 是由evth-pair 技术实现的

再次测试ip addr
image.png

  1. 再启动一个容器测试, 发现有多了一对网卡

image.png

  • 给容器分配的网卡地址都是成对出现的, veth-pair 就是一对虚拟设备接口, 它们都是成对出现的, 一端连接协议, 一端彼此相连, 正是因为这个特性, veth-pair 充当一个桥梁, 用来连接各种虚拟网络设备
  • OpenStac, Docker 容器之间的连接, OVS 的连接, 都是使用veth-pair 技术
  1. 测试容器之间是否能ping 通, 如下所示:

image.png

网络模型图

image.png

  • 结论:
    • tomcat01 和tomcat02 公用一个路由器, docker0
    • 所有的容器不指定网络的情况下, 都是由docker0 路由的, docker 会给容器分期一个默认的可用IP
    • Docker 使用的是Linux 桥接, 宿主机中是一个Docker 容器的网桥docker0, 最多分配65535 个

image.png

  • Docker 中所有的网络接口都是虚拟的, 虚拟的转发效率高
  • 只要容器删除, 对应的网络地址就会被删除

image.png

—link

抛出问题

  • 微服务项目中, 配置了数据库IP 地址, 如果使用docker 部署, 每次分配给MySQL 的ip 地址就会变, 希望使用服务名来访问容器

测试

  • 使用tomcat02 容器ping tomcat01 容器 ```shell docker exec -it tomcat02 ping tomcat01

发现直接使用容器名, 不能ping 通

ping: tomcat01: Name or service not known

  1. - 使用--link 命令进行容器之间的连接, 发现可以使用容器名来ping
  2. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/2516625/1643792248977-af38fb77-a699-4c6e-9243-b1428f959ae6.png#clientId=u06056fcc-d5c3-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=229&id=u52188ced&margin=%5Bobject%20Object%5D&name=image.png&originHeight=400&originWidth=1326&originalType=binary&ratio=1&rotation=0&showTitle=false&size=63884&status=done&style=none&taskId=u62e20ce1-231a-42f3-aafc-8b40540eb2e&title=&width=757.7142857142857)
  3. - 但是反向不能ping 通, 因为没有配置
  4. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/2516625/1643792350130-55895b99-5147-498d-a13f-cccc2092f2f8.png#clientId=u06056fcc-d5c3-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=35&id=u9e083382&margin=%5Bobject%20Object%5D&name=image.png&originHeight=61&originWidth=950&originalType=binary&ratio=1&rotation=0&showTitle=false&size=8978&status=done&style=none&taskId=ucdd9c097-22be-4958-9861-fe5d6494292&title=&width=542.8571428571429)
  5. <a name="lV8JD"></a>
  6. ## 原理探究
  7. - tomcat03 hosts 中配置了tomcat02 的地址
  8. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/2516625/1643793645965-07776e73-c51c-4048-8778-f9cbf5ffd389.png#clientId=u06056fcc-d5c3-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=160&id=ud874b4a2&margin=%5Bobject%20Object%5D&name=image.png&originHeight=280&originWidth=978&originalType=binary&ratio=1&rotation=0&showTitle=false&size=29355&status=done&style=none&taskId=ucf43c0fe-81a0-4a14-812e-22878c357e2&title=&width=558.8571428571429)
  9. - 本质:
  10. - hosts 配置中增加了容器名和IP 的配置
  11. <a name="mEGif"></a>
  12. ## network 命令
  13. ```shell
  14. #使用network ls 命令来查看网络列表
  15. docker network ls
  16. NETWORK ID NAME DRIVER SCOPE
  17. d09975f74ad0 bridge bridge local
  18. d30adabb09ce host host local
  19. 2f73acc8df73 none null local
  1. #使用inspect 命令来查看网络具体信息
  2. docker network inspect d09975f74ad0
  3. #以下是docker0 的具体信息
  4. [
  5. {
  6. "Name": "bridge",
  7. "Id": "d09975f74ad0fb541aac83f498fb57faed55157b61ae4dcb9e53f97b74fd5464",
  8. "Created": "2022-02-02T02:30:04.985189843-05:00",
  9. "Scope": "local",
  10. "Driver": "bridge",
  11. "EnableIPv6": false,
  12. "IPAM": {
  13. "Driver": "default",
  14. "Options": null,
  15. "Config": [
  16. {
  17. "Subnet": "172.17.0.0/16",
  18. "Gateway": "172.17.0.1"
  19. }
  20. ]
  21. },
  22. "Internal": false,
  23. "Attachable": false,
  24. "Containers": {
  25. "3fbf9cd2ca26d07a9d77df5be6afa554ead335c8cbe30f22ec962c664feae53d": {
  26. "Name": "tomcat03",
  27. "EndpointID": "300ca07f517257e39f24ff158479e7971782e3dc07a2a59c7618876d7386a60a",
  28. "MacAddress": "02:42:ac:11:00:04",
  29. "IPv4Address": "172.17.0.4/16",
  30. "IPv6Address": ""
  31. },
  32. "8bf803d31d17bf70e8b5a045692a802cee45d542afa4571c8afe0b6305980477": {
  33. "Name": "tomcat02",
  34. "EndpointID": "968d07131fd81c2f4118a997b2db91dcb40581d4b95e194723d9aaa7ebae46d0",
  35. "MacAddress": "02:42:ac:11:00:03",
  36. "IPv4Address": "172.17.0.3/16",
  37. "IPv6Address": ""
  38. },
  39. "b94a83be3fc9c179fc4f3dd418add445758ab7f712ace032b8ef25ec51101072": {
  40. "Name": "tomcat01",
  41. "EndpointID": "43b95090964a868c8162e901c3fcb7db1d46183a81e9887aa848525eb8ce1852",
  42. "MacAddress": "02:42:ac:11:00:02",
  43. "IPv4Address": "172.17.0.2/16",
  44. "IPv6Address": ""
  45. }
  46. },
  47. "Options": {
  48. "com.docker.network.bridge.default_bridge": "true",
  49. "com.docker.network.bridge.enable_icc": "true",
  50. "com.docker.network.bridge.enable_ip_masquerade": "true",
  51. "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
  52. "com.docker.network.bridge.name": "docker0",
  53. "com.docker.network.driver.mtu": "1500"
  54. },
  55. "Labels": {}
  56. }
  57. ]

自定义网络

抛出问题

  • docker0 不支持容器名连接访问

查看所有的docker 网络

image.png

网络模式

  • bridge (桥接模式, 自己创建使用这个模式)
    • 有0.2 和0.3 两个网络地址, 它们不能直接访问, 需要通过0.1 转发访问
  • none (不配置网络)
  • host:
    • 和宿主机共享网络
  • container
    • 容器网络连通 (局限性很大)

测试

  1. 启动容器
    1. #使用--net bridge 参数, 使用的桥接方式是通过docker0 转发
    2. docker run -d -P --name tomcat01 --net bridge tomcatip:0.1
  • docker0 特点: 默认, 域名不能访问, —link 可以打通连接
  1. 创建自定义网络 ```shell

    使用docker network create 命令创建自定义的网络

    —driver: 使用的模式, bridge, 使用的是桥接(docker0)

    —subnet: 子网掩码, 后面跟划分网络内主机的掩码

    —gateway: 网关地址

    mynet: 网络名, 可以换成其他名字

    docker network create —driver bridge —subnet 192.168.0.0/16 —gateway 192.168.0.1 mynet

    创建完毕后产生的信息

    ee7ec2ca1d394e79916fcf5ed4f358e869cad2a4ce450722af2c728f3dc22431

查看网络列表

docker network ls

发现已经有自定义网络

NETWORK ID NAME DRIVER SCOPE d09975f74ad0 bridge bridge local d30adabb09ce host host local ee7ec2ca1d39 mynet bridge local 2f73acc8df73 none null local

  1. 3. 查看自定义网络信息
  2. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/2516625/1643794785871-01301693-fece-43b1-bb1d-c1a0eb2f7157.png#clientId=u06056fcc-d5c3-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=451&id=u0a280db7&margin=%5Bobject%20Object%5D&name=image.png&originHeight=790&originWidth=1316&originalType=binary&ratio=1&rotation=0&showTitle=false&size=51849&status=done&style=none&taskId=udd108075-ad91-4800-a765-652f11bd7fe&title=&width=752)
  3. 4. 启动容器, 将容器添加到自定义的网络中(通过--net 网络名添加到网络中), 之后再查看自定义的网络信息
  4. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/2516625/1643794979873-86be4172-1018-4682-9704-85f59fe53398.png#clientId=u06056fcc-d5c3-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=773&id=ua0da3c5d&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1353&originWidth=2160&originalType=binary&ratio=1&rotation=0&showTitle=false&size=176336&status=done&style=none&taskId=ub9623cba-a903-4757-8ed8-8a848d874d3&title=&width=1234.2857142857142)
  5. 5. 测试ping 命令, 发现可以通过容器名ping
  6. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/2516625/1643795170828-2079c54d-f424-46dc-a89e-a333feec2a03.png#clientId=u06056fcc-d5c3-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=294&id=u40562e4c&margin=%5Bobject%20Object%5D&name=image.png&originHeight=514&originWidth=2053&originalType=binary&ratio=1&rotation=0&showTitle=false&size=119950&status=done&style=none&taskId=udcdc2fd3-909d-4385-b62e-ad7d8373d49&title=&width=1173.142857142857)
  7. <a name="WWNLF"></a>
  8. ## 好处
  9. - 自定义网络中, docker 会维护每个容器之间的关系, 这样容器之间就可以通过容器名来访问彼此
  10. - 不同的集群使用不同的网络, 保证集群安全和健康
  11. <a name="I4RwA"></a>
  12. # 网络连通
  13. <a name="csiYI"></a>
  14. ## 抛出问题
  15. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/2516625/1643796584748-068ec87c-71ef-4883-bb2e-c4e6fae69ed3.png#clientId=u06056fcc-d5c3-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=618&id=u7067f514&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1081&originWidth=1775&originalType=binary&ratio=1&rotation=0&showTitle=false&size=138135&status=done&style=none&taskId=u56e9077c-2d65-43f7-b9dc-2940e14cfbe&title=&width=1014.2857142857143)
  16. - Docker0 tomcat-01 ping mynet tomcat-net-01, 发现ping 不通
  17. - 需要将docker0 tomcat-01 连到mynet, 这样就可以实现以上目标
  18. <a name="tqVvd"></a>
  19. ## network 之connect 命令
  20. - 使用说明
  21. ```shell
  22. docker network connect --help
  23. Usage: docker network connect [OPTIONS] NETWORK CONTAINER
  24. Connect a container to a network
  25. Options:
  26. --alias stringSlice Add network-scoped alias for the container
  27. --help Print usage
  28. --ip string IP Address
  29. --ip6 string IPv6 Address
  30. --link list Add link to another container (default [])
  31. --link-local-ip stringSlice Add a link-local address for the container
  • 将tomcat-01 添加到mynet 中

    1. docker network connect mynet tomcat01
  • 查看mynet 网络信息, 可以看到tomcat01 被添加到了mynet 网络中

  • 这样就实现了一个容器两个IP 地址

image.png

  • 再次ping tomcat-net-01, 发现可以ping 通

image.png

  • 结论:
    • 假设要跨网络操作别人, 就需要使用docker network connect 连通网络

实战: 部署redis 集群

  • 创建redis 网络, 6 个redis 容器, 挂载每个节点的目录, 并启动容器 ```shell

    创建网络

    docker network create redis —subnet 172.38.0.0/16

通过脚本创建6 个redis 配置

for port in $(seq 1 6); \ do \ mkdir -p /mydata/redis/node-${port}/conf touch /mydata/redis/node-${port}/conf/redis.conf cat << EOF >/mydata/redis/node-${port}/conf/redis.conf port 6379 bind 0.0.0.0 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 cluster-announce-ip 172.38.0.1${port} cluster-announce-port 6379 cluster-announce-bus-port 16379 appendonly yes EOF done

可以将这段代码拷贝到for 循环中, 这样就可以一次性启动redis 容器

docker run -p 637${port}:6379 -p 1637${port}:16379 —name redis-${port} \

-v /mydata/redis/node-${port}/data:/data \

-v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \

-d —net redis —ip 172.38.0.1${port} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

启动第一个redis 容器

docker run -p 6371:6379 -p 16371:16379 —name redis-1 \ -v /mydata/redis/node-1/data:/data \ -v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf \ -d —net redis —ip 172.38.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

启动第二个redis 容器

docker run -p 6372:6379 -p 16372:16379 —name redis-2 \ -v /mydata/redis/node-2/data:/data \ -v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf \ -d —net redis —ip 172.38.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

启动第三个redis 容器

docker run -p 6373:6379 -p 16373:16379 —name redis-3 \ -v /mydata/redis/node-3/data:/data \ -v /mydata/redis/node-3/conf/redis.conf:/etc/redis/redis.conf \ -d —net redis —ip 172.38.0.13 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

启动第四个redis 容器

docker run -p 6374:6379 -p 16374:16379 —name redis-4 \ -v /mydata/redis/node-4/data:/data \ -v /mydata/redis/node-4/conf/redis.conf:/etc/redis/redis.conf \ -d —net redis —ip 172.38.0.14 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

启动第五个redis 容器

docker run -p 6375:6379 -p 16375:16379 —name redis-5 \ -v /mydata/redis/node-5/data:/data \ -v /mydata/redis/node-5/conf/redis.conf:/etc/redis/redis.conf \ -d —net redis —ip 172.38.0.15 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

启动第六个redis 容器

docker run -p 6376:6379 -p 16376:16379 —name redis-6 \ -v /mydata/redis/node-6/data:/data \ -v /mydata/redis/node-6/conf/redis.conf:/etc/redis/redis.conf \ -d —net redis —ip 172.38.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

  1. - 进入其中一个redis 容器, 创建集群
  2. ```shell
  3. redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
  • 创建成功后, 会产生以下信息

image.png

  • 测试redis 集群

image.png

实战: springboot 微服务打包Docker 镜像

  • 创建springboot 项目
  • 打包应用
  • 编写dockerfile ```dockerfile FROM java:8

COPY *.jar /app.jar

CMD [“—server.port=8080”]

EXPOSE 8080

ENTRYPOINT [“java”, “-jar”, “/app.jar”]

  1. - 构建镜像
  2. - jar 包和dockerfile 上传到服务器
  3. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/2516625/1643802159561-29414c4a-fc10-41f5-824a-dcdf4338047e.png#clientId=u06056fcc-d5c3-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=129&id=u29cbdf31&margin=%5Bobject%20Object%5D&name=image.png&originHeight=226&originWidth=787&originalType=binary&ratio=1&rotation=0&showTitle=false&size=19149&status=done&style=none&taskId=uf05d67f2-ad25-4ab5-a2bd-3f525b6eab7&title=&width=449.7142857142857)
  4. - 执行生成镜像命令
  5. ```shell
  6. docker build -t demo .
  • 发布运行

    • 执行以下命令
      1. docker run -d -P --name demo01 demo
  • 测试

    • 执行以下命令 ```shell curl localhost:32781/hello

返回以下信息

Hello, FLM ```