本文經過實際操做來演示Kubernetes的使用,由於環境有限,集羣部署在本地3個ubuntu上,主要包括以下內容:php
關於 Kubernetes 系統架構及組件介紹見這裏。前端
Role | Hostname | IP Address |
---|---|---|
APIServer | kubernetes | 172.29.88.206 |
Minion | minion1 | 172.29.88.207 |
Minion | minion2 | 172.29.88.208 |
在詳細介紹部署Kubernetes集羣前,先給你們展現下集羣的邏輯架構。從下圖可知,整個系統分爲兩部分,第一部分是Kubernetes APIServer,是整個系統的核心,承擔集羣中全部容器的管理工做;第二部分是minion,運行Container Daemon,是全部容器棲息之地,同時在minion上運行Open vSwitch程序,經過GRE Tunnel負責minions之間Pod的網絡通訊工做。
node
爲了解決跨minion之間Pod的通訊問題,咱們在每一個minion上安裝Open vSwtich,並使用GRE或者VxLAN使得跨機器之間P11od能相互通訊,本文使用GRE,而VxLAN一般用在須要隔離的大規模網絡中。對於Open vSwitch的介紹請參考另外一篇文章Open vSwitch。linux
sudo apt-get install openvswitch-switch bridge-utils
安裝完Open vSwitch和橋接工具後,接下來便創建minion0和minion1之間的隧道。首先在minion1和minion2上分別創建OVS Bridge:git
# ovs-vsctl add-br obr0
接下來創建gre,並將新建的gre0添加到obr0,在minion1上執行以下命令:github
# ovs-vsctl add-port obr0 gre0 -- set Interface gre0 type=gre options:remote_ip=172.29.88.208
上面的remoute_ip是另外一臺服務minion2上的對外IP。golang
在minion2上執行:redis
# ovs-vsctl add-port obr0 gre0 -- set Interface gre0 type=gre options:remote_ip=172.29.88.207
至此,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上執行:docker
# brctl addbr kbr0 //建立linux bridge代替docker0 # brctl addif kbr0 obr0 //添加obr0爲kbr0的接口 # ip link set dev docker0 down //設置docker0爲down狀態 # ip link del dev docker0 //刪除docker0,可選
查看這些接口的狀態:json
# service openvswitch-switch status # ovs-vsctl show 9d248403-943c-41c0-b2d0-3f9b130cdd3f Bridge "obr0" Port "gre0" Interface "gre0" type: gre options: {remote_ip="172.29.88.207"} Port "obr0" Interface "obr0" type: internal ovs_version: "2.0.2" # brctl show bridge name bridge id STP enabled interfaces docker0 8000.56847afe9799 no kbr0 8000.620ff7ee9c49 no obr0
爲了使新建的kbr0在每次系統重啓後任然有效,咱們在minion1的/etc/network/interfaces
文件中追加內容以下:(在CentOS上會有些不同)
# vi /etc/network/interfaces auto kbr0 iface kbr0 inet static address 172.17.1.1 netmask 255.255.255.0 gateway 172.17.1.0 dns-nameservers 172.31.1.1
一樣在minion2上追加相似內容,只需修改address爲172.17.2.1和gateway爲172.17.2.0便可,而後執行ip link set dev kbr0 up
,你能在minion1和minion2上發現kbr0都設置了相應的IP地址。爲了驗證咱們建立的隧道是否能通訊,咱們在minion1和minion2上相互ping對方kbr0的IP地址,從下面的結果發現是不通的,經查找這是由於在minion1和minion2上缺乏訪問172.17.1.1和172.17.2.1的路由,所以咱們須要添加路由保證彼此之間能通訊:
minion1上執行: # ip route add 172.17.2.0/24 via 172.29.88.208 dev eth0 minion2上執行: # ip route add 172.17.1.0/24 via 172.29.88.207 dev eth0
如今能夠ping通對方的虛擬網絡了:
$ ping 172.17.2.1 PING 172.17.2.1 (172.17.2.1) 56(84) bytes of data. 64 bytes from 172.17.2.1: icmp_seq=1 ttl=64 time=0.334 ms 64 bytes from 172.17.2.1: icmp_seq=2 ttl=64 time=0.253 ms ^C --- 172.17.2.1 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 999ms rtt min/avg/max/mdev = 0.253/0.293/0.334/0.043 ms
下面安裝 Kubernetes APIServer 及kubelet、proxy等服務。
能夠本身從源碼編譯kubernetes(須要安裝golang環境),也能夠從GitHub Kubernetes repo release page.選擇編譯好的二進制版本(v0.7.2)下載,爲了方便後面啓動或關閉kubernetes組件,咱們同時下載二進制包和源碼包:
# cd /usr/local/src # wget https://github.com/coreos/etcd/releases/download/v2.0.0-rc.1/etcd-v2.0.0-rc.1-linux-amd64.tar.gz # wget https://github.com/GoogleCloudPlatform/kubernetes/releases/download/v0.7.2/kubernetes.tar.gz # wget https://github.com/GoogleCloudPlatform/kubernetes/archive/v0.7.2.zip
而後解壓下載的kubernetes和etcd包,並在kubernetes(minion1)、minion2上建立目錄/opt/bin
# mkdir /opt/bin //這一步APIserver和全部minions上都要建立 解壓kubernetes src# tar xf kubernetes.tar.gz # ll drwxr-xr-x 3 501 staff 4096 Dec 19 02:32 etcd-v2.0.0-rc.1-linux-amd64/ -rw-r--r-- 1 root root 6223584 Jan 6 14:39 etcd-v2.0.0-rc.1-linux-amd64.tar.gz drwxr-xr-x 7 root root 4096 Nov 20 06:35 kubernetes/ -rw-r--r-- 1 root root 82300483 Jan 6 14:37 kubernetes.tar.gz -rw-r--r-- 1 root root 9170754 Jan 9 14:47 v0.7.2.zip # cd kubernetes/server # tar xf kubernetes-server-linux-amd64.tar.gz # cd kubernetes/server/bin/ APIserver自己須要的是kube-apiserver kube-scheduler kube-controller-manager kubecfg四個 # cp -a kube* /opt/bin/ 把proxy和kubelet複製到其餘minions,確保這些文件都是可執行的 # scp kube-proxy kubelet root@172.29.88.207:/opt/bin # scp kube-proxy kubelet root@172.29.88.208:/opt/bin
/opt/bin
並無加入系統PATH
,因此kube-apiserver -version
是看不到結果,但在後面配置的服務中會自動加入(PATH=$PATH:/opt/bin
)。
etcd
在這裏的做用是服務發現存儲倉庫,通俗的來說就是記錄kubernetes啓動了多少pods、services、replicationController以及它們的信息等,詳細介紹見這裏。此外版本2.0與v0.4.6在啓動參數上的寫法有必定差異。
# tar xf etcd-v2.0.0-rc.1-linux-amd64.tar.gz && cd etcd-v2.0.0-rc.1-linux-amd64/ # cp -a etcd etcdctl /opt/bin
這一步主要是爲了管理kube-apiserver等進程的方便,避免每次都手動啓動各服務、添加冗長的啓動參數選項,並且在不一樣的系統平臺下kubernetes已經提供了相應的工具。
解壓kubernetes*源碼包* src# unzip xf v0.7.2.zip && cd kubernetes-0.7.2 這裏比較奇怪的是最新release版本源碼的cluster目錄下是有ubuntu子目錄的,但latest以前的下載後沒有ubuntu目錄 # cd cluster/ubuntu # ll .. 2 root root 4096 Jan 8 17:39 default_scripts/ 各組件默認啓動參數 .. 2 root root 4096 Jan 8 17:39 init_conf/ upstart啓動方式 .. 2 root root 4096 Jan 8 17:39 initd_scripts/ service啓動方式,與upstart選其一 .. 1 root root 1213 Jan 8 08:53 util.sh* # ./util.sh
util.sh
腳本就是把當前目錄下的service/upstart腳本、默認參數配置文件複製到/etc
下,能夠經過service etcd start
的形式管理kubernetes。因爲kubernetes更新速度極快,項目的文件和目錄結構常常變化,請找準文件。接下來咱們須要修改那些只適合本機使用的默認參數。(請注意備份先,由於後面可否正常跨機器管理docker與這些選項有關,特別是IP)
etcd官方建議使用新的2379端口代替4001 # vi /etc/default/etcd ETCD_OPTS="-listen-client-urls=http://0.0.0.0:4001" # vi /etc/default/kube-apiserver KUBE_APISERVER_OPTS="--address=0.0.0.0 \ --port=8080 \ --etcd_servers=http://127.0.0.1:4001 \ --logtostderr=true \ --portal_net=11.1.1.0/24" # vi /etc/default/kube-scheduler KUBE_SCHEDULER_OPTS="--logtostderr=true \ --master=127.0.0.1:8080" # vi /etc/default/kube-controller-manager KUBE_CONTROLLER_MANAGER_OPTS="--master=127.0.0.1:8080 \ --machines=172.29.88.207,172.29.88.208 \ --logtostderr=true" * 複製kubelet、kube-proxy等到minion1: # scp /etc/default/{kubelet,kube-proxy} 172.29.88.207:/etc/default/ # scp /etc/init.d/{kubelet,kube-proxy} 172.29.88.207:/etc/init.d/ # scp /etc/init/{kubelet.conf,kube-proxy.conf} 172.29.88.207:/etc/init/
* 在minion1端進行 # vi /etc/default/kubelet KUBELET_OPTS="--address=172.29.88.207 \ --port=10250 \ --hostname_override=172.29.88.207 \ --etcd_servers=http://172.29.88.206:4001 \ --logtostderr=true" # vi /etc/default/kube-proxy KUBE_PROXY_OPTS="--etcd_servers=http://172.29.88.207:4001 \ --logtostderr=true" (對minion2重複上面 * 兩個步驟,把上面.207改爲.208)
上面的各配置文件就是對應命令的選項,具體含義使用-h
。這裏只簡單說明:
etcd
服務APIserver和minions都要訪問,也就是其餘組件的--etcd_servers
值(帶http前綴)kube-apiserver
監聽在8080端口,也就是其餘組件的--master
值;--portal_net
地址段不能與docker的橋接網卡kbr0重複,指定docker容器的IP段etcd
、kube-apiserver
、kube-scheduler
、kube-controller-manager
運行在apiserver(服務)端,kubelet
、kube-proxy
運行在minion(客戶端)kube-controller-manager
使用預先定義pod模板建立pods,保證指定數量的replicas在運行,默認監聽在master的127.0.0.1:10252kubelet
默認監聽端口10250,也正是apiserver的--kubelet_port
的值重啓docker
接下來重啓minion一、minion2上的Docker daemon(注意使用的網橋):
# docker -d -b kbr0
因爲後面的測試可能須要在線下載images,因此若是你的服務器沒法訪問docker hub,上面啓動時記得設置HTTP_PROXY
代理。
啓動apiserver
# service etcd start # service kube-apiserver start
kube-apiserver
啓動後會自動運行kube-scheduler
、kube-controller-manager
,但修改配置後依然能夠單獨重啓各個服務如service kube-contoller-manager restart
。這些服務的日誌能夠從/var/log/upstart/kube*
找到。
在minion一、minion2上啓動kubelet、kube-proxy:
# service kubelet start # service kube-proxy start
爲了方便,咱們使用Kubernetes提供的例子Guestbook(下載的源碼example目錄下能夠找到)來演示Kubernetes管理跨機器運行的容器,下面咱們根據Guestbook的步驟建立容器及服務。在下面的過程當中若是是第一次操做,可能會有必定的等待時間,狀態處於pending,這是由於第一次下載images須要一段時間。
配置管理操做都在apiserver上執行,而且都是基於實現編寫好的json格式。涉及到下載docker鏡像的部分,若是沒有外網,可能須要修改image的值或使用本身搭建的docker-registry:
# cd kubernetes-0.7.2/examples/guestbook/ # cat redis-master.json { "id": "redis-master", "kind": "Pod", "apiVersion": "v1beta1", "desiredState": { "manifest": { "version": "v1beta1", "id": "redis-master", "containers": [{ "name": "master", "image": "dockerfile/redis", "cpu": 100, "ports": [{ "containerPort": 6379, "hostPort": 6379 }] }] } }, "labels": { "name": "redis-master" } } # kubecfg -h http://172.29.88.206:8080 -c redis-master.json create pods # kubecfg -h http://172.29.88.206:8080 -c redis-master-service.json create services
完成上面的操做後,咱們能夠看到以下redis-master Pod被調度到172.29.88.207:
(下面直接list其實是省略了-h http://127.0.0.1:8080
)
# kubecfg list pods Name Image(s) Host Labels Status ---------- ---------- ---------- ---------- ---------- redis-master dockerfile/redis 172.29.88.207/ name=redis-master Running 查看services: # kubecfg list services Name Labels Selector IP Port ---------- ---------- ---------- ---------- ------ kubernetes component=apiserver,provider=kubernetes 11.1.1.233 443 kubernetes-ro component=apiserver,provider=kubernetes 11.1.1.204 80 redis-master name=redis-master name=redis-master 11.1.1.175 6379
發現除了redis-master的服務以外,還有兩個Kubernetes系統默認的服務kubernetes-ro和kubernetes。並且咱們能夠看到每一個服務都有一個服務IP及相應的端口,對於服務IP,是一個虛擬地址,根據apiserver的portal_net
選項設置的CIDR
表示的IP地址段來選取,在咱們的集羣中設置爲11.1.1.0/24。爲此每新建立一個服務,apiserver都會在這個地址段中隨機選擇一個IP做爲該服務的IP地址,而端口是事先肯定的。對redis-master服務,其服務地址爲11.1.1.175,端口爲6379,與minion主機映射的端口也是6379。
# kubecfg -h http://172.29.88.206:8080 -c redis-slave-controller.json create replicationControllers # kubecfg -h http://172.29.88.206:8080 -c redis-slave-service.json create services
注意上面的redis-slave-controller.json
有個"replicas": 2
、"hostPort": 6380
,由於咱們的集羣中只有2個minions,若是爲3的話,就會致使有2個Pod會調度到同一臺minion上,產生端口衝突,有一個Pod會一直處於pending狀態,不能被調度(能夠經過日誌看到緣由)。
# kubecfg list pods Name Image(s) Host Labels Status ---------- ---------- ---------- ---------- -------- 2c2a06...c2971614d brendanburns/redis-slave 172.29.88.208/ name=redisslave,uses=redis-master Running 2c2ad5...c2971614d brendanburns/redis-slave 172.29.88.207/ name=redisslave,uses=redis-master Running redis-master dockerfile/redis 172.29.88.207/ name=redis-master Running # kubecfg list services Name Labels Selector IP Port ---------- ---------- ---------- ---------- -------- kubernetes component=apiserver,provider=kubernetes 11.1.1.233 443 kubernetes-ro component=apiserver,provider=kubernetes 11.1.1.204 80 redis-master name=redis-master name=redis-master 11.1.1.175 6379 redisslave name=redisslave name=redisslave 11.1.1.131 6379
前面2步都是guestbook的redis數據存儲,如今部署應用:(修改frontend-controller.json
的replicas
爲2)
# kubecfg -h http://172.29.88.206:8080 -c frontend-controller.json create replicationControllers # kubecfg -h http://172.29.88.206:8080 -c frontend-service.json create services
# kubecfg -h http://172.29.88.206:8080 list pods Name Image(s) Host Labels Status ---------- ---------- ---------- ---------- ---------- 2c2a06...c2971614d brendanburns/redis-slave 172.29.88.208/ name=redisslave,uses=redis-master Running 2c2ad5...c2971614d brendanburns/redis-slave 172.29.88.207/ name=redisslave,uses=redis-master Running d87744...c2971614d kubernetes/example-guestbook-php-redis 172.29.88.207/ name=frontend,uses=redisslave,redis-master Running redis-master dockerfile/redis 172.29.88.207/ name=redis-master Running 1370b9...c2971614d kubernetes/example-guestbook-php-redis 172.29.88.208/ name=frontend,uses=redisslave,redis-master Running # kubecfg -h http://172.29.88.206:8080 list services Name Labels Selector IP Port ---------- ---------- ---------- ---------- ------ redis-master name=redis-master name=redis-master 11.1.1.175 6379 redisslave name=redisslave name=redisslave 11.1.1.131 6379 frontend name=frontend name=frontend 11.1.1.124 80 kubernetes component=apiserver,provider=kubernetes 11.1.1.233 443 kubernetes-ro component=apiserver,provider=kubernetes 11.1.1.204 80 <pre><code>經過查看可知 Frontend Pod 也被調度到兩臺minion,服務IP爲11.1.1.124,端口是80,映射到外面minions的端口爲8000(能夠經過`ps -ef|grep docker-proxy`發現)。 ### 4.4 其餘操做(更新、刪除、查看) ## **刪除** 除此以外,你能夠刪除Pod、Service,如刪除minion1上的redis-slave Pod: kubecfg -h http://172.29.88.206:8080 delete pods/2c2ad505-96fd-11e4-9c0b-000c2971614d Status ---------- Success 格式爲`services/服務Name`、`pods/pods名字`,沒必要關心從哪一個minion上刪除了。須要提醒的是,這裏pods的replcas爲2,因此即便刪除了這個pods,kubernetes爲自動爲你從新啓動一個。 **更新** 更新ReplicationController的Replicas數量: </code></pre> # kubecfg list replicationControllers Name Image(s) Selector Replicas ---------- ---------- ---------- ---------- frontendController kubernetes/example-guestbook-php-redis name=frontend 2 redisSlaveController brendanburns/redis-slave name=redisslave 2 <pre><code>把frontendController的Replicas更新爲1,則這行以下命令,而後再經過上面的命令查看frontendController信息,發現Replicas已變爲1: kubecfg -h http://172.29.88.206:8080 resize frontendController 1 **查看** Kubernetes內置提供了一個簡單的UI來查看pods、services、replicationControllers,但極其簡陋,暫時能夠忽略,訪問`http://172.29.88.206:8080/static/#/groups//selector/`: ![kubernetes-simpleui][5] 在瀏覽器訪問api:`http://172.29.88.206:8080/api/v1beta1/replicationControllers` 。 ![kubernetes-api][2] etcd作服務發現,能夠經過api訪問其內容,訪問`http://172.29.88.206:4001/v2/keys/registry/services/endpoints/default` ,獲得json格式數據。 ### 4.5 演示guestbook ## 經過上面的結果可知當前提供前端服務的PHP和提供數據存儲的後端服務Redis master的Pod分別運行在172.29.88.208和172.29.88.207上,即容器運行在不一樣主機上,還有Redis slave也運行在兩臺不一樣的主機上,它會從Redis master同步前端寫入Redis master的數據。下面咱們從兩方面驗證Kubernetes能提供跨機器間容器的通訊: **瀏覽器訪問留言簿** 在瀏覽器打開`http://${IPAddress}:8000`,IPAddress爲PHP容器運行的minion的IP地址,其暴漏的端口爲8000,這裏IP_Address爲172.29.88.208。打開瀏覽器會顯示以下信息: ![kubernetes-guestbook1][3] 你能夠輸入信息並提交,而後Submit按鈕下方會顯示你輸入的信息: ![kubernetes-guestbook2][4] 因爲前端PHP容器和後端Redis master容器分別在兩臺minion上,所以PHP在訪問Redis master服務時必定得跨機器通訊,可見Kubernetes的實現方式避免了用link只能在同一主機上實現容器間通訊的缺陷。 **從redis後端驗證** 咱們從後端數據層驗證不一樣機器容器間的通訊。根據上面的輸出結果發現Redis slave和Redis master分別調度到兩臺不一樣的minion上,在172.29.88.207主機上執行`docker exec -ti e5941db7e424 /bin/sh`,e5941db7e424 master的容器ID(`docker ps`),進入容器後經過redis-cli命令查看從瀏覽器輸入的信息以下: </code></pre> # docker exec -ti e5941db7e424 /bin/sh # redis-cli 127.0.0.1:6379> keys * 1) "messages" 127.0.0.1:6379> get messages ",Hi, Sean,Kubernetes,,llll,abc,\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd\xd4\xb0\xef\xbf\xbd,sync info,"
相似能夠在172.29.88.208的redis-slave上看到一樣的內容。因而可知Redis master和Redis slave之間數據同步正常,OVS GRE隧道技術使得跨機器間容器正常通訊。
F0319 16:56:08.058335 9960 kubecfg.go:438] Got request error: The requested resource does not exist.
參考
原文連接地址:http://seanlook.com/2015/02/07/docker-kubernetes-deploy2/