k8s+docker整理
docker容器
docker网络模式
先来个整体感觉:
我们在使用docker run 创建容器的时候可以使用–net 选项指定容器的网络模式,默认是bridge。docker也有以下四种网络模式:
- host模式:容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口
- container模式:创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围
- none:此种模式下并不会给容器进行任何的网络配置,需要自己手动添加
- bridge:模式会为每一个容器分配、设置IP等,并将容器连接到一个docker0虚拟网桥,通过docker0网桥以及Iptables nat表配置与宿主机通信。
创建容器的时候可以指定docker run --net <NETWORK>
来指定网络模式
一、bridge模式
当你安装完成docker的时候,默认就会创建三个网络,你可以使用docker network ls
查看:
-
Bridge 详解
1.1 网络拓扑
当Docker server启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。接下来就要为容器分配IP了,Docker会从RFC1918所定义的私有IP网段中,选择一个和宿主机不同的IP地址和子网分配给docker0,连接到docker0的容器就从这个子网中选择一个未占用的IP使用。如一般Docker会使用172.17.0.0/16这个网段,并将172.17.0.1/16分配给docker0网桥(在主机上使用ifconfig命令是可以看到docker0的,可以认为它是网桥的管理接口,在宿主机上作为一块虚拟网卡使用)。单机环境下的网络拓扑如下,主机地址为10.10.0.186/24。
1.2 创建过程1)在主机上创建一对虚拟网卡veth pair设备。veth设备总是成对出现的,它们组成了一个数据的通道,数据从一个设备进入,就会从另一个设备出来。因此,veth设备常用来连接两个网络设备;
2)Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0。另一端放在主机中,以venth3ef412c这样类似的名字命名,并将这个网络设备加入到docker0网桥中,可以通过
brctl show
命令查看;
3)从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关;
docker run --name nginx_bridge --net=bridge -p 80:80 -d nginx ##创建bridge类型容器
[root@cherish ~]# docker ps ----查看容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fcd90ebf7cc9 nginx "nginx -g 'daemon ..." 25 seconds ago Up 24 seconds 0.0.0.0:80->80/tcp nginx_bridge
[root@cherish ~]# docker inspect fcd90ebf7cc9
......
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "6982d57583c811ba7a5addd0a82ed841b105028b7eb4525e1ed906f280521236",
"EndpointID": "84137f6a7e1d55aa1e14b28027efa1866dd7f6180e5204937b30e843c203a0da",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02"
......
[root@cherish ~]# docker network inspect bridge
[
{
"Name": "bridge",
"Id": "6982d57583c811ba7a5addd0a82ed841b105028b7eb4525e1ed906f280521236",
"Created": "2019-08-24T15:31:06.082641335+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Containers": {
"fcd90ebf7cc91a59411afc17190ad5438910e0092f0927523bd6ca4dc82b375b": {
"Name": "nginx_bridge",
"EndpointID": "84137f6a7e1d55aa1e14b28027efa1866dd7f6180e5204937b30e843c203a0da",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
1.3 容器间的通信
在bridge模式下,连接在同一网桥的容器可以互相通信。(若出于安全考虑,也可以禁止它们之间通信,方法是在DOCKER_OPTS变量中设置–icc=false,这样只有使用–link才能使两个容器通信
)。
(关于OPTS可以自行搜索DOCKER_OPTS)
docker可以开启容器间通信(意味着默认配置–icc=true),也就是说,宿主机上的所有容器可以不受任何限制地相互通信,这可能导致拒绝服务攻击。进一步地,Docker可以通过–ip_forward和–iptables两个选项控制容器间、容器和外部世界的通信。 iptables -t nat -vnL
可以查看具体规则
1)容器也可以与外部进行通信,可以查看自己本机的iptable规则,发现
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
这条规则也就是说说允许所有源地址为 172.17.0.0/16的包(也就是说从容器发出的包),并且不是从docker0网卡发出的,进行源地址转换,转换成主机网卡的地址;也可以看出bridge模式是对包作SNAT转换;
2)那么外界怎么访问容器内的服务呢,同样在你创建一个web类型的容器的时候去查看本机的iptable规则,也会有
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.17.0.2:80
此条规则就是对主机eth0收到的目的端口为80的tcp流量进行DNAT转换,将流量发往172.17.0.2:80,也就是我们上面创建的Docker容器;所以,外界访问容器内服务可以通过访问物理机ip:端口
同样的你也可以自定义创建docker的DNS、ip address以及网桥:
docker network create --driver bridge new_bridge
二、Host 详解
采用 host 模式的 Docker Container,可以直接使用 宿主机的 IP 地址与外界进行通信,若宿主机的 eth0 是一个公有 IP,那么容器也拥有这个公 有 IP。同时容器内服务的端口也可以使用宿主机的端口,无需额外进行 NAT 转换。但是这样的话会损失其他特性,最明显的就是Docker Container 网络环境隔离性的弱化,即容器不再拥有隔离、独立的网络栈。
docker run --name nginx_host --net host -p 80:80 -d nginx
三、Container 详解 net=container:Name/ID
与指定的容器使用同一个network namespace,具有同样的网络配置信息,两个容器除了网络,其他都还是隔离的。
自定义网络 与默认的bridge原理一样,但自定义网络具备内部DNS发现,可以通过容器名或者主机名容器之间网络通信。
docker run -it --name vm4 --net container:vm1 ubuntu
四、None模式
网络环境为 none,即不为 Docker Container 任何的网络环境。一旦 Docker Container 采用了
none 网络模式,那么容器内部就只能使用 loopback 网络设备,不会再有其他的网络资源 ;
但并非是说是在也不可以拥有网络,你可以自己去指定相关网络配置
在 none 网络模式下分配固定 ip:
netns 是在 linux 中提供网络虚拟化的一个项目,使用 netns 网络空间虚拟化可以在本地虚拟
化出多个网络环境,目前 netns 在 lxc 容器中被用来为容器提供网络。
使用 netns 创建的网络空间独立于当前系统的网络空间,其中的网络设备以及 iptables 规则
等都是独立的,就好像进入了另外一个网络一样
docker run -it --name vm5 --net none ubuntu
[root@cherish ~]docker inspect vm5 |grep Pid # 过滤vm5的进程id
[root@cherish ~]cd /proc/Pid
[root@cherish ~]cd ns
[root@cherish ~]ln -s /proc/14854/ns/net /var/run/netns/Pid
[root@cherish ~]ip link set veth1 netns Pid //将venth1加入到网络名称空间Pid中
[root@cherish ~]ip netns exec Pid ip link set veth1 name eth0 //修改venth1接口为eth0
[root@cherish ~]ip netns exec Pid ip link set up dev eth0 //将接口up
[root@cherish ~]ip netns exec Pid ip addr add 172.17.0.100/24 dev eth0
[root@cherish ~]ip netns exec Pid ip route add default via 172.17.0.1
##检查网络
[root@cherish ~]ip a
[root@cherish ~]route -n
[root@cherish ~]ping www.baidu.com
[ ] 拓展
1、自定义docker0网桥的ip信息:/etc/docker/docker.json
{
"bip": "192.168.1.5/24",
"fixed-cidr": “10.20.0.0/16”,
"fixed-cidr-v6": "2001:db8::/64",
"mtu": 1500,
"default-gateway": "10.20.1.1",
"default-gateway-v6": "2001:db8:abcd::89",
"dns": ["10.20.1.2","10.20.1.3"]
}
****** 核心选项为bip,即为bridge ip ,用于指定自身的ip地址,其他选项可以通过计算得出;
2、监听其他主机上的docker(docker守护进程的C/S,其默认只监听Unix socket格式的地址,/var/run/docker.sock;如果使用TCP套接字,修改/etc/docker/daemon.json:
"hosts": ["tcp://0.0.0.0:2375","unix:///var/run/docker.sock"]
也可以向docker直接传递“-H | --host”选项
docker -H “远程主机的IP” command
(记得重启docker服务)
3、创建自定义网桥
1)一种是修改原先网桥Ip等配置,如上第一种方法;
2)使用docker network命令创建新的网桥:(具体docker network可以使用帮助文档查看)
docker network create -d bridge --subnet "172.28.0.0/16" --gateway "172.28.0.1" my_bridge
docker network ls 或者brctl show 查看你所创建的网桥
那么如果想原始网桥和你自定义的网桥内的容器互通的话,需要打开宿主机的核心转换功能:
修改 /proc/sys/net/ipv4/ip_forward
为“1”即可;如果没有互通的话需要检查iptables规则:iptables -vnL
,但需要注意如果删除一些规则的话,本身一些SNAT以及DNAT规则会失效;
docker存储卷
- Why Data Colume?
1、docker镜像由多个只读层叠加而成,启动容器时,docker只会加载只读镜像层并在镜像栈顶部添加一个读写层;
2、如果运行中的容器修改了现有的一个已经存在的文件,那么该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏,此即为“写时复制(COW)”机制; - docker存储卷的类型:
两种类型都在容器中存在一个挂载点,但其在宿主机上位置有所不同;
1、Bind mount volume — 手动绑定
a volume that points to a user-specified location on the host file system
2、Docker-managed volume ---- 自动创建
the docker daemon creates managed volumes in a portion of the host’s file system that’s owned by docker
容器中使用Volumes
1、docker-managed volume
docker run -it --name busybox_one -v /data busybox
docker inspect busybox_one //查看容器busybox_one的卷、卷标识符及挂载的主机目录
2、Bind-mount Volume
docker run -it --name busybox_volume_two -v HOSTDIR:VOLUMEDIR busybox
docker inspect -f {{.Mounts}} busybox_volume_two //可以使用golong模板查看
- 复制已存在容器的卷
docker run --name busybox_volume_three --network container:busybox_volume_two --volume-from busybox_volume_two -it busybox