zoukankan      html  css  js  c++  java
  • docker知识5---docker网络

    一、Linux network namespace

      network namespace 是实现网络虚拟化的重要功能,它能创建多个隔离的网络空间,它们有独自的网络栈信息。不管是虚拟机还是容器,运行的时候仿佛自己就在独立的网络中。

      Usage: ip netns list
             ip netns add NAME
             ip netns set NAME NETNSID
             ip [-all] netns delete [NAME]
             ip netns identify [PID]
             ip netns pids NAME
             ip [-all] netns exec [NAME] cmd ...
             ip netns monitor
             ip netns list-id
    

        有了不同 network namespace 之后,也就有了网络的隔离,但是如果它们之间没有办法通信,也没有实际用处。要把两个网络连接起来,linux 提供了 veth pair 。可以把 veth pair 当做是双向的 pipe(管道),从一个方向发送的网络数据,可以直接被另外一端接收到;或者也可以想象成两个 namespace 直接通过一个特殊的虚拟网卡连接起来,可以直接通信。

    ip netns add test1  #添加网络名称空间;
    ip netns add test2  #添加网络名称空间;
    ip netns list       #列出网络名称空间;
    ip netns exec test1 ip a  #进入test1网络名称空间执行命令ip a;
    ip netns exec test1 ip link set dev lo up  #进入test1网络名称空间启动lo接口;
    ip netns exec test2 ip link set dev lo up  #进入test2网络名称空间启动lo接口;
    ip link add veth-test1 type veth peer name veth-test2   #添加2个端口veth-test1、veth-test2,并为端口建立信道;
    ip link set veth-test1 netns test1                     #将veth-test1端口添加进网络名称空间test1;
    ip link set veth-test2 netns test2                    #将veth-test2端口添加进网络名称空间test2;
    ip netns exec test1 ip addr add 192.168.1.1/24 dev veth-test1   #为端口添加IP;
    ip netns exec test2 ip addr add 192.168.1.2/24 dev veth-test2   #为端口添加IP;
    ip netns exec test1 ip link set dev veth-test1 up
    ip netns exec test2 ip link set dev veth-test2 up
    ip netns exec test1 ip a
    ip netns exec test2 ip a
    ip netns exec test1 ping 192.168.1.2 -c 3  #测试2个网络名称空间的端口是否能通信;

     

     

     二、docker容器网络

    在顶层设计中,Docker 网络架构由 3 个主要部分构成:CNM、Libnetwork 和驱动。
        1)CNM 是设计标准。在 CNM 中,规定了 Docker 网络架构的基础组成要素。
        2)Libnetwork 是 CNM 的具体实现,并且被 Docker 采用,Libnetwork 通过 Go 语言编写,并实现了 CNM 中列举的核心组件。
        3)驱动通过实现特定网络拓扑的方式来拓展该模型的能力。

    网络模式1:桥接网络;开启2个容器,查看容器网络不同namespace间如何通信;

    docker run -d --name test1 busybox /bin/sh -c "while true;do sleep 3600;done"  #启动容器;
    docker network ls               #查看docker网络;
    docker network inspect bridge   #查看桥接网络详细信息;
    docker exec -it test1 ip a      #查看容器网络;veth928e759@if16与eth0@if17是2个不同的network namespace之间的一对veth,实现两者间的通信;
    brctl show                #查看宿主机桥接网络信息;veth928e759@if16桥接在宿主机docker0桥接网络的veth928e759接口上;
    docker run -d --name test2 busybox /bin/sh -c "while true;do sleep 3600;done"
    docker exec -it test2 ip a
    docker exec -it test1 ping 172.17.0.3 -c 3

     

     

    ##网络模式2:NAT网络;

    查看容器如何访问Internet;---通过iptables实现nat转换;

    docker exec -it test2 ping baidu.com -c 3
    

    ##网络模式3:none;该网络模式适用于高安全性的应用场景,如:保存密码;
    docker run -d --name test3 --network none busybox /bin/sh -c "while true;do sleep 3600;done"   #启动网络模式为none的容器test3;
    brctl show
    docker network inspect none   #none网络中有一个容器test3;
    docker exec -it test3 ip a    #容器test3只有lo接口,表示该容器只能通过exec登录;

    ##网络模式4:host;容器共享宿主机的network namespace,但易引起宿主机端口及容器端口冲突;
    docker run -d --name test4 --network host busybox /bin/sh -c "while true;do sleep 3600;done"   #启动网络模式为host的容器test4;
    docker container ls
    brctl show
    docker network inspect host   #host网络中有一个容器test4;容器没有网卡mac地址及IP;
    docker exec -it test4 ip a    #容器test4的接口与宿主机一致;
    ip a                          #宿主机与容器的接口一致;

     

    ##docker link:使用默认docker0桥接网络,在启动容器时需添加--link参数才能实现单方向域名解析;使用自建的桥接网络,在启动容器时会默认添加--link参数,实现双方向域名解析;
    docker network create my-bridge    #创建dockers网桥;
    docker network ls                  #显示dockers网桥;
    brctl show                         #查看Linux中网桥;
    docker run -d --name test1 busybox /bin/sh -c "while true;do sleep 3600;done"                 #启动默认桥接模式docker0的容器test1;
    docker run -d --name test2 --link test1 busybox /bin/sh -c "while true;do sleep 3600;done"    #启动默认桥接模式docker0的容器test2,添加指向test1的link;
    docker exec -it test1 ip a |awk '/172/{print $2}' |cut -d/ -f 1   #查看容器test1的IP;
    docker exec -it test2 ip a |awk '/172/{print $2}' |cut -d/ -f 1   #查看容器test2的IP;
    docker exec -it test1 ping $(docker exec -it test2 ip a |awk '/172/{print $2}' |cut -d/ -f 1) -c 3 #容器test1能ping通test2的IP;
    docker exec -it test1 ping test2 -c 3   #容器test1不能ping通test2的name;
    docker exec -it test2 ping $(docker exec -it test1 ip a |awk '/172/{print $2}' |cut -d/ -f 1) -c 3 #容器test1能ping通test2的IP;
    docker exec -it test2 ping test1 -c 3   #容器test1能ping通test2的name;

     

    docker run -d --name nginx-local nginx   #容器默认映射端口为80;但由于未作端口映射,容易引发端口冲突;
    telnet 172.17.0.2 80 
    telnet 127.0.0.1 80
    telnet 192.168.66.10 80
    curl http://172.17.0.2:80      #宿主机上都能访问nginx服务;
    curl http://127.0.0.1:80       #宿主机上都能访问nginx服务;
    curl http://192.168.66.10:80   #其他主机及宿主机上都能访问nginx服务;
    docker network create my-bridge
    docker run -d --network my-bridge -p 1800:80 --name nginx-1 nginx
    telnet 172.20.0.2 80        #端口服务正常;
    telnet 127.0.0.1 1800       #端口服务正常;
    telnet 192.168.66.10 1800   #端口服务正常;
    

    VMware虚拟机映射端口或端口转发:https://jingyan.baidu.com/article/b2c186c8e61a2e856ef6ff8e.html;

     

     

    案例:端口映射
    mkdir flask-redis
    cd flask-redis
    cat <<eof> app.py
    from flask import Flask
    from redis import Redis
    import os
    import socket
    
    app = Flask(__name__)
    redis = Redis(host=os.environ.get('REDIS_HOST', '127.0.0.1'), port=6379)
    
    
    @app.route('/')
    def hello():
        redis.incr('hits')
        return 'Hello Container World! I have been seen %s times and my hostname is %s.
    ' % (redis.get('hits'),socket.gethostname())
    
    
    if __name__ == "__main__":
        app.run(host="0.0.0.0", port=5000, debug=True)
    eof
    
    cat <<eof> Dockerfile
    FROM python:2.7
    LABEL maintaner="chalon"
    COPY . /app
    WORKDIR /app
    RUN pip install flask redis
    EXPOSE 5000
    CMD [ "python", "app.py" ]
    eof
    docker build -t chalon/flask-redis ./
    docker image ls
    
    docker run -d --name redis redis 
    docker run -d --link redis --name flask-redis -e REDIS_HOST=redis chalon/flask-redis  #-e设置环境变量;
    docker exec -it flask-redis env                 #查看容器flask-redis中env环境变量;
    docker exec -it flask-redis ping redis -c 3     #测试容器flask-redis是否能ping通redis容器;
    docker exec -it flask-redis curl 127.0.0.1:5000 #测试容器内部的服务结果为正常;
    docker exec -it flask-redis curl 127.0.0.1:5000 #测试容器内部的服务结果为正常;
    docker exec -it flask-redis curl 127.0.0.1:5000 #测试容器内部的服务结果为正常;
    curl 127.0.0.1:5000                             #宿主机测试服务结果为不正常;
    docker stop flask-redis && docker rm flask-redis #删除容器;
    docker run -d --link redis -p 1500:5000 --name flask-redis -e REDIS_HOST=redis chalon/flask-redis  #启动容器;
    docker exec -it flask-redis curl 127.0.0.1:5000 #测试容器内部的服务结果为正常;
    docker exec -it flask-redis curl 127.0.0.1:5000 #测试容器内部的服务结果为正常;
    curl 127.0.0.1:1500         #宿主机能访问服务,由于redis-server未重启,则会累加访问次数;
    curl 127.0.0.1:1500         #宿主机能访问服务,由于redis-server未重启,则会累加访问次数;
    

     

     

     网络模式5:overlay---多节点容器通信

     

     详细信息详见https://github.com/docker/labs/blob/master/networking/concepts/; VXLAN包结构示意图如下:

        案例:docker网络模式5---overlay
        ####部署etcd集群(分布式存储),用于存储容器IP,以避免IP冲突;
        ##在docker-node1(192.168.66.10)上执行
        wget https://github.com/coreos/etcd/releases/download/v3.0.12/etcd-v3.0.12-linux-amd64.tar.gz
        tar zxvf etcd-v3.0.12-linux-amd64.tar.gz
        cd etcd-v3.0.12-linux-amd64
        nohup ./etcd --name controller --initial-advertise-peer-urls http://192.168.66.10:2380 
           --listen-peer-urls http://192.168.66.10:2380 
           --listen-client-urls http://192.168.66.10:2379,http://127.0.0.1:2379 
           --advertise-client-urls http://192.168.66.10:2379 
           --initial-cluster-token etcd-cluster 
           --initial-cluster controller=http://192.168.66.10:2380,k8s-master02=http://192.168.66.11:2380 
           --initial-cluster-state new &
        ##在docker-node2(192.168.66.11)上执行
        wget https://github.com/coreos/etcd/releases/download/v3.0.12/etcd-v3.0.12-linux-amd64.tar.gz
        tar zxvf etcd-v3.0.12-linux-amd64.tar.gz
        cd etcd-v3.0.12-linux-amd64
        nohup ./etcd --name k8s-master02 --initial-advertise-peer-urls http://192.168.66.11:2380 
           --listen-peer-urls http://192.168.66.11:2380 
           --listen-client-urls http://192.168.66.11:2379,http://127.0.0.1:2379 
           --advertise-client-urls http://192.168.66.11:2379 
           --initial-cluster-token etcd-cluster 
           --initial-cluster controller=http://192.168.66.10:2380,k8s-master02=http://192.168.66.11:2380 
           --initial-cluster-state new &
        ./etcdctl cluster-health #检查cluster状态
        
        ###重启docker服务
        ##在docker-node1(192.168.66.10)上执行
        service docker stop
        /usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=etcd://192.168.66.10:2379 --cluster-advertise=192.168.66.10:2375 & #启动docker,并获取etcd集群信息;此时,可使用ps或docker version查看dockerd状态是运行的,并未采取systemctl方式启动服务;
        ##在docker-node2(192.168.66.11)上执行
        service docker stop
        /usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=etcd://192.168.66.11:2379 --cluster-advertise=192.168.66.11:2375 & #启动docker,并获取etcd集群信息;
        
        ###创建overlay network
        ##在docker-node1上创建一个demo的overlay network
        docker network create -d overlay demo 
        docker network ls
        docker network inspect demo
        ##看到在node2上,这个demo的overlay network会被同步创建
        docker network ls
        ./etcdctl ls docker #检查etcd数据库中的docker目录;
        #在docker-node1(192.168.66.10)上执行
        docker run -d --name overlay_test1 --net demo busybox sh -c "while true; do sleep 3600; done" #创建容器后,将会创建1个docker_gwbridge的网络;
        docker exec overlay_test1 ifconfig
        docker network inspect demo #查看demo网络,包含1个container信息,其IP为10.0.0.1;
        #在docker-node2(192.168.66.11)上执行
        docker run -d --name overlay_test2 --net demo busybox sh -c "while true; do sleep 3600; done"
        docker exec overlay_test2 ifconfig
        docker network inspect demo #查看demo网络,包含2个container信息,其IP为10.0.0.2;
        docker exec overlay_test2 ping 10.0.0.1 -c 3
    

     

     

     

     

     

      

      

      

  • 相关阅读:
    准确率99.9%的离线IP地址定位库
    手写一个消息队列以及延迟消息队列
    rabbitmq介绍
    污点和亲和力高级调度方式
    ceph
    Vue作业
    label和labelSeletor
    http状态简记
    数据库
    作业
  • 原文地址:https://www.cnblogs.com/chalon/p/15076916.html
Copyright © 2011-2022 走看看