Kubernetes Cookbook 编程指南 中文版教程
创建时间:2018-12-07  访问量:3668  7  0

Kubernetes Cookbook 编程指南 中文版教程

创建一个层叠网络 

Kubernetes通过抽象化网络的方式使跨节点之间的容器相互通信。使用这种方式可行的基本单元是pod,它是Kubernetes中部署的最小单元,并共享集中化环境中的上下文。pod中的容器可以通过本地主机的端口与其它容器通信。Kubernetes可以跨节点部署pod。

那么,pod相互之间是如何进行对话的呢?

Kubernetes是在一个共享的网络命名空间中为每个Pod分配一个IP地址,因此,pod就可以通过网络与其它pod进行通信。有多种方式可以实现这个目的。最简单并且跨平台的方式就是使用flannel。

Flannel为每个主机分配一个IP子网,Docker接受它并将IP分配给独立的容器。Flannel使用etcd来存储IP映射信息,并且有几个后端选择可以用于转发数据包。最简单的后端选择将是使用TUN设备来将IP段封装到UDP数据包中。黙认端口是8285。

Flannel还支持VXLAN内存作为后端来封装数据包。当它不在用户空间中运行时,它可能提供比UDP更好的性能。另一个主流的选择是使用基于Google Cloud Engine(https://cloud.google.com/compute/docs/networking#routing)的高级路由规则。本节我们将使用UDP和VXLAN作为示例说明。

Flanneld是flannel用于监示etcd中信息的代理,为每个主机分配子网租赁,并路由数据包。本部分我们将使用并运行flanneld服务为每个主机分配子网。

如果你正在努力寻找使用哪种类型的后端,这里有一个UDP与VXLAN之间简单的性能测式。我们使用qperf(http://linux.die.net/man/1/qperf)来衡量容器之间数据包的传送性能。当主机上有一些负载时,通过UDP的TCP流单向带宽要比VXLAN慢0.3倍。

开始准备

在安装flannel之前,确定你已经有了etcd服务端点。Flannel需要etcd作为它的数据库。如果此时Doker正在运行,请先停止Docker服务并删除docker0网络,这是由Docker创建的一个虚拟网桥。

# 停止Docker服务
$ sudo service docker stop
# 删除Docker0
$ ip link delete docker0

译者注:如果使用ifconfig命令可以查看的网络配置中有一个名为docker0的网桥。

安装

在etcd实例上使用之前学习的etcdctl命令,向etcd中的/coreos.com/network/config键插入期望的配置数据。

配置中的Key 描述
Network 分配给全部虚拟网络的Flannel IPv4网络
SubnetLen 为主机分配的子网前缀长度,黙认为24
SubnetMin flannel子网分配的IP范围的开始
Subnet flannel子网分配的IP范围的结束
Backend 用于转发数据包的后端选择。黙认是udp
# 为层叠网络Flannel的创建插入期望的CIDR
$ etcdctl set /coreos.com/network/config '{"Network":"192.168.0.0/16"}'

黙认情况下,Flannel会为层叠网络分配192.168.0.0/16的IP地址,为每个主机分192.168.0.0/24的IP地址,当然,你也可以重写黙认的设置并将它插入etcd:

$ cat flnnel-config-udp.json
{
    "Network":"192.168.0.0/16",
    "SubnetLen":"192.168.10.0",
    "SubnetMax":"192.168.99.0",
    "Backend":{
        "Type":"udp",
        "Port":7890
    }
}

使用etcd命令插入flannel-config-udp.json配置:

# 通过Json文件方式插入Key
$ etcdctl set /coreos.com/network/config < flannel-config-udp.json

然后,flannel将为具有/28子网的每个主机分配,并且仅在192.168.10.0到192.168.99.0之间发布子网。后端仍然使用udp并且黙认的端口将从8285改为7890。

我们也可以使用VXLAN来封装数据包并使用etcdctl插入配置文件:

$ cat flannel-config-vxlan.json
{
    "Network":"192.168.0.0/16",
    "SubnetLen":24,
    "Backend":{
        "Type":"vxlan",
        "VNI":1
    }
}

译者注:192.168.0.0/16,这个16表示子网掩码的位数即掩码为255.255.0.0,24表示255.255.255.0

# 通过Json文件插入Key
$ etcdctl set /coreos.com/network/config < flannel-config-vxlan.json

你可能需要使用etcdctl查看配置:

$ etcdctl get /coreos.com/network/config
{
    "Network": "192.168.0.0/16",
    "SubnetLen": 24,
    "Backend": {
        "Type": "vxlan",
        "VNI": 1
    }
}

CentOS 7 or Red Hat Enterprise Linux 7

RHEL7,CentOS7或更新版本的Linux都有一个官方flannel发行包。你可以通过yum命令进行安装:

# 安装flannel软件包
$ sudo yum install flannel

安装完成后, 我们需要配置etcd服务器,以至于可以使用于flannel的服务:

$ cat /etc/sysconfig/flanneld
​
# Flannel配置选项
​
# etcd url 地址。当etcd运行是指向这个服务器
FLANNEL_ETCD="<your etcd server>"
​
# etcd配置key。这是flannel查询需要配置的key。
# 地址范围分配
FLANNEL_ETCD_KEY="/coreos.com/network"
​
# 可以在这里添加任何需要传入的附加选项
# FLANNEL_OPTIONS=""
​
我可以在启动服务器时总是使flanneld保存运行状态。使用systemctl可以实现:

# 黙认启用flanneld服务
$ sudo systemctl enable flanneld
​
# 启动flanneld
$ sudo service flanneld start
​
# 验证服务的运行状态
$ sudo service flannel status
译者注:译者安装的flannel的配置文件中的FLANNEL_ETCD_KEY="/atomic.io/metwork"

其它 Linux 选项

另外,你总是可以下载一个二进制包。CoreOS flannel官方发布页面:https://githup.com/coreos/flannel/release。选择带有latest release标签的包;它包含最新bug修改:

# 下载 flannel 软件包
$ curl -L -O https://github.com/coreos/flannel/releases/download/v0.5.5/
flannel-0.5.5-linux-amd64.tar.gz


# 解压软件包
$ tar zxvf flannel-0.5.5-linux-amd64.tar.gz
​
# 将flanneld安装目录复制到$PATH目录
$ sudo cp flannel-0.5.5/flanneld /usr/local/bin

如果你使用如etcd安装部分那样的启动脚本,你很可能需要选择相同的方式来描述flanneld:

$ cat /usr/lib/systemd/system/flanneld.service
[Unit]
Description=Flanneld overlay address etcd agent
Wants=etcd.service
After=etcd.service
Before=docker.service
​
[Service]
Type=notify
EnvironmentFile=/etc/sysconfig/flanneld
EnvironmentFile=-/etc/sysconfig/docker-network
ExecStart=/usr/bin/flanneld -etcd-endpoints=${FLANNEL_ETCD} -etcdprefix=${FLANNEL_ETCD_KEY} $FLANNEL_OPTIONS
Restart=on-failure
​
RestartSec=5s
​
[Install]
WantedBy=multi-user.target
然后,使用sudo systemctl enable flanneld命令使服务开机自启动。

另外,如果你使用的是一个基于init的Linux系统,你可以将启动脚本(init)放在/etc/init.d/flanneld目录下:

#!/bin/bash
​
# flanneld This shell script takes care of starting and stopping
flanneld
#
​
# Source function library.
. /etc/init.d/functions
​
# Source networking configuration.
. /etc/sysconfig/network
​
prog=/usr/local/bin/flanneld
lockfile=/var/lock/subsys/`basename $prog`
​当你设置好环境变量时,你就可以实现start,stop状态了,并且可以重启服务。你仅仅需要关注的是在启动服务时确保在配置文件中添加了etcd服务端点:
start() {
    # 启动服务
    echo -n $"Starting $prog:"
    daemon $prog\
        --etcd-endpoints=="<your etcd server>"
        -ip-masq=true
        > /var/log/flanneld.log 2 > &1 &
    RETVAL=$?
    echo
    [ $RETVAL -eq 0 ] && touch $lockfile
    return $RETVAL
}
​
stop() {
    [ "$EUID" != "0" ] && exit 4
        echo -n $"Shutting down $prog"
    killproc $prog
    RETVAL=$?
        echo
    [ $RETVAL -eq 0 ] && rm -f $lockfile
    return $RETVAL
}
​
case "$1" in
    start)
    start
    ;;
    stop)
    stop
    ;;
    status)
    status prog
    ;;
    restart|force-reload)
    stop
    start
    ;;
    try-restart|condrestart)
    if status $prog > /dev/null; then
        stop
        start
    fi
    ;;
    reload)
    exit 3
    ;;
    *)
    echo $"Usage: $0 {start|stop|status|restart|try-restart|force-reload}"
    exit 2
esac

如果flannel在启动时卡死

检查你的etcd端口是否是可访问的,并且FLANNEL_ETCD_KEY中的key列表是否存在:

# FLANNEL_ETCD_KEY="/coreos.com/network/config"
$ curl -L http://<etcd endpoint>:2379/v2/keys/coreos.com/
network/config

你也可以使用sudo journalctl -u flanneld命令查看flannel日志。

flannel服务启动完成后,你应该查看一下/run/flannel/subnet.env文件,并使用ifconfig命令查看名为flannel0网桥。

如何去做...

为了确保flannel能够工作并通过Docker虚拟接口传送数据包,我们需要在Docker中集成flannel。

Flannel网络配置

  1. 在flanneld启动运行后,使用ifconfig或ip命令查看接口中是否有一个flannel0的虚拟网桥:

# 检验当前ipv4范围
$ ip a | grep flannel | grep inet
inet 192.168.50.0/16 scope global flannel0

我们来看一下前面的例子,flannel0的子网租赁是192.168.50.0/16。

  1. 当你的flanneld服务启动时,flannel就会从etcd中获取子网租赁并保存,然后黙认写到环境变量文件/run/flannel/subnet.env中,或者你可以在启动时通过使用--subnet-file参数来改变黙认的文件路径:

# 在主机上检验flannel子网配置
$ cat /run/flannel/subnet.env
FLANNEL_SUBNET=192.168.50.1/24
FLANNEL_MTU=1472
FLANNEL_IPMASQ=true

与Docker集成

Docker服务支持一些参数。在/run/flannel/subnet.env文件中,flannel已经通过使用推荐的MTU与IPMASQ的设置分配了一个子网。Docker中相应的参数与下表所示:

参数 含义
--bip="" 指定网桥IP(docker0)
--mtu=0 设置容器网络MTU(针对docker0和veth)
--ip-mask=true (可选)启用IP伪装
  1. 我们可以Docker服务中使用/run/flannel/subnet.env文件中列出的变量:

# 从subnet.env文件中导入环境变量
$ . /run/flannel/subnet.env
​
# 使用flannel信息启动docker服务
# docker -d --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU}
# 如果你的Docker版本是1.8以上,使用daemon子命令代替
$ docker daemon --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU}
  1. 另外,你也可将它指定为Docker的/etc/sysconfig/docker文件中的OPTIONS,这是Docker在CentOS系统中的配置文件:

/etc/sysconfig/docker文件

# set the variables into OPTIONS
$ OPTIONS="--bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU} --ipmasq=${FLANNEL_IPMASQ}"

在前面的示例中,在/etc/sysconfig/docker文件中指定了${FLANNEL_SUBNET}替换了192.168.50.1/24与${FLANNEL_MTU}替换了1472。

  1. 使用service docker start启动Docker并输入ifconfig;你可以看到虚拟网络设备docker0和它从flannel中分配的IP地址。

它是如何工作的...

在前面一步创建了有两个名字分别分flannel0与docker0的虚拟网桥,让我们使用ip命令来看看它们的IP范围:

# 校检本地 IPv4 网络
$ ip -4 a | grep inet
inet 127.0.0.1/8 scope host lo
inet 10.42.1.171/24 brd 10.42.21.255 scope global dynamic ens160
inet 192.168.50.0/16 scope global flannel0
inet 192.168.50.1/24 scope global docker0

主机IP地址为10.42.1.171/24,flannel0是192.168.50.0/16,docker0是192.168.50.1/24,并且将路由设置为所有IP范围:

# 验证路径
$ route -n
Destination Gateway Genmask Flags Metric Ref Use
Iface
0.0.0.0 10.42.1.1 0.0.0.0 UG 100 0 0
ens160
192.168.0.0 0.0.0.0 255.255.0.0 U 0 0 0
flannel0
192.168.50.0 0.0.0.0 255.255.255.0 U 0 0 0
docker0

让你们再深入点查看一下etcd是如何存储flannel的子网信息的。你可以通过etcd中的etcdctl命令获取网络配置。

# 获取网络配置
$ etcdctl get /coreos.com/network/config
{ "Network": "192.168.0.0/16" }
​
# 显示所有子网租赁
$ etcdctl ls /coreos.com/network/subnets
/coreos.com/network/subnets/192.168.50.0-24
​前面的示例展示了CIDR网络是192.168.0.0/16。只有一个子网租赁。验证Key的值;这恰好是主机eth0的IP地址:
# 显示`/coreos.com/network/subnets/192.168.50.0-24`Key的Value
$ etcdctl get /coreos.com/metwork/subnets/192.168.50.0-24
{"PublicIP":"10.42.1.171"}
如果你使用其它后端的解决方案而不是简单的UDP,你可能会查看到更多的配置信息,如下所示:
# 当使用不同后端时的显示值
$ etcdctl get /coreos.com/network/subnets/192.168.50.0-24
{"PublicIP":"10.97.1.171","BackendType":"vxlan","BackendData":{"VtepMAC":"ee:ce:55:32:65:ce"}}
​下面说明了一个数据包是如何从Pod1通过层叠网络到Pod4的。正如我们前面讨论的,每个Pod都有它自己的IP地址并且数据包是封装的,因此Pod的IP就可以路由了。数据包从Pod1经过连接在docker0上的veth(virtual network interface)设备路由到flannel0。该通信由flanneld封装并发送到目标Pod的主机(10.42.1.172)上。

我们通过运行两个独立的容器做一个简单的测试以查看flannel是否工作得很好。假设我们有两个主机(10.42.1.171和10.42.1.172)和不同的子网,由Flannel分配并使用相同的etcd后端,并且每个主机已经通过docker run -it ubuntu /bin/bash启动Docker并运行。

我们可以看到两个容器可以使用ping互相通信。让我们使用host2中的tcpdump命令来观察数据包,这是一个命令行工具,可以帮助转储一个网络数据:

# install tcpdump in container
$ yum install -y tcpdump
​
# observe the UDP traffic from host2
$ tcpdump host 10.42.1.172 and udp
11:20:10.324392 IP 10.42.1.171.52293 > 10.42.1.172.6177: UDP, length 106
11:20:10.324468 IP 10.42.1.172.47081 > 10.42.1.171.6177: UDP, length 106
11:20:11.324639 IP 10.42.1.171.52293 > 10.42.1.172.6177: UDP, length 106
11:20:11.324717 IP 10.42.1.172.47081 > 10.42.1.171.6177: UDP, length 106
容器之间的通信是使用flanneld通过6177端口封装在UDP中。

还可以参见

设置完成后并且理解层叠网络,我们就好理解flannel在Kubernetes中是如何表现的。看看下面的内容:

  1. 第2章Pod的使用,服务的使用指南,理解Kubernetes的概念

  2. 第3章容器端口转发指南,使用容器

  3. 第7章授权与认证指南,高级集群管理