CentOS 7實戰Kubernetes部署

1. 前言

上一節我們闡述了Kubernetes的系統架構,讓大家對Kubernetes有一定的初步瞭解,但是就如何使用Kubernetes, 也許大家還不知如何下手。本文作者將帶領大家如何在本地部署、配置Kubernetes集羣網絡環境以及通過實例演示跨機器服務間的通信,主要包括如下內容:

  • 部署環境介紹

  • Kubernetes集羣邏輯架構

  • 部署Open vSwitch、Kubernetes、Etcd組件

  • 演示Kubernetes管理容器

2. 部署環境

  • VMware Workstation:10.0.3

  • VMware Workstation網絡模式:NAT

  • 操作系統信息:CentOS 7 64位

  • Open vSwitch版本信息:2.3.0

  • Kubernetes版本信息:0.5.2

  • Etcd版本信息:0.4.6

  • Docker版本信息:1.3.1

  • 服務器信息:

    RoleHostnameIP Address
    APIServerkubernetes192.168.230.3
    Minionminion1192.168.230.4
    Minionminion2192.168.230.5

3. Kubernetes集羣邏輯架構

在詳細介紹部署Kubernetes集羣前,先給大家展示下集羣的邏輯架構。從下圖可知,整個系統分爲兩部分,第一部分是Kubernetes APIServer,是整個系統的核心,承擔集羣中所有容器的管理工作;第二部分是minion,運行Container Daemon,是所有容器棲息之地,同時在minion上運行Open vSwitch程序,通過GRE Tunnel負責minion之間Pod的網絡通信工作。IlLltJJ.png

4. 部署Open vSwitch、Kubernetes、Etcd組件

4.1 安裝Open vSwitch及配置GRE

爲了解決跨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等服務。

4.2 安裝Kubernetes APIServer

在安裝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、minion1、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 [email protected]:/opt/kubernetes/bin
[root@kubernetes amd64]# scp kube-proxy kubelet [email protected]:/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服務就能正常運行。

4.3 安裝Kubernetes Kubelet及Proxy

根據Kubernetes的設計架構,需要在minion上部署docker, kubelet, kube-proxy,在4.2節部署APIServer時,我們已經將kubelet和kube-proxy已經分發到兩minion上,所以只需配置docker,kubelet,proxy的unit文件,然後啓動服務就即可,具體配置見GetStartingKubernetes

5. 演示Kubernetes管理容器

爲了方便,我們使用Kubernetes提供的例子Guestbook來演示Kubernetes管理跨機器運行的容器,下面我們根據Guestbook的步驟創建容器及服務。在下面的過程中如果是第一次操作,可能會有一定的等待時間,狀態處於pending,這是因爲第一次下載images需要一段時間。

5.1 創建redis-master Pod和redis-master服務

[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

5.2 創建redis-slave Pod和redis-slave服務

[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

5.3 創建Frontend Pod和Frontend服務

在創建之前修改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

5.4 演示跨機器服務通信

完成上面的操作後,我們來看當前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。打開瀏覽器會顯示如下信息:                                                                          
    3xkPnXN.png  
    你可以輸入信息並提交,如"Hello Kubernetes"、"Container",然後Submit按鈕下方會顯示你輸入的信息。LjqT1cH.png                                              
    由於前端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命令查看從瀏覽器輸入的信息如下:

    lutEj0V.png                                                              
    如果我們在192.168.230.5上運行的Redis slave容器裏查到跟Redis master容器裏相同的信息,那說明Redis master和Redis slave之間的數據同步正常工作,下面是從192.168.230.5上運行的Redis slave容器查詢到的信息:

    grIJeCk.png                  
    由此可見Redis master和Redis slave之間數據同步正常,OVS GRE隧道技術使得跨機器間容器正常通信。

6. 結論

本文主要介紹如何在本地環境部署Kubernetes集羣和演示如何通過Kubernetes管理集羣中運行的容器,並通過OVS管理集羣不同minion的Pod之間的網絡通信。接下來會對Kubernetes各個組件源碼進行詳細分析,闡述Kubernetes的工作原理。

7. 個人簡介

楊章顯,現就職於Cisco,主要從事WebEx SaaS服務運維,系統性能分析等工作。特別關注雲計算,自動化運維,部署等技術,尤其是Go、OpenvSwitch、Docker及其生態圈技術,如Kubernetes、Flocker等Docker相關開源項目。Email: [email protected]

8. 參考資料

  1. https://n40lab.wordpress.com/2014/09/04/openvswitch-2-3-0-lts-and-centos-7/

  2. https://github.com/GoogleCloudPlatform/kubernetes/tree/master/examples/guestbook


本文轉載自InfoQ: http://www.infoq.com/cn/articles/centos7-practical-kubernetes-deployment

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章