1. 前言
php
上一节咱们阐述了Kubernetes的系统架构,让你们对Kubernetes有必定的初步了解,可是就如何使用Kubernetes, 也许你们还不知如何下手。本文做者将带领你们如何在本地部署、配置Kubernetes集群网络环境以及经过实例演示跨机器服务间的通讯,主要包括以下内容:前端
部署环境介绍linux
Kubernetes集群逻辑架构git
部署Open vSwitch、Kubernetes、Etcd组件github
演示Kubernetes管理容器redis
VMware Workstation:10.0.3算法
VMware Workstation网络模式:NATdocker
操做系统信息:CentOS 7 64位json
Open vSwitch版本信息:2.3.0后端
Kubernetes版本信息:0.5.2
Etcd版本信息:0.4.6
Docker版本信息:1.3.1
服务器信息:
Role | Hostname | IP Address |
---|---|---|
APIServer | kubernetes | 192.168.230.3 |
Minion | minion1 | 192.168.230.4 |
Minion | minion2 | 192.168.230.5 |
在详细介绍部署Kubernetes集群前,先给你们展现下集群的逻辑架构。从下图可知,整个系统分为两部分,第一部分是Kubernetes APIServer,是整个系统的核心,承担集群中全部容器的管理工做;第二部分是minion,运行Container Daemon,是全部容器栖息之地,同时在minion上运行Open vSwitch程序,经过GRE Tunnel负责minion之间Pod的网络通讯工做。
为了解决跨minion之间Pod的通讯问题,咱们在每一个minion上安装Open vSwtich,并使用GRE或者VxLAN使得跨机器之间Pod能相互通讯,本文使用GRE,而VxLAN一般用在须要隔离的大规模网络中。对于Open vSwitch的具体安装步骤,可参考这篇博客,咱们在这里就再也不详细介绍安装步骤了。安装完Open vSwitch后,接下来便创建minion1和minion2之间的隧道。首先在minion1和minion2上创建OVS Bridge,
[root@minion1 ~]# ovs-vsctl add-br obr0
接下来创建gre,并将新建的gre0添加到obr0,在minion1上执行以下命令,
[root@minion1 ~]# ovs-vsctl add-port obr0 gre0 -- set Interface gre0 type=gre options:remote_ip=192.168.230.5
在minion2上执行,
[root@minion2 ~]# ovs-vsctl add-port obr0 gre0 -- set Interface gre0 type=gre options:remote_ip=192.168.230.4
至此,minion1和minion2之间的隧道已经创建。而后咱们在minion1和minion2上建立Linux网桥kbr0替代Docker默认的docker0(咱们假设minion1和minion2都已安装Docker),设置minion1的kbr0的地址为172.17.1.1/24, minion2的kbr0的地址为172.17.2.1/24,并添加obr0为kbr0的接口,如下命令在minion1和minion2上执行。
[root@minion1 ~]# brctl addbr kbr0 //建立linux bridge [root@minion1 ~]# brctl addif kbr0 obr0 //添加obr0为kbr0的接口 [root@minion1 ~]# ip link set dev docker0 down //设置docker0为down状态 [root@minion1 ~]# ip link del dev docker0 //删除docker0
为了使新建的kbr0在每次系统重启后任然有效,咱们在/etc/sysconfig/network-scripts/目录下新建minion1的ifcfg-kbr0以下:
DEVICE=kbr0 ONBOOT=yes BOOTPROTO=static IPADDR=172.17.1.1 NETMASK=255.255.255.0 GATEWAY=172.17.1.0 USERCTL=no TYPE=Bridge IPV6INIT=no
一样在minion2上新建ifcfg-kbr0,只需修改ipaddr为172.17.2.1和gateway为172.17.2.0便可,而后执行systemctl restart network重启系统网络服务,你能在minion1和minion2上发现kbr0都设置了相应的IP地址。为了验证咱们建立的隧道是否能通讯,咱们在minion1和minion2上相互ping对方kbr0的IP地址,从下面的结果发现是不通的,经查找这是由于在minion1和minion2上缺乏访问172.17.1.1和172.17.2.1的路由,所以咱们须要添加路由保证彼此之间能通讯。
[root@minion1 network-scripts]# ping 172.17.2.1 PING 172.17.2.1 (172.17.2.1) 56(84) bytes of data. ^C --- 172.17.2.1 ping statistics --- 2 packets transmitted, 0 received, 100% packet loss, time 1000ms [root@minion2 ~]# ping 172.17.1.1 PING 172.17.1.1 (172.17.1.1) 56(84) bytes of data. ^C --- 172.17.1.1 ping statistics --- 2 packets transmitted, 0 received, 100% packet loss, time 1000ms
因为经过ip route add添加的路由会在下次系统重启后失效,为此咱们在/etc/sysconfig/network-scripts目录下新建一个文件route-eth0存储路由,这里须要注意的是route-eth0和ifcfg-eth0的黑体部分必须保持一致,不然不能工做,这样添加的路由在下次重启后不会失效。为了保证两台minion的kbr0能相互通讯,咱们在minion1的route-eth0里添加路由172.17.2.0/24 via 192.168.230.5 dev eno16777736,eno16777736是minion1的网卡,一样在minion2的route-eth0里添加路由172.17.1.0/24 via 192.168.230.4 dev eno16777736。重启网络服务后再次验证,彼此kbr0的地址能够ping通,如:
[root@minion2 network-scripts]# ping 172.17.1.1 PING 172.17.1.1 (172.17.1.1) 56(84) bytes of data. 64 bytes from 172.17.1.1: icmp_seq=1 ttl=64 time=2.49 ms 64 bytes from 172.17.1.1: icmp_seq=2 ttl=64 time=0.512 ms ^C --- 172.17.1.1 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1002ms rtt min/avg/max/mdev = 0.512/1.505/2.498/0.993 ms
到如今咱们已经创建了两minion之间的隧道,并且能正确的工做。下面咱们将介绍如何安装Kubernetes APIServer及kubelet、proxy等服务。
在安装APIServer以前,咱们先下载Kubernetes及Etcd,作一些准备工做。在kubernetes上的具体操做以下:
[root@kubernetes ~]# mkdir /tmp/kubernetes [root@kubernetes ~]# cd /tmp/kubernetes/ [root@kubernetes kubernetes]# wget https://github.com/GoogleCloudPlatform/kubernetes/releases/download/v0.5.2/kubernetes.tar.gz [root@kubernetes kubernetes]# wget https://github.com/coreos/etcd/releases/download/v0.4.6/etcd-v0.4.6-linux-amd64.tar.gz
而后解压下载的kubernetes和etcd包,并在kubernetes、minion一、minion2上建立目录/opt/kubernetes/bin,
[root@kubernetes kubernetes]# mkdir -p /opt/kubernetes/bin [root@kubernetes kubernetes]# tar xf kubernetes.tar.gz [root@kubernetes kubernetes]# tar xf etcd-v0.4.6-linux-amd64.tar.gz [root@kubernetes kubernetes]# cd ~/kubernetes/server [root@kubernetes server]# tar xf kubernetes-server-linux-amd64.tar.gz [root@kubernetes kubernetes]# /tmp/kubernetes/kubernetes/server/kubernetes/server/bin
复制kube-apiserver,kube-controller-manager,kube-scheduler,kubecfg到kubernetes的/opt/kubernetes/bin目录下,而kubelet,kube-proxy则复制到minion1和minion2的/opt/kubernetes/bin,并确保都是可执行的。
[root@kubernetes amd64]# cp kube-apiserver kube-controller-manager kubecfg kube-scheduler /opt/kubernetes/bin [root@kubernetes amd64]# scp kube-proxy kubelet root@192.168.230.4:/opt/kubernetes/bin [root@kubernetes amd64]# scp kube-proxy kubelet root@192.168.230.5:/opt/kubernetes/bin
为了简单咱们只部署一台etcd服务器,若是须要部署etcd的集群,请参考官方文档,在本文中将其跟Kubernetes APIServer部署同一台机器上,并且将etcd放置在/opt/kubernetes/bin下,etcdctl跟ectd同一目录。
[root@kubernetes kubernetes]# cd /tmp/kubernetes/etcd-v0.4.6-linux-amd64 [root@kubernetes etcd-v0.4.6-linux-amd64]# cp etcd etcdctl /opt/kubernetes/bin
需注意的是kubernetes和minion上/opt/kubernetes/bin目录下的文件都必须是可执行的。到目前,咱们准备工做已经差很少,如今开始给apiserver,controller-manager,scheduler,etcd配置unit文件。首先咱们用以下脚本etcd.sh配置etcd的unit文件,
#!/bin/sh ETCD_PEER_ADDR=192.168.230.3:7001 ETCD_ADDR=192.168.230.3:4001 ETCD_DATA_DIR=/var/lib/etcd ETCD_NAME=kubernetes ! test -d $ETCD_DATA_DIR && mkdir -p $ETCD_DATA_DIR cat <<EOF >/usr/lib/systemd/system/etcd.service [Unit] Description=Etcd Server [Service] ExecStart=/opt/kubernetes/bin/etcd \\ -peer-addr=$ETCD_PEER_ADDR \\ -addr=$ETCD_ADDR \\ -data-dir=$ETCD_DATA_DIR \\ -name=$ETCD_NAME \\ -bind-addr=0.0.0.0 [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable etcd systemctl start etcd
对剩下的apiserver,controller-manager,scheduler的unit文件配置的脚本,能够在github 上GetStartingKubernetes找到,在此就不一一列举。运行相应的脚本后,在APIServer上etcd, apiserver, controller-manager, scheduler服务就能正常运行。
根据Kubernetes的设计架构,须要在minion上部署docker, kubelet, kube-proxy,在4.2节部署APIServer时,咱们已经将kubelet和kube-proxy已经分发到两minion上,因此只需配置docker,kubelet,proxy的unit文件,而后启动服务就便可,具体配置见GetStartingKubernetes。
为了方便,咱们使用Kubernetes提供的例子Guestbook来演示Kubernetes管理跨机器运行的容器,下面咱们根据Guestbook的步骤建立容器及服务。在下面的过程当中若是是第一次操做,可能会有必定的等待时间,状态处于pending,这是由于第一次下载p_w_picpaths须要一段时间。
[root@kubernetes ~]# cd /tmp/kubernetes/kubernetes/examples/guestbook [root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 -c redis-master.json create pods [root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 -c redis-master-service.json create services
完成上面的操做后,咱们能够看到以下redis-master Pod被调度到192.168.230.4。
[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 list pods Name Image(s) Host Labels Status ---------- ---------- ---------- ---------- ---------- redis-master dockerfile/redis 192.168.230.4/ name=redis-master Running
但除了发现redis-master的服务以外,还有两个Kubernetes系统默认的服务kubernetes-ro和kubernetes。并且咱们能够看到每一个服务都有一个服务IP及相应的端口,对于服务IP,是一个虚拟地址,根据apiserver的portal_net选项设置的CIDR表示的IP地址段来选取,在咱们的集群中设置为10.10.10.0/24。为此每新建立一个服务,apiserver都会在这个地址段中随机选择一个IP做为该服务的IP地址,而端口是事先肯定的。对redis-master服务,其服务地址为10.10.10.206,端口为6379。
[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 list services Name Labels Selector IP Port ---------- ---------- ---------- ---------- ---------- kubernetes-ro component=apiserver,provider=kubernetes 10.10.10.207 80 redis-master name=redis-master name=redis-master 10.10.10.206 6379 kubernetes component=apiserver,provider=kubernetes 10.10.10.161 443
[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 -c redis-slave-controller.json create replicationControllers [root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 -c redis-slave-service.json create services
而后经过list命令可知新建的redis-slave Pod根据调度算法调度到两台minion上,服务IP为10.10.10.92,端口为6379
[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 list pods Name Image(s) Host Labels Status ---------- ---------- ---------- ---------- ---------- redis-master dockerfile/redis 192.168.230.4/ name=redis-master Running 8c0ddbda-728c-11e4-8233-000c297db206 brendanburns/redis-slave 192.168.230.5/ name=redisslave,uses=redis-master Running 8c0e1430-728c-11e4-8233-000c297db206 brendanburns/redis-slave 192.168.230.4/ name=redisslave,uses=redis-master Running [root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 list services Name Labels Selector IP Port ---------- ---------- ---------- ---------- ---------- redisslave name=redisslave name=redisslave 10.10.10.92 6379 kubernetes component=apiserver,provider=kubernetes 10.10.10.161 443 kubernetes-ro component=apiserver,provider=kubernetes 10.10.10.207 80 redis-master name=redis-master name=redis-master 10.10.10.206 6379
在建立以前修改frontend-controller.json的Replicas数量为2,这是由于咱们的集群中只有2台minion,若是按照frontend-controller.json的Replicas默认值3,那会致使有2个Pod会调度到同一台minion上,产生端口冲突,有一个Pod会一直处于pending状态,不能被调度。
[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 -c frontend-controller.json create replicationControllers [root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 -c frontend-service.json create services
经过查看可知Frontend Pod也被调度到两台minion,服务IP为10.10.10.220,端口是80。
[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 list pods Name Image(s) Host Labels Status ---------- ---------- ---------- ---------- ---------- redis-master dockerfile/redis 192.168.230.4/ name=redis-master Running 8c0ddbda-728c-11e4-8233-000c297db206 brendanburns/redis-slave 192.168.230.5/ name=redisslave,uses=redis-master Running 8c0e1430-728c-11e4-8233-000c297db206 brendanburns/redis-slave 192.168.230.4/ name=redisslave,uses=redis-master Running a880b119-7295-11e4-8233-000c297db206 brendanburns/php-redis 192.168.230.4/ name=frontend,uses=redisslave,redis-master Running a881674d-7295-11e4-8233-000c297db206 brendanburns/php-redis 192.168.230.5/ name=frontend,uses=redisslave,redis-master Running [root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 list services Name Labels Selector IP Port ---------- ---------- ---------- ---------- ---------- kubernetes-ro component=apiserver,provider=kubernetes 10.10.10.207 80 redis-master name=redis-master name=redis-master 10.10.10.206 6379 redisslave name=redisslave name=redisslave 10.10.10.92 6379 frontend name=frontend name=frontend 10.10.10.220 80 kubernetes component=apiserver,provider=kubernetes 10.10.10.161 443
除此以外,你能够删除Pod、Service及更新ReplicationController的Replicas数量等操做,如删除Frontend服务:
[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 delete services/frontend Status ---------- Success
还能够更新ReplicationController的Replicas的数量,下面是更新Replicas以前ReplicationController的信息。
[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 list replicationControllers Name Image(s) Selector Replicas ---------- ---------- ---------- ---------- redisSlaveController brendanburns/redis-slave name=redisslave 2 frontendController brendanburns/php-redis name=frontend 2
如今咱们想把frontendController的Replicas更新为1,则这行以下命令,而后再经过上面的命令查看frontendController信息,发现Replicas已变为1。
[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 resize frontendController 1 [root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 list replicationControllers Name Image(s) Selector Replicas ---------- ---------- ---------- ---------- redisSlaveController brendanburns/redis-slave name=redisslave 2 frontendController brendanburns/php-redis name=frontend 1
完成上面的操做后,咱们来看当前Kubernetes集群中运行着的Pod信息。
[root@kubernetes guestbook]# kubecfg -h http://192.168.230.3:8080 list pods Name Image(s) Host Labels Status ---------- ---------- ---------- ---------- ---------- a881674d-7295-11e4-8233-000c297db206 brendanburns/php-redis 192.168.230.5/ name=frontend,uses=redisslave,redis-master Running redis-master dockerfile/redis 192.168.230.4/ name=redis-master Running 8c0ddbda-728c-11e4-8233-000c297db206 brendanburns/redis-slave 192.168.230.5/ name=redisslave,uses=redis-master Running 8c0e1430-728c-11e4-8233-000c297db206 brendanburns/redis-slave 192.168.230.4/ name=redisslave,uses=redis-master Running
经过上面的结果可知当前提供前端服务的PHP和提供数据存储的后端服务Redis master的Pod分别运行在192.168.230.5和192.168.230.4上,即容器运行在不一样主机上,还有Redis slave也运行在两台不一样的主机上,它会从Redis master同步前端写入Redis master的数据。下面咱们从两方面验证Kubernetes能提供跨机器间容器的通讯:
在浏览器打开http://${IP_Address}:8000,IP_Address为PHP容器运行的minion的IP地址,其暴漏的端口为8000,这里IP_Address为192.168.230.5。打开浏览器会显示以下信息:
你能够输入信息并提交,如"Hello Kubernetes"、"Container",而后Submit按钮下方会显示你输入的信息。
因为前端PHP容器和后端Redis master容器分别在两台minion上,所以PHP在访问Redis master服务时必定得跨机器通讯,可见Kubernetes的实现方式避免了用link只能在同一主机上实现容器间通讯的缺陷,对于Kubernetes跨机器通讯的实现方法,之后我会详细介绍。
从上面的结果,可得知已经实现了跨机器的通讯,如今咱们从后端数据层验证不一样机器容器间的通讯。根据上面的输出结果发现Redis slave和Redis master分别调度到两台不一样的minion上,在192.168.230.4主机上执行docker exec -ti c41711cc8971 /bin/sh,c41711cc8971是Redis master的容器ID,进入容器后经过redis-cli命令查看从浏览器输入的信息以下:
若是咱们在192.168.230.5上运行的Redis slave容器里查到跟Redis master容器里相同的信息,那说明Redis master和Redis slave之间的数据同步正常工做,下面是从192.168.230.5上运行的Redis slave容器查询到的信息:
因而可知Redis master和Redis slave之间数据同步正常,OVS GRE隧道技术使得跨机器间容器正常通讯。
本文主要介绍如何在本地环境部署Kubernetes集群和演示如何经过Kubernetes管理集群中运行的容器,并经过OVS管理集群不一样minion的Pod之间的网络通讯。接下来会对Kubernetes各个组件源码进行详细分析,阐述Kubernetes的工做原理。
杨章显,现就任于Cisco,主要从事WebEx SaaS服务运维,系统性能分析等工做。特别关注云计算,自动化运维,部署等技术,尤为是Go、OpenvSwitch、Docker及其生态圈技术,如Kubernetes、Flocker等Docker相关开源项目。Email: yangzhangxian@gmail.com
https://n40lab.wordpress.com/2014/09/04/openvswitch-2-3-0-lts-and-centos-7/
https://github.com/GoogleCloudPlatform/kubernetes/tree/master/examples/guestbook
本文转载自InfoQ: http://www.infoq.com/cn/articles/centos7-practical-kubernetes-deployment