docker容器互联

本章要点:docker容器互联,端口映射

参考来源汇总: Docker容器互联1Docker网络管理2容器与外部连接

端口映射

除了通过网络访问外,Docker还提供了两个方便功能来满足服务访问的基本需求:

  1. 允许映射容器内应用的服务端口到本地宿主主机;
  2. 互联机制实现多个容器间通过容器名来快速访问;

端口映射访问容器

  • 从外部访问容器应用:

    #  -P 随机映射端口 (容器中EXPOSE出的端口)
    ]# docker run -itd -P --name n1 nginx
    Status: Downloaded newer image for nginx:latest
    0a461db48626c065cb39f3c4eb53e7a25c43e2cb632a28b56d74ba1cba269ae7
    
    ~ ]# docker ps
    CONTAINER ID   IMAGE     COMMAND CREATED STATUS PORTS  NAMES
    0a461db48626   nginx     "/docker-entrypoint.…"   8 seconds ago    Up 8 seconds    0.0.0.0:49153->80/tcp, :::49153->80/tcp   n1
    
  • 映射所有接口地址

    ~ ]# docker run -itd -p 12888:80 --name n2 nginx
    6c88c535528d1a2c3791c85a348763eb68e781d04d872f5905f2d6502504be15
    
    ~ ]# docker ps
    CONTAINER ID   IMAGE     COMMAND  CREATED          STATUS          PORTS  NAMES
    6c88c535528d   nginx     "/docker-entrypoint.…"   2 seconds ago    Up 1 second     0.0.0.0:12888->80/tcp, :::12888->80/tcp   n2
    
  • 指定地址

    ]# docker run -itd -p 127.0.0.1:12889:80 --name n3 nginx
    d5c6c68e873185abe7171b92df67306bfd463251189fbc62ffb68bd88efff442
    
    ~ ]# docker ps
    CONTAINER ID   IMAGE     COMMAND CREATED          STATUS                  PORTS NAMES
    d5c6c68e8731   nginx     "/docker-entrypoint.…"   2 seconds ago    Up Less than a second   127.0.0.1:12889->80/tcp                   n3
    
    # 如果不写端口就是随机
    ]# docker run -itd -p 127.0.0.1::80 --name n4 nginx
    87158d011b0b377054c735b0f448f037f124559cf1552b8b1b0b87bc2021cfc7
    ~ ]# docker ps
    CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS                                     NAMES
    87158d011b0b   nginx     "/docker-entrypoint.…"   2 seconds ago    Up 1 second     127.0.0.1:49154->80/tcp                   n4
    
  • 指定协议

    ]# docker run -itd -p 127.0.0.1::80/udp --name n5 nginx
    8361c6b3a3697c128b6387530296be50e7c0bd629a6ef792d0d9636ba1df148e
    
    ~ ]# docker ps
    CONTAINER ID   IMAGE     COMMAND CREATED              STATUS              PORTS NAMES
    8361c6b3a369   nginx     "/docker-entrypoint.…"   1 second ago         Up 1 second         80/tcp, 127.0.0.1:49153->80/udp           n5
    
  • 查看绑定端口

    ]# docker port n4 
        80/tcp -> 127.0.0.1:49154
    

容器间互联

        同一台宿主机上的多个docker容器之间如果想进行通信,可以通过使用容器的ip地址来通信,也可以通过宿主机的ip加上容器暴露出的端口来通信,前者会导致ip址址的硬编码,不方便迁移,并且容器重启后ip地址会改变,除非使用固定的ip,后都的通信方式比较单一,只能依靠监听在暴露出的端口的进程来进来有限通信。通信docker的link机制可以通过一个name来和另一个容器通信,link机制方便了容器去发现其它的容器并且可以安全的传递一些连接信息给其它的容器。

  • 语法

    docker run --link=[容器名]:别名 [镜像] [命令]
    
  • 示例 - 默认网络

    # 运行两个容器
    docker run -d -P --name tomcatn1 -v share1:/usr/local/tomcat/webapps/ edf8233555ae
    docker run -d -P --name tomcatn2 -v share1:/usr/local/tomcat/webapps/ edf8233555ae
    
    docker inspect -f '{{ .NetworkSettings.Networks.bridge.IPAddress  }}' tomcatn1
    172.17.0.2
    docker inspect -f '{{ .NetworkSettings.Networks.bridge.IPAddress  }}' tomcatn2
    172.17.0.3
    docker inspect -f '{{ .NetworkSettings.EndpointID  }}' tomcatn2
    3b8493a98b7f8866055e07338....
    
    # 当我们重启容器之后,容器的id会产生变化, 容器的ip地址是一个不可靠的连接,它会随着容器的改变而改变,如果某些服务使用的ip跟端口是固定的,那么后续使用会产生异常
    
  • 示例 - 容器互联-link

    # 创建两个容器,一个假设是数据库,另一个为web
    ]# docker run -itd --name db nginx
    
    # 将db链接到web中, 这些就可以避免外部直接访问数据库
    ]# docker run -itd --name web --link db:link-db nginx
    
    ]# docker ps
    CONTAINER ID   IMAGE     COMMAND  CREATED          STATUS          PORTS     NAMES
    ccb226d24865   nginx     "/docker-entrypoint.…"   2 seconds ago  80/tcp    web
    0cb1c854cec2   nginx     "/docker-entrypoint.…"   40 seconds ago 80/tcp    db
    
    ]# docker inspect -f "{{ .HostConfig.Links }}" web
    [/db:/web/link-db]
    
    # --rm在执行完最后一条任务之后会直接删除容器
    ]# docker run --rm --name w2 --link db:link-db nginx env
    LINK_DB_PORT_80_TCP=tcp://172.17.0.2:80
    LINK_DB_ENV_PKG_RELEASE=1~buster
    HOSTNAME=5e1e40f85c3b
    LINK_DB_ENV_NGINX_VERSION=1.19.10
    ....
    LINK_DB_NAME=/w2/link-db
    LINK_DB_PORT_80_TCP_ADDR=172.17.0.2
    LINK_DB_PORT_80_TCP_PORT=80
    LINK_DB_PORT_80_TCP_PROTO=tcp
    PWD=/
    
    ]# docker run --rm -it --name w2 --link db:link-db nginx cat /etc/hosts
    127.0.0.1	localhost
    ....
    172.17.0.2	link-db 0cb1c854cec2 db		# 1、别名, 2、容器ID, 3、容器名称
    172.17.0.4	41dbe70b10ea
    
  • 示例 - 拒绝所有容器间互联

    守护进程添加启动选项:  --icc=false
    /usr/bin/docker -icc=false
    
  • 示例- 允许特定容间器连接

    守护进程添加启动选项: docker利用了iptables阻止了容器间访问,并利用link选项
    	--icc=false --iptables=true
    	--link
    /usr/bin/docker -icc=false
    

网络虚拟化

        Docker中的网络接口默认都是虚拟接口,虚拟接口最大优势就是转发效率极高,这是因为Linux通过在内核中进行数据复制来实现虚拟接口之间的数据转发,即发送接口的发送缓存中的数据包将被直接复制到接收接口的接收缓存中,而无需通过外部物理网络设备进行交换,Docker容器网络很好的利用了Linux虚拟网络技术,在本地主机和容器内分别创建一个虚拟接口,并让它们互相连通(这一对接口叫做veth pair)

请添加图片描述

网络容器接口

一般情况下,Docker创建一个容器的时候,会有如下过程。

  1. 创建一对虚拟接口,分别放到本地主机和新容器的命名空间中。

  2. 本地主机一段的虚拟接口连接到默认的docker0网桥或者指定的网桥上,并具有一个veth开头的唯一名字,如veth1234。

    ]# yum install bridge-utils
    ]# brctl show
        bridge name	bridge id			STP 	enabled	interfaces
        docker0		8000.02427de30f27	no		veth4e48afe
    
  3. 容器一端的虚拟接口将放到新创建的容器中,并修改名称作为eth0,这个接口只在容器的命名空间可见。

  4. Docker 在启动时会创建一个虚拟网桥 docker0, 容器启动后都会被桥接到 docker0 上,并自动分配到一个 IP 地址。

  5. 从网桥可用地址段中获取一个空闲地址分配给容器的eth0(例如172.17.0.2/16),并配置默认路由网关为docker0网卡的内部接口docker0的ip地址(例如:172.17.42.1/16)。

    ~]# ip a
    5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
        link/ether 02:42:f9:e2:05:8f 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
    

容器与外部网络的连接

配置容器以访问外部网络及允许外部访问容器。通过设置ip_forward参数和使用iptables规则实现容器网络连接

转发理论

先给结论:使用 iptables -t [表名] -Siptables -t [表名] -L [链名] 命令,指定 Docker 相关链(如 DOCKER、DOCKER-USER)即可查看,需关注 nat 表和 filter 表。

  • 数据转发说明

    • 当数据以本地为目的地时, 数据–> perrouting --> input --> 本机服务 --> output --> postrouting
    • 数据发送时路径: 本机发出–> output --> postrouting
    • 转发路径: 数据不是本机时先到forward链,在进行一个转发
  • filter表中包含的链

    • INPUT

    • FORWARD请添加图片描述

    • OUTPUT

  • 查看 Docker 链的关键命令

    命令格式 作用 示例
    iptables -t nat -S 查看 nat 表中所有链(含 Docker 相关链)的规则 iptables -t nat -S 可显示 DOCKER 链的规则
    iptables -t filter -S 查看 filter 表中所有链(含 Docker 相关链)的规则 iptables -t filter -S 可显示 DOCKER 和 DOCKER-USER 链
    iptables -t filter -L DOCKER-USER 单独查看 filter 表中 DOCKER-USER 链的详细规则 iptables -t filter -L DOCKER-USER --line-number(带编号)
  • 核心步骤与注意事项

    • 确定目标表:Docker 网络规则主要在 nat 表(地址转换)和 filter 表(数据包过滤)中。
    • 查看所有 Docker 链
      • 执行 iptables -t nat -S 查看 nat 表的 DOCKER 链(如端口映射规则)。
      • 执行 iptables -t filter -S 查看 filter 表的 DOCKER(容器间通信)和 DOCKER-USER(用户自定义规则)链。
    • 单独查看特定链:若需修改用户规则,可单独查看 DOCKER-USER 链:iptables -t filter -L DOCKER-USER -n(-n 以数字显示 IP/端口)。
    • 权限要求:所有 iptables 命令需 root 权限(前缀加 sudo
  • 转发示例
    • 容器要想访问外部网络,需要本地系统的转发支持

      cat /etc/sysctl.conf
      net.ipv4.ip_forward = 1
      
      启动Docker服务的时候设定 --ip-forward=true,Docker就会自动设置系统的ip_forward值为1
      
    • 示例

      # 配置前,先清掉iptables策略用于查看
      ~]#  iptables -L -n
      # 运行容器并映射端口
      ~]# docker run -d -P -v share1:/usr/local/tomcat/webapps edf8233555ae
      
      # 两个表 nat 映射端口, 
      ~]# iptables -t nat -L DOCKER -n
      Chain DOCKER (2 references)
      target     prot opt source               destination         
      DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:1030 to:172.17.0.2:8080
      
      # 转发过滤端口
      ~]# iptables -t filter -L DOCKER -n
      Chain DOCKER (0 references)
      target     prot opt source               destination         
      ACCEPT     tcp  --  0.0.0.0/0            172.17.0.2           tcp dpt:8080
      ``
      
Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐