• docker 基础之网络管理


    docker网络基础

    docker使用到的与linux网络有关的主要技术

    • Network Namespace(网络命名空间)
    • Veth设备对
    • Iptables/NetFilter
    • 网桥
    • 路由

    标准的dokcer支持以下4种网络模式

    • host模式: 使用--net=host指定
    • container模式:使用--net=container:NAME_or_ID指定
    • none模式: 使用 --net=none指定
    • bridge模式:使用--net=bridge指定,为默认设置
      • docker第一次启动时会创建一个虚拟网桥,默认为docker0,在私有网络空间中给这个网桥分配一个子网,由docker创建出来的每一个容器,会创建一个虚拟的以太网设备(veth设备对),其中一端关联到网桥,一端使用linux的网络命名空间技术映射为容器内的eth0设备,然后从网桥的地址段内给eth0接口分配一个ip地址  

    容器访问外部网络

    器要想访问外部网络,需要本地系统的转发支持。在Linux 系统中,检查转发是否打开。

    $sysctl net.ipv4.ip_forward
    net.ipv4.ip_forward = 1

    如果为 0,说明没有开启转发,则需要手动打开。

    从外部访问容器

    容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P 或 -p 参数来指定端口映射。

    当使用 -P 标记时,Docker 会随机映射一个 49000~49900 的端口到内部容器开放的网络端口。
    -p(小写的)则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。支持的格式有 

    ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort。

    映射所有接口地址

    使用 hostPort:containerPort 格式本地的 5000 端口映射到容器的 5000 端口,可以执行

    $ sudo docker run -d -p 5000:5000 training/webapp python app.py

    此时默认会绑定本地所有接口上的所有地址。


    映射到指定地址的指定端口
    可以使用 ip:hostPort:containerPort 格式指定映射使用一个特定地址,比如 localhost 地址 127.0.0.1

    $ sudo docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py

    映射到指定地址的任意端口

    使用 ip::containerPort 绑定 localhost 的任意端口到容器的 5000 端口,本地主机会自动分配一个端口。

    $ sudo docker run -d -p 127.0.0.1::5000 training/webapp python app.py

    还可以使用 udp 标记来指定 udp 端口

    $ sudo docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py

    查看映射端口配置

    使用 docker port 来查看当前映射的端口配置,也可以查看到绑定的地址

    $ docker port nostalgic_morse 5000    #container NAMES
    127.0.0.1:49155.

    注意:
    容器有自己的内部网络和 ip 地址(使用 docker inspect 可以获取所有的变量,Docker 还可以有一个可变的网络配置。)

    -p 标记可以多次使用来绑定多个端口,例如:

    $ sudo docker run -d -p 5000:5000 -p 3000:80 training/webapp python app.py

    容器互联

    官网示例

    先创建一个新的 Docker 网络。
    
    $ docker network create -d bridge my-net
    -d 参数指定 Docker 网络类型,有 bridge overlay。其中 overlay 网络类型用于 Swarm mode
    
    
    连接容器,运行一个容器并连接到新建的 my-net 网络
    
    $ docker run -it --rm --name busybox1 --network my-net busybox sh
    
    打开新的终端,再运行一个容器并加入到 my-net 网络
    
    $ docker run -it --rm --name busybox2 --network my-net busybox sh
    
    进入容器,通过互相ping 容器名称来判断是否互联
    

      

    自己测试示例

    #查看所有网络:
    docker network ls
    
    #创建自己的网络
    docker network create -d bridge my-bridge-network
    
    #检查网络(如果你检查网络,会发现里面什么都没有)
    docker network inspect my-bridge-network

    添加一个容器到自定义的网络

    #指定网络 运行(将db添加为自定义的网络)
    docker run -d --net=my-bridge-network --name db training/postgres     #--name 为定义的名字
    
    
    #再次检查网络(会发现多了一个容器)
    docker network inspect my-bridge-network
    
    #查看网络情况
    docker inspect --format='{{json .NetworkSettings.Networks}}' db
    
    #查看ip地址
    docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' db
    
    #启动另一个容器:并不在一个网段,未加入到自定义的网络 名称为web
    docker run -d --name web training/webapp python app.py

    进入交互模式,并且ping web的地址进行测试

    docker exec -it db bash #此时是ping 不通的
    
    #将web加入自定义的网络
    $ docker network connect my-bridge-network web
    
    docker exec -it db bash   #然后在去交互模式ping web,就可以通信了

    容器互联-linking系统 

    docker有一个linking 系统可以连接多个容器。它会创建一对父子关系,父容器可以看到所选择的 子容器的信息。

    注意
    容器的名 称 是 唯 一的。如果 你 命名了一个 叫 web的容器,当 你 要 再次 使用 web这个名 称 的 时候 , 你 需要用 docker rm来 删 除之前创建的容器,也可以 再 执行 docker run的 时候 加--rm标记来 停止旧 的容器, 并删 除, rm 和 -d 参 数是 不兼 容的

    使用--name标记可以为容器命名

    $ sudo docker run -d -P --name web training/webapp python app.py

    使用docker ps -l 来验证我们设定的命名

    $ sudo docker ps -l

    links可以让容器之间安全的交互,使用--link标记。

    #先创建一个新的数据库容器,
    $ sudo docker run -d --name db training/postgres
    
    
    #创建一个新的web容器,并将它link到db容器 
    $ docker run -d -P --name web --link db:db training/webapp python app.py
    
    # --link标记的格式:--link name:alias,name是我们要链接的容器的名称,alias是这个链接的别名(会在新建的容器中/etc/hosts添加一条记录 ip db 此处的db为指定的alias别名

    使用docker ps来查看容器的链接

     可以看到命名的容器,db和web,db容器的names列有db也有web/db。这表示web容 器链接到db容器,他们是一个父子关系。在这个link中,2个容器中有一对父子关系。docker在2个 容器之间创建了一个安全的连接,而且不用映射他们的端口到宿主主机上。在启动db容器的时候也不 用-p和-P标记。使用link之后我们就可以不用暴露数据库端口到网络上。

    docker 通过2种方式为父子关系的容器公开连接信息:

    • 环境变量
    • 更新/etc/hosts文件

    #使用env命令来查看容器的环境变量 
    $ sudo docker run --rm --name web2 --link db:db training/webapp env
    
    #除了环境变量,docker还添加host信息到父容器的/etc/hosts的文件。下面是父容器web的hosts文件 
    $ sudo docker run -t -i --rm --link db:db training/webapp /bin/bash 
    root@aed84ee21bde:/opt/webapp# cat /etc/hosts

    这里有2个hosts,第一个是web容器,web容器用id作为他的主机名,第二个是db容器的ip和主机名

    root@aed84ee21bde:/opt/webapp# apt-get install -yqq inetutils-ping 
    root@aed84ee21bde:/opt/webapp# ping db 
    PING db (172.17.0.5): 48 data bytes 
    56 bytes from 172.17.0.5: icmp_seq=0 ttl=64 time=0.267 ms 
    56 bytes from 172.17.0.5: icmp_seq=1 ttl=64 time=0.250 ms 
    56 bytes from 172.17.0.5: icmp_seq=2 ttl=64 time=0.256 ms 
    用ping来ping db容器,它会解析成172.17.0.5

    注意:官方的ubuntu镜像默认没有安装ping
    注意:你可以链接多个子容器到父容器,比如我们可以链接多个web到db容器上。

    docker高级网络配置

    快速配置指南

    下面是一个跟docker网络相关的命令列表,有些命令选项只有 在docker服务启动的时候才可以执行,而且不能马上生效。

    • -b BRIDGE or --bridge=BRIDGE —   桥接配置--bip=CIDR —              定制docker0的掩码-H SOCKET... or --host=SOCKET... — 它告诉docker从哪个通道来接收run container stop container这样的命令,也是docker api的地址--icc=true|false           
    • --ip-forward=true|false      
    • --iptables=true|false         
    • --mtu=BYTES —            
    • --dns=IP_ADDRESS...         
    • --dns-search=DOMAIN...       
    • -h HOSTNAME or --hostname=HOSTNAME — 主机名配置--link=CONTAINER_NAME:ALIAS     — link 系统--net=bridge|none|container:NAME_or_ID|host     —桥接配置-p SPEC or --publish=SPEC       — 映射容器端口到宿主主机-P or --publish-all=true|false     — 映射容器端口到宿主主机

    配置容器dns服务的方法

    • -h HOSTNAME or --hostname=HOSTNAME 设定容器的主机名,它会被写到/etc/hostname,/etc/hosts中的ip地址自动写成分配的ip地址, 在/bin/bash中显示该主机名。但它不会在docker ps中显示,也不会在其他的容器的/etc/hosts中显示。
    • --link=CONTAINER_NAME:ALIAS 这选项会在创建容器的时候添加一个其他容器CONTAINE_NAME的主机名到/etc/hosts文件中, 让新容器的进程可以使用主机名ALIAS就可以连接它。
    • --dns=IP_ADDRESS 添加dns服务器到容器的/etc/resolv.conf中,让容器用这ip地址来解析所有不在/etc/hosts中的主 机名。 
    • --dns-search=DOMAIN 设定容器的搜索域,当设定搜索域为.example.com时,会在搜索一个host主机名时,dns不仅搜索 host,还会搜索host.example.com

    注意:如果 没 有上 述最 后 2个 选 项, docker会用主机上的 /etc/resolv.conf来配置容器, 它 是 默 认配置。


    创建自己的桥接

    #停止旧网桥并删除 
    $ sudo service docker stop 
    $ sudo ip link set dev docker0 down 
    $ sudo brctl delbr docker0
    
    # 创建自己的网桥 
    $ sudo brctl addbr bridge0 
    $ sudo ip addr add 192.168.5.1/24 dev bridge0 
    $ sudo ip link set dev bridge0 up 
    # 确认网桥启动 
    $ ip addr show bridge0
    
    # 告诉docker桥接设置,并启动docker服务(在ubuntu上) 
    $ echo 'DOCKER_OPTS="-b=bridge0"' >> /etc/default/docker 
    $ sudo service docker start

    docker服务启动成功并绑定容器到新的网桥,建一个容器,你会看到它的ip是我们的设置的新ip 段,docker会自动检测到它。

    用brctl show可以看到容器启动或则停止后网桥的配置变化,在容器中使 用ip a 和ip r 来查看ip地址配置和路由信息


    创建一个点到点连接(network namespace)

    #创建一个名为nestest的 network namespace
    ip netns add netest
    
    #列出系统中存在的network namespace
    ip netns list
    
    #删除一个network namespace
    ip netns delete nstest
    
    #在network namespace中执行一条命令
    ip netns exec <network namespace name > command
    
    如:
    ip netns exec <network namespace name > ip addr
    
    #在network namespace中启动一个bash
    ip netns exec <network namespace name > /bin/bash

    默认docker会将所有容器连接到由docker0提供的虚拟子网,你也可以使用自己创建的网桥。但如 果你想要2个特殊的容器之间可以直连通信,而不用去配置复杂的主机网卡桥接。
    解决办法很简单:创建一对接口,把2个容器放到这对接口中,配置成点到点链路类型。这2个容 器就可以直接通信了。配置如下:

    # 在2个终端中启动2个容器 
    $ sudo docker run -i -t --rm --net=none base /bin/bash 
    root@1f1f4c1f931a:/#
    $ sudo docker run -i -t --rm --net=none base /bin/bash 
    root@12e343489d2f:/#
    
    
    #找到他们的process IDs ,然后创建他们的 namespace entries
    $ sudo docker inspect -f '{{.State.Pid}}' 1f1f4c1f931a 
    2989 
    $ sudo docker inspect -f '{{.State.Pid}}' 12e343489d2f 
    3004 
    $ sudo mkdir -p /var/run/netns 
    $ sudo ln -s /proc/2989/ns/net /var/run/netns/2989 
    $ sudo ln -s /proc/3004/ns/net /var/run/netns/3004
    # 创建”peer“接口,然后配置路由
    
    #在主机上创建虚拟网卡 $ sudo ip link add A type veth peer name B
    $ sudo ip link set A netns
    2989           #2989为一个network namespace此处是将网卡放到network namespace中的命令 $ sudo ip netns exec 2989 ip addr add 10.1.1.1/32 dev A $ sudo ip netns exec 2989 ip link set A up       #启动网卡 $ sudo ip netns exec 2989 ip route add 10.1.1.2/32 dev A    #分配ip $ sudo ip link set B netns 3004 $ sudo ip netns exec 3004 ip addr add 10.1.1.2/32 dev B $ sudo ip netns exec 3004 ip link set B up $ sudo ip netns exec 3004 ip route add 10.1.1.1/32 dev B

    现在这2个容器就可以相互ping通,并成功建立连接。点到点链路不需要子网和子网掩码,使用ip route 来连接单个ip地址到指定的网络接口。

    如果 没 有 特 殊 需要 你不 需要指定 --net=none来创建点到点 链路 。 还有一个办法就是创建一个只跟主机通信的容器,除非有特殊需求,你可以仅用--icc=false来限制 主机间的通信。

     

  • 相关阅读:
    十大佛教经典语,你最中意哪一句
    哲理人生名句, 拿个本子记下来
    逸乐有节 不可过度
    教你怎么用59秒就能打动客户?
    爱的意义
    一个聪明女人写的日记(转)
    做人做事十三条铁则
    爱上一个人的7个征兆
    办公室白领须知的18个定律
    生活智慧:奇特的人生法则
  • 原文地址:https://www.cnblogs.com/FRESHMANS/p/8425804.html
Copyright © 2020-2023  润新知