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.\n' % (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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

 

 

  

 

 

 

 

  

 

posted on 2021-07-29 20:23  chalon  阅读(129)  评论(0编辑  收藏  举报