Kubernetes是啥?用它寫(xiě)個(gè)hello,world啊!
引子
現(xiàn)在微服務(wù)非常火,也帶火了 Docker。因?yàn)槲⒎?wù)很適合用 Docker 容器實(shí)現(xiàn),每個(gè)容器承載一個(gè)服務(wù)。一臺(tái)計(jì)算機(jī)同時(shí)運(yùn)行多個(gè)容器,從而就能很輕松地模擬出復(fù)雜的微服務(wù)架構(gòu)。于是乎 Docker 的人氣迅速攀升,速度之快,令人瞠目結(jié)舌。
就在 Docker 容器技術(shù)被炒得熱火朝天之時(shí),大家發(fā)現(xiàn),如果想要將 Docker 應(yīng)用于具體的業(yè)務(wù)實(shí)現(xiàn),是存在困難的——編排、管理和調(diào)度等各個(gè)方面,都不容易。于是,人們迫切需要一套管理系統(tǒng),對(duì) Docker 及容器進(jìn)行更高級(jí)更靈活的管理。
就在這個(gè)時(shí)候,K8S 出現(xiàn)了。
K8S,就是基于容器的集群管理平臺(tái),它的全稱,是kubernetes。
Kubernetes 是谷歌開(kāi)源的 Docker 容器集群管理系統(tǒng),主要為容器化的服務(wù)提供資源調(diào)度、擴(kuò)容、縮容以及部署等功能。
其實(shí)從 Kuberbetes 就可以看出了它的用途,這個(gè)單詞源于古希臘,意思是舵手,Docker的 logo 是一條鯨魚(yú),那么 Kubernetes 就是鯨魚(yú)賴以生存的地方-海洋的領(lǐng)導(dǎo)者;它誕生的時(shí)間有點(diǎn)晚,15 年 7 月份才出現(xiàn)第一個(gè)版本,不過(guò)一出生就大受歡迎,很多包括 IBM、紅帽、微軟等巨頭都紛紛參與進(jìn)來(lái)。
下面就帶你認(rèn)識(shí)一下 Kubernetes,并用他來(lái)實(shí)現(xiàn)革命性的hello,world!
Kubernetes一直被雪藏的前身
過(guò)去十幾年,谷歌一直有個(gè)秘密武器:Borg。Borg 一直以來(lái)都是谷歌內(nèi)部使用的大規(guī)模集群管理系統(tǒng),Borg 是基于容器技術(shù)發(fā)展起來(lái)的,主要還是實(shí)現(xiàn)資源管理的自動(dòng)化和在跨多個(gè)數(shù)據(jù)中心的背景下的提高資源的利用率,谷歌一直視 Borg 為傳家寶,哪怕員工離職都不能透漏給外界,直到 2015 年谷歌才公開(kāi),也就是說(shuō) Kubernetes 其實(shí)是 Borg 的一個(gè)開(kāi)源版本。
使用Kubernetes?給我一個(gè)理由!
第一,方便。如果我們的系統(tǒng)設(shè)計(jì)遵循了 Kubernetes 的設(shè)計(jì)思想,那么傳統(tǒng)系統(tǒng)架構(gòu)中與業(yè)務(wù)沒(méi)有什么關(guān)系的底層代碼、功能模塊之類的我們都可以不用考慮了,我們不用再把精力耗費(fèi)在負(fù)載均衡器的選型和部署實(shí)施等問(wèn)題,也不用考慮引入甚至是自己開(kāi)發(fā)一個(gè)復(fù)雜的服務(wù)治理框架,更不用為這些頭疼了:服務(wù)監(jiān)控、故障處理等??傊?,Kubernetes 就是解放我們的精力的,好讓我們更加專注于業(yè)務(wù)本身來(lái)做開(kāi)發(fā)。
第二,開(kāi)放。Kubernetes 可以兼容所有的語(yǔ)言,所有的編程接口也都能兼容,不管你用什么語(yǔ)言寫(xiě)的都可以映射為 Kubernetes 的 Service 以及通過(guò)標(biāo)準(zhǔn)的 TCP 通信協(xié)議進(jìn)行交互,更大好處是,現(xiàn)有的系統(tǒng)也可以改造升級(jí)并遷移到 Kubernetes 平臺(tái)上;
第三,強(qiáng)大。經(jīng)過(guò)十幾年的發(fā)展,Kubernetes 已經(jīng)成為了非常完備的分布式系統(tǒng)支撐平臺(tái),擁有極其強(qiáng)大的集群管理能力:多層次的安全防護(hù)和準(zhǔn)入機(jī)制、多租戶應(yīng)用支撐能力、透明的服務(wù)注冊(cè)和服務(wù)發(fā)現(xiàn)機(jī)制、內(nèi)建智能負(fù)載均衡器、還能夠及時(shí)發(fā)現(xiàn)故障并自我修復(fù)、服務(wù)滾動(dòng)升級(jí)和在線擴(kuò)容能力、可擴(kuò)展的資源自動(dòng)調(diào)度機(jī)制、多粒度的資源配額管理……太多了,不一而足!
IT 我們都知道技術(shù)更新?lián)Q代快得比你換衣服都快,Docker 這個(gè)容器化技術(shù)的明星已經(jīng)如此普及,從單機(jī)到集群這已經(jīng)是個(gè)不可逆轉(zhuǎn)的大趨勢(shì),云計(jì)算也是如火如荼的進(jìn)行著,Kubernetes 是業(yè)界公認(rèn)的目前為止唯一一個(gè) Docker 分布式系統(tǒng)解決方案。
開(kāi)始之前你總得知道這些!
不過(guò)先別著急,再開(kāi)始之前你總得先有點(diǎn)知識(shí)儲(chǔ)備才行,就像學(xué)習(xí) Java 的時(shí)候也不是上來(lái)就寫(xiě)hello,world而是先學(xué)一些與或非、數(shù)據(jù)類型等知識(shí)才開(kāi)始。
在 Kubernetes 中 Service 就是分布式集群架構(gòu)的核心,一個(gè) Service 具有一下幾個(gè)關(guān)鍵的特征:
擁有一個(gè)位置指定的名字,就如同數(shù)據(jù)庫(kù)中的主鍵; 擁有一個(gè)虛擬的 IP 和端口號(hào); 擁有提供遠(yuǎn)程服務(wù)的能力并能夠映射到提供這種服務(wù)的一組容器應(yīng)用上;
目前,Service 都是基于 Socket 通信方式或者是實(shí)現(xiàn)了某個(gè)具體業(yè)務(wù)的一個(gè)特定 TCP Server 進(jìn)程來(lái)提供服務(wù)的,雖然一個(gè) Service 通常都是由多個(gè)相關(guān)的服務(wù)進(jìn)程來(lái)提供服務(wù),而且每個(gè)服務(wù)進(jìn)程都有一個(gè)獨(dú)立的 EndPoint(IP + Port)訪問(wèn)點(diǎn),但是!但是 Kubernetes 可以讓我們通過(guò)虛擬 Cluster IP + Service Port 連接到指定的 Service上。
有了 Kubernetes 內(nèi)建的透明負(fù)載均衡和故障恢復(fù)機(jī)制,哪怕后端有再多的服務(wù)進(jìn)程,哪怕有再多的服務(wù)進(jìn)程會(huì)由于故障而重新部署到其他的機(jī)器,都不會(huì)影響到我們對(duì)服務(wù)的正常調(diào)用;
Kubernetes 一旦創(chuàng)建就不會(huì)再發(fā)生變化,這也意味著,在 Kubernetes 集群中我們?cè)僖膊挥脼榱?IP 地址的頻繁變動(dòng)而頭疼了。
容器的其中一個(gè)好處就是擁有強(qiáng)大的隔離功能,所以必須把為 Service 提供服務(wù)的這組進(jìn)程放到容器中進(jìn)行隔離,Kubernetes 的 Pod 對(duì)象就是干這事的,每個(gè)服務(wù)進(jìn)程包裝到相應(yīng)的 Pod 中使其成為 Pod 中運(yùn)行的一個(gè) Container(容器)。
為了建立 Service 和 Pod 之間的關(guān)聯(lián),Kubernetes 會(huì)給每個(gè) Pod 貼身一個(gè) Label(標(biāo)簽),然后給相應(yīng)的 Service 定義 Label Selector(標(biāo)簽選擇器)。
那么,Pod 又是個(gè)什么東東?
Pod 運(yùn)行在 Node(節(jié)點(diǎn))中,這個(gè)節(jié)點(diǎn)既可以是物理機(jī)也可以是公有云或者是私有云中的虛擬機(jī),通常一個(gè)節(jié)點(diǎn)上運(yùn)行著幾百個(gè) Pod。
每個(gè) Pod 中都運(yùn)行著一個(gè)叫做 Pause 的容器和一些業(yè)務(wù)容器,為了提高通信和數(shù)據(jù)交換的效率,這些業(yè)務(wù)容器共享 Pause 容器的網(wǎng)絡(luò)棧和 Volume 掛載卷,我們可以利用這個(gè)特性把一組密切相關(guān)的服務(wù)進(jìn)程放到同一個(gè) Pod 中。
不過(guò),有一點(diǎn)需要注意:不是每一個(gè) Pod 及其里面扥容器都能“映射”到一個(gè) Service 上,只要那些提供對(duì)外或者隊(duì)內(nèi)的服務(wù)的一組 Pod 才能“映射”成一個(gè)服務(wù)。
在集群管理方面,Kubernetes 把集群中的機(jī)器劃分成一個(gè) Master 節(jié)點(diǎn)和一群工作節(jié)點(diǎn),前者運(yùn)行著與集群管理相關(guān)的進(jìn)程,工作節(jié)點(diǎn)運(yùn)行著應(yīng)用程序。
在 Kubernetes 集群中,擴(kuò)容的話你只需要為與 Service 關(guān)聯(lián)的 Pod 創(chuàng)建一個(gè) Replication Controller,Replication Controller 文件至少包含一下信息:
目標(biāo) Pod 定義; 目標(biāo) Pod 需要運(yùn)行的副本數(shù)量; 要監(jiān)控的目標(biāo) Pod 的標(biāo)簽;
創(chuàng)建好 Replication Controller 后。Kubernetes 會(huì)通過(guò) Replication Controller 中定義的標(biāo)簽來(lái)篩選出對(duì)應(yīng)的Pod實(shí)例并實(shí)時(shí)監(jiān)控狀態(tài)和數(shù)量,如果實(shí)例數(shù)量少少于副本數(shù)量則會(huì)根據(jù) Replication Controller 中定義的 Pod 模板來(lái)創(chuàng)建一個(gè)新的 Pod,再把這個(gè) Pod 調(diào)度到合適的 Node 上啟動(dòng)運(yùn)行,直到 Pod 實(shí)例數(shù)量達(dá)到預(yù)定目標(biāo)。
凡事都得從hello,world開(kāi)始
這里hello,world是一個(gè) Web 留言板應(yīng)用,是個(gè)基于 PHP + Redis 的兩層分布式架構(gòu)的 Web 應(yīng)用,這是留言板的系統(tǒng)部署架構(gòu)圖:

三個(gè) Docker 鏡像:
redis-master:用于前端 Web 應(yīng)用進(jìn)行寫(xiě)留言的操作,其中已經(jīng)保存了一條“hello,world”。guestbook-redis-slave:用于前端 Web 應(yīng)用進(jìn)行讀留言的操作,并且和 redis-master 的數(shù)據(jù)保持同步。guestbook-php-frontend:PHPWeb 服務(wù),在網(wǎng)頁(yè)上顯示留言內(nèi)容,同時(shí)提供一個(gè)文本輸入框供訪問(wèn)者添加留言。
這是 Kubernetes 部署架圖:

下面我們一起開(kāi)始手把手的教大家利用 k8s 搭建一個(gè)hello,world應(yīng)用。注意,本文使用的是 centos 操作系統(tǒng)。
首先,我們需要開(kāi)啟路由轉(zhuǎn)發(fā)功能,如果不執(zhí)行此步驟容器不能訪問(wèn)外網(wǎng):
echo 1 > /proc/sys/net/ipv4/ip_forward
然后,我們?cè)谂渲?yum 源:
yum install -y epel-release
yum clean all
yum list
再接著,我們安裝 Docker。
yum install -y docker-io
Docker 安裝完畢后,我們就開(kāi)始搭建 Kunernetes 運(yùn)行環(huán)境了。
## 關(guān)閉防火墻
systemctl disable firewalld
suystemctl stop firewalld
## 再安裝 etcd 和 Kubernetes 軟件
yum install -y etcd
yum install -y kubernetes
然后修改 Docker 的配置文件 /etc/sysconfig/docker,OPTIONS 修改如下:
OPTIONS='--selinux-enabled=false --insecure-registry gcr.io'
注意,Docker 鏡像源建議采用國(guó)內(nèi)的鏡像源。通用的方法就是編輯/etc/docker/daemon.json:
{
"registry-mirrors" : [
"http://ovfftd6p.mirror.aliyuncs.com",
"http://registry.docker-cn.com",
"http://docker.mirrors.ustc.edu.cn",
"http://hub-mirror.c.163.com"
],
"insecure-registries" : [
"registry.docker-cn.com",
"docker.mirrors.ustc.edu.cn"
],
"debug" : true,
"experimental" : true
}
然后重啟 Docker 的 daemon 即可。
systemctl daemon-reload
systemctl restart docker
再接著修改 Kubernetes 的 apiserver 配置文件 /etc/kubernetes/apiserver:
將 –admission_control 參數(shù)中的 ServiceAccount 刪除。
然后按照順序啟動(dòng)所有的服務(wù):
systemctl start etcd
systemctl start docker
systemctl start kube-apiserver
systemctl start kube-controller-manager
systemctl start kube-scheduler
systemctl start kubelet
systemctl start kube-proxy
檢查上述服務(wù)是否都已經(jīng)啟動(dòng)成功,如果都已經(jīng)成功則 kubernetes 集群環(huán)境就已經(jīng)安裝完畢。
為 Redis-master 服務(wù)創(chuàng)建 RC 文件,語(yǔ)法格式為 ymal。
apiVersion: v1
kind: ReplicationController
metadata:
name: redis-master
labels:
name: redis-master
spec:
replicas: 1
selector:
name: redis-master
template:
metadata:
labels:
name: redis-master
spec:
containers:
- name: master
image: kubeguide/redis-master
ports:
- containerPort: 6379
然后在 Master 節(jié)點(diǎn)中執(zhí)行命令:Kubectl create -f<config_file>,并把它發(fā)布到 Kubernetes 集群中:
$ kubectl create -f redis-master-controller.yaml
replicationcontrollers/redis-master
然后再創(chuàng)建與之關(guān)聯(lián)的 Service。service 對(duì)應(yīng)的文件 redis-master-service.yaml,內(nèi)容如下:
apiVersion: v1
kind: Service
metadata:
name: redis-master
labels:
name: redis-master
spec:
ports:
- port: 6379
targetPort: 6379
selector:
name: redis-master
創(chuàng)建 redis-master service。
kubectl create -f redis-master-service.yaml
接著,再創(chuàng)建 redis-slave 服務(wù),與前者一樣,先創(chuàng)建 redis-slave 的 RC 定義文件 redis-salve-controller.yaml。
apiVersion: v1
kind: ReplicationController
metadata:
name: redis-slave
labels:
name: redis-slave
spec:
replicas: 2
selector:
name: redis-slave
template:
metadata:
labels:
name: redis-slave
spec:
containers:
- name: slave
image: kubeguide/guestbook-redis-slave
env:
- name: GET_HOSTS_FROM
value: env
ports:
- containerPort: 6379
然后創(chuàng)建 redis-salve 對(duì)應(yīng)的 Pod。
kubectl create -f redis-salve-controller.yaml
Pod 創(chuàng)建完成后,創(chuàng)建對(duì)應(yīng)的 service。先創(chuàng)建 service 的配置文件redis-salve-service.yaml,內(nèi)容如下:
apiVersion: v1
kind: Service
metadata:
name: redis-slave
labels:
name: redis-slave
spec:
ports:
- port: 6379
selector:
name: redis-slave
然后根據(jù)配置文件,創(chuàng)建 service。
kubectl create -f redis-slave-service.yaml
為了實(shí)現(xiàn) Redis 集群的主從數(shù)據(jù)同步,redis-slave 需要知道 redis-master 的地址,所以我們需要在 redis-slave 鏡像的啟動(dòng)命令/run.sh中添加:
redis-server --slaveof ${REDIS_MASTER_SERVICE_HOST} 6379
最后,創(chuàng)建 frontend 的 RC 文件frontend-controller.yaml,內(nèi)容如下:
apiVersion: v1
kind: ReplicationController
metadata:
name: frontend
labels:
name: frontend
spec:
replicas: 3
selector:
name: frontend
template:
metadata:
labels:
name: frontend
spec:
containers:
- name: frontend
image: kubeguide/guestbook-php-frontend
env:
- name: GET_HOSTS_FROM
value: env
ports:
- containerPort: 80
然后在運(yùn)行kubectl create命令創(chuàng)建 RC:
$ kubectl create -f frontend-controller.yaml
replcationcontrollers/frontend
再創(chuàng)建與之關(guān)聯(lián)的 Service,frontend-service.yaml內(nèi)容如下:
apiVersion: v1
kind: Service
metadata:
name: frontend
labels:
name: frontend
spec:
type: NodePort
ports:
- port: 80
nodePort: 30001
selector:
name: frontend
最后一步,創(chuàng)建 service。
$ kubectl create -f frontend-service.yaml
services/frontend
下面就可以打開(kāi)瀏覽器輸入:http://虛擬機(jī)IP:30001 之后就會(huì)出現(xiàn)hello,world,成功了就這這樣:

總結(jié)
這就是 Kubernetes,實(shí)現(xiàn)了hello,world就算是一只腳踏進(jìn)來(lái)了,Kubernetesde 的好處太多了,最直接的好處就是可以輕裝上陣開(kāi)發(fā)復(fù)雜的系統(tǒng),架構(gòu)師專注于“服務(wù)組件”,剩下的人則負(fù)責(zé)業(yè)務(wù)代碼的開(kāi)發(fā),而且 Kubernetes 還是實(shí)現(xiàn)微服務(wù)的利器,微服務(wù)其實(shí)就是一個(gè)巨無(wú)霸給拆成一個(gè)個(gè)小單體的過(guò)程,Kubernetes 來(lái)做這事無(wú)疑是最佳人選!
最近我拉了一個(gè) k8s 學(xué)習(xí)交流群,有想學(xué)習(xí)的微信私我,一起精進(jìn)!
