懶惰是萬惡之源,雖然小編對「五一」四天小長假也是沒有一點抵抗力,乘本身還有一點僅存意識沒有被「五一」侵蝕,趕忙把文章更了。
這是小編對kubernetes的第一篇文章,這篇文章介紹瞭如下內容:前端
Kubernetes是一個全新的基於容器技術的分佈式架構領先方案,與2015年被Google高調的正式開源。一經開源便迅速稱霸容器技術領域。
Kubernetes是一個開放的平臺。不侷限與任何一種語言,不管是C、java、Python均可以毫無阻礙的映射Kubernetes的service,並經過標準的TCP協議進行交互。
Kubernetes是一個完備的分佈式系統支撐平臺。具有完備的集羣管理能力,內建負載均衡、強大的故障發現和自我修復能力,並提供了完備的管理工具,如開發、部署測試、運維監控等等。總之,Kubernetes是一個一站式的完備的分佈式系統開發和支撐平臺。java
第一點就是跟docker相仿,部署簡單,大大節省了運維的成本,pod之間的資源是相互隔離的,不會各自的系統環境影響其餘服務,只要輕鬆的修改image,並部署相應的service和deployment就能夠實現服務部署應用、服務滾動升級等等。
其次,Kubernetes全面擁抱微服務架構。將一個巨大的單體應用,分解成多個微服務,每個微服務後又有多個實例,而且內嵌了負載均衡。讓咱們直接應用微服務解決複雜業務系統的架構問題。
而後,就是咱們能夠隨時隨地的總體「搬遷」到公有云上。舉個例子,後臺的某個namespace下運行着各類應用的管控程序,此時咱們只須要在web界面中,建立本身的項目,並在項目中部署本身的應用,後臺就會根據咱們的資源模板,在相應的namespace中運行咱們部署的應用,這裏因爲使用的namespace能夠作到徹底的資源隔離。使部署更簡單,讓開發人員的重點都放在業務之上。
最後,Kubernetes有超強的橫向擴展能力,學習過hadoop的生態的朋友們必定知道,hdfs好處之一就是部署在廉價的機器上,並實現了冗餘備份,更是支持橫向的擴展,這些優勢對於後起之秀的Kubernetes固然是通通繼承下來,而且與之完善。Kubernetes能夠作到不用修改代碼就能平滑擴招到擁有上百個node的大規模集羣。
老版本的架構:
新版本的架構:
node
在演示以前,因爲你們可能對yaml語法有寫模糊,小編這裏先介紹一下yaml的基本語法,有助於你們理解下面案例的配置文件。mysql
① Yaml的語法規則:
- 大小寫敏感
- 使用縮進表示層級關係
- 縮進時不容許使用 Tab 鍵,只容許使用空格
- 縮進的空格數目不重要,只要相同層級的元素左側對齊便可
- 「#」 表示註釋
- 在 yaml 裏面,連續的項目(如:數組元素、集合元素)經過減號「-」來表示,map 結構 裏面的鍵值對(key/value)用冒號「:」來分割。
② Yaml支持的三種數據結構:
1. 對象:對象的一組鍵值對,使用冒號結構表示。linux
#案例演示 animal: pets hash: name: Steve foo: bar 或者:hash: { name: Steve, foo: bar }
2. 數組:一組連詞線開頭的行,構成一個數組。web
#案例演示 - Cat - Dog - Goldfish 或者:[ 'Cat', 'Dog', 'Goldfish' ]
3. 複合結構:對象和數組能夠結合使用,造成複合結構。redis
#案例演示 bat: website: baidu: http://www.baidu.com qq: http://www.qq.com ali: - http://www.taobao.com - http://www.tmall.com ceo: yanhongli: 李彥宏 huatengma: 馬化騰 yunma: 馬雲
4. 純量:純量是最基本的、不可再分的值。如:字符串、布爾值、整數、浮點數、Null、時間、日期
#案例演示
number: 12.30sql
說了這麼多的概念,相比你們對Kubernetes也是有所動心,那麼小編這就帶你們簡單的部署一下Kubernetes,感覺一下他的強大之處。
這裏咱們使用一個MySQL+Tomcat實現一個簡單的web應用的部署。docker
#單機版的k8s安裝 [root@zy ~]# systemctl disable firewalld [root@zy ~]# systemctl stop firewalld [root@zy ~]#yum install -y etcd kubernetes #按順序啓動如下服務 [root@zy ~]#systemctl start etcd [root@zy ~]#systemctl start docker [root@zy ~]#systemctl start kube-apiserver [root@zy ~]#systemctl start kube-controller-manager [root@zy ~]#systemctl start kube-scheduler [root@zy ~]#systemctl start kubelet [root@zy ~]#systemctl start kube-proxy #批量啓動服務 for i in etcd docker kube-apiserver kube-controller-manager kube-scheduler kubelet kube-proxy ;do systemctl start $i ;done;
#① MySQL服務的RC(mysql-rc.yaml) apiVersion: v1 kind: ReplicationController #副本控制器RC metadata: name: mysql #RC的名稱,全局惟一 spec: replicas: 1 #pod 期待的副本數 selector: app: mysql #符合目標的pod擁有此標籤 template: #根據下面的模板建立pod的副本 metadata: labels: #pod副本擁有的標籤,對應RC的selector app: mysql spec: #pod內容器的定義部分 containers: - name: mysql #容器名稱 image: mysql #鏡像名稱 ports: #容器內應用監聽的端口號 - containerPort: 3306 env: #容器內容的環境變量 - name: MYSQL_ROOT_PASSWORD value: "123456"
#② MySQL的service(mysql-svc.yaml) apiVersion: v1 kind: Service metadata: name: mysql spec: ports: - port: 3306 selector: app: mysql
#③ Tomcat服務的RC(myweb-rc.yaml) apiVersion: v1 kind: ReplicationController #副本控制器RC metadata: name: myweb #RC的名稱,全局惟一 spec: replicas: 2 #pod 期待的副本數 selector: app: myweb #符合目標的pod擁有此標籤 template: #根據下面的模板建立pod的副本 metadata: labels: #pod副本擁有的標籤,對應RC的selector app: myweb spec: #pod內容器的定義部分 containers: - name: myweb #容器名稱 image: kubeguide/tomcat-app:v1 #鏡像名稱 ports: #容器內應用監聽的端口號 - containerPort: 8080
#④ Tomcat服務的service(myweb-svc.yaml) apiVersion: v1 kind: Service metadata: name: myweb spec: type: NodePort ports: - port: 8080 nodePort: 30001 selector: app: myweb
#執行如下命令 [root@zy ~]#kubelet create -f ./mysql-rc.yaml [root@zy ~]#kubelet create -f ./mysql-svc.yaml [root@zy ~]#kubelet create -f ./myweb-rc.yaml [root@zy ~]#kubelet create -f ./ myweb-svc.yaml 注意:這裏可能會涉及到image的下載,須要聯網。
驗證是否部署成功:
#查看集羣中的RC資源對象
[root@zy ~]# kubectl get rc
數據庫
[root@zy ~]# kubectl get svc #查看集羣中的service資源對象
#訪問pod中的Tomcat服務: [root@zy ~]# curl 192.168.130.130:30001
到此在單機版的kubernetes集羣中,咱們就部署成功一個Tomcat+MySQL服務。
經過上面的案例你們也對Kubernetes有必定的瞭解,而且能簡單的實際的操做一下Kubernetes,可是可能對其中的細節並非很瞭解,就像什麼是「rc」,爲何就能經過service將容器中的服務映射到宿主機中供外部訪問等等,接下來小編就給你們介紹Kubernetes幾個重中之重的基礎概念。
說道master你們必定不會陌生,分佈式集羣中沒有老大怎麼能行,羣龍無首那豈不天下大亂。Kubernetes中的master就是集羣的控制節點,基本上Kubernetes全部的控制命令都會發給它,他來負責具體的執行,若是它一旦宕機,集羣內部的全部容器應用的管理都將失效。爲了不被斬首,最好設置多個master造成高可用。
這裏介紹一下master中的一組進程:
- Kube-apiserver:提供了HTTP Rest接口的關鍵服務進程,是Kubernetes集羣中增、刪、改、查等操做的惟一入口。若是它啓動失敗,那麼Kubernetes的全部操做均將無效。
- Kube-controller-manager:Kube-controller-manager:
- Kube-scheduler:負責資源調度的進程,當咱們部署應用,建立pod時,這個進程就會根據每一個node的資源狀況,將pod安排的指定的node中運行。
- etcd:Kubernetes裏的全部資源對象的數據所有保存在etcd中,他就是一個Kubernetes的數據庫。好比,建立相應的pod時,就會在etcd中生成一個記錄,若是後期這個pod被刪除,一樣的存在etcd中這個記錄也會被刪除。
Kubernetes集羣中除了master,其餘的機器就是node,也就是所謂的從節點。Node是Kubernetes集羣的工做負載節點,每一個node都會被master分配必定的工做負載。就像hdfs同樣,若是有從節點宕機,master就會將此節點上的工做(對於hdfs是副本)轉義到其餘的可用的node上,以保證咱們設置的replica個數。
這裏介紹一下node中的一組進程:
- Kubelet:負責node節點上的pod的建立、啓停、同時與master保持通訊。
- Kube-proxy:實現service的通訊與負載均衡機制的重要組件。
- Docker:負責node中的容器建立和管理。
固然上面,說到了Kubernetes集羣能夠橫向擴展,也就是node能夠動態的添加,當node節點上安裝了相應的配置,默認狀況下kubelet會自動的向master註冊本身,kubelet會向master彙報自身狀況(資源、系統…),這樣master會發現node並以後爲其分配工做負載。固然這種相似心跳機制的通訊,有助於master計算各個node的資源,更好的進行過負載,也有助於master對node的管理,當有node「失聯」時,master也會很快的將其node上的工做負載轉移到其餘機器上,有利於集羣的正常工做。
pod是Kubernetes最基本最重要的概念,pod也是Kubernetes集羣的負責均衡的最小單位。
上面的圖就是一個pod中的結構,這裏不論pod中運行多少container,都有一個pause container,它的做用就是表明這個容器組的狀態,爲pod中的每個container共享IP和數據目錄。
Kubernetes爲每個pod分配了一個Pod IP,這個Pod IP被pod中的全部容器共享,默認的Kubernetes集羣中任意的兩個pod之間能夠直接的TCP通訊。
默認的當pod中有某個容器中止時,Kubernetes會自動檢測到這個問題並重啓這個pod(重啓pod中全部的container)。當前前面也說了,當node宕機時,會將工做負載移動到其餘的node上,這個裏的工做負載就是pod。
當時小編學習k8s的label也是半知半解,k8s的中文官檔把label解釋的太過官方,小編我愣是讀了3遍沒有看懂到底label強大在哪裏。容小編我先介紹一下label,label是一個key=value的鍵值對,其中key與value由用戶自定義。Label能夠附加在各類資源對象上,例如:node、pod、service、RC等。一個資源對象又能夠定義多個label,同一個label也能夠被添加到任意數量的資源對象上,label一般在資源對象定義時建立,同時也能夠在資源對象建立後動態添加。
是否是聽了上面一堆向繞口令式的解釋,有種想打人的衝突。年輕人,不要心浮氣躁,其實label很簡單,學過JavaScript小夥伴必定知道選擇器,有什麼類選擇器、id選擇器。其實label就和JavaScript的標籤同樣,當咱們給某一個資源對象用label打上標籤的時候,能夠在其餘的資源對象中經過「selector」來選擇相應的標籤,這樣就能準確的定位當擁有相應標籤的資源對象了。
Label selector有兩種類型:
- 基於等式: name=redis-slave #匹配具備name=redis-slave標籤的資源對象
- 基於集合:env!=production #匹配不具備env=production標籤的資源對象
Label selector在k8s集羣中的重要使用場景:
- Kube-controller進程經過資源對象RC上定義的label selector來篩選要監控的pod副本的數量,從而實現pod副本的數量始終符合預期設定的全自動控制流程
- Kube-proxy進程經過service的label selector來選擇對應的pod,自動創建起每個service到對應pod的請求轉發路由表,從而實現了service的智能複雜均衡。
- 經過對某些node定義特定的label,而且在pod定義文件中使用nodeselector這種標籤地調度,kube-scheduler進程能夠實現pod「定向調度」的特性。
總之,使用label能夠對對象建立多組標籤,label和label selector共同構成了k8s系統中最核心的應用模型,使得被管理對象可以被精確地分組管理。
RC實際上是一個定義了指望的場景,即聲明某種pod的副本數量在任意時刻都符合某個預期的值,因此RC的定義包括如下幾部分:
- pod的期待的副本數
- 用於篩選目標pod的label selector
- 當pod的副本數小於預期數量,用於建立新的pod的pod模板
如上圖所示,RC就控制着,label爲name=app的pod保持兩個副本,若是有pod出現問題,RC會在相應的其餘node上,根據RC中的template啓動pod,若是pod的副本數對於期待的值,RC會馬上終結掉多餘數量的pod,這一切都是自動化的。固然若是要下線pod,能夠先將RC中期待的副本數設置爲0,以後再刪除RC便可。
在k8s v1.2是RC升級成爲了一個新的概念---replica set,其實兩者的區別就是,RC使用的是基於等式的label selector,而RS使用的是基於集合的label selector。
RC的特性:
- 經過RC能夠實現pod的建立以及副本數的自動控制
- 經過改變RC中定義的pod的副本數,能夠實現pod的擴容和縮容
- 經過改變RC中template的image版本,能夠實現pod的滾動升級(優雅)
deployment也是kubernetes v1.2引入的概念,它的宗旨在於更好的解決pod的編排問題。Deployment內部是使用了replica set來實現,其類似度與replication controller有90%以上。Deployment相對於RC最大的優點就是,咱們能夠隨時知道當前pod部署的進度,這是由於咱們期待系統啓動N個pod的目標狀態,是一個連續變化的過程,而deployment能夠實時的跟蹤這個過程,這至關有助於排查錯誤。
Deployment的典型使用場景:
- 建立deployment對象來生成RS,並完成pod副本的建立過程
- 建立deployment對象來生成RS,並完成pod副本的建立過程
- 當deployment不穩定時,能夠回滾到先前的一個deployment版本
- 暫停deployment以便於一次性修改多個podtemplatespec的配置項,以後再恢復deployment進行新的發佈。
在k8s中,pod的管理對象RC、deployment、daemonset和job都是無狀態的服務。可是不少時候咱們須要有狀態的服務,好比MySQL、akka、zookeeper集羣,他們的節點都有固定的身份、集羣規模比較固定,集羣中的每一個節點都是有狀態的一般會持久化數據到磁盤、若是磁盤損壞則集羣的某個節點將沒法正常運行。若是使用RC/deployment來控制這些pod,那麼咱們發現這是不知足要求的。由於,pod的名稱是隨機產生的,pod的IP是在運行期間才肯定的,並且咱們須要pod在失敗重啓後,仍然能掛載集羣中的數據共享。
根據以上的問題,kubernetes從v1.4引入了petSet,並在v1.5正式更名爲statuefulSet。而它的特性是:
- statuefulSet裏的每個pod都有穩定的、惟一的網絡表示(經過某種DNS實現),能夠發現集羣中的其餘成員
- statuefulSet裏的每個pod都有穩定的、惟一的網絡表示(經過某種DNS實現),能夠發現集羣中的其餘成員
- statuefulSet中的pod採用的是穩定的持久化存儲卷,經過PV/PVC來實現。刪除pod時默認不會刪除與statuefulSet相關的存儲卷。
service也是kubernetes裏最核心的資源對象之一,kubernetes的每個service其實就是微服務架構中的一個「微服務」,由下圖所示:
Service定義了一個服務的訪問入口,前端的frontend pod經過這個入口地址訪問其背後的一組由pod副本組成的集羣實例,service與其後端的pod經過label selector無縫對接。可是咱們想到了,雖然客戶端訪問的是service,可是最終訪問的仍是對應的service下的pod中的應用程序,因爲pod在失敗重啓後,他的IP地址是動態變化的,那麼咱們如何肯定咱們該如何訪問服務。這裏service設計了一種巧妙的方法,service一旦建立,集羣會自動爲它分配一個可用的clusterIP,並且在service的整個生命週期中,這個clusterIP不會改變,咱們只要使用最基本的TCP網絡通訊,就能夠訪問具體的service服務,那以後service與pod的通訊,是經過每一個node節點上的kube-proxy,它負責把對service的請求轉發到後端的某個pod中。這樣咱們就能夠經過一個固定的IP去訪問服務啦。固然最終咱們訪問的仍然是宿主機的某個端口,咱們能夠在定義service的yaml文件中,配置相應的宿主機的端口映射來實現外部訪問集羣內部的服務。
apiVersion: v1 kind: Service metadata: name: myweb spec: type: NodePort #這裏就設置了service到宿主機端口獲得映射 ports: - port: 8080 nodePort: 30001 selector: app: myweb
volume是pod中可以被多個容器訪問的共享目錄。K8s中的volume跟docker中的volume比較類似,可是二者不能等價。K8s中的volume定義在pod上,而後被一個pod例的多個容器掛載到具體的文件目錄下,其次,kubernetes中的volume與pod的生命週期相同,但與容器的生命週期不相關,當容器終止或者重啓時,volume中的數據不會丟失。
Volume的使用也比較簡單,咱們先在pod中聲明一個volume,而後在容器裏引用該volume並mount到容器的目錄中便可。例:
template: metadata: labels: app: app-demo tier: frontend spec: volume: - name: datavol emptyDir: {} containers: - name: tomcat-deom image: tomcat volumeMounts: - mountPath: /mydata-data name: datavol
這裏就是使用了一個emptyDir 類型的volume,掛載到container中的/mydata-data下。
這裏介紹一下volume的常見的類型:
- emptyDir:臨時的空目錄,當pod在node中建立時自動分配,當pod從node中移除時,其emptyDir分配的目錄中的數據也將被刪除
- hostPath:在pod上掛載宿主機的文件或者目錄。
- gecPersistenDisk:表示使用谷歌公有云提供的永久磁盤存放volume的數據。
- nfs:表示使用nfs網絡文件系統提供的共享目錄存儲數據,固然想用這種方式,還須要額外的部署一個nfs服務。
volume是定義在pod上的,屬於「計算資源」的一部分,而實際上,「網絡存儲」是相對獨立與「計算資源」而存在的一種實體資源。相似於網盤,而kubernetes中的persistent volume 和與之關聯的persistent volume claim ,也起到了相似的做用。
PV的特色:
- PV只能是網絡存儲,不屬於任何一個node,可是能夠在任意一個node中訪問
- PV並非定義在pod上的,而是獨立於pod以外定義的
例:
#定義一個PV apiVersion: v1 kind: PersistentVolume metadata: name: pv003 spec: capacity: storage: 5Gi accessModes: - ReadWriteOnce nfs: path: /somedata server: 172.17.0.2
#若是pod想使用上面的PV,就須要定義一個PVC kind: PersistentVolumeCliam apiVersion: v1 metadata: name: myclaim spec: accessModes: - ReadWriteOnce resources: requests: storage: 8Gi #而後在pod的volume總引用上述的PVC便可 spec: volume: - name: mypd PersistentVolumeCliam: cliamName: myclaim
最後介紹一下PV的狀態:
Availale:空閒狀態
Bound:已經綁定到某個PVC上
Released:對應的PVC已經刪除,可是資源尚未被集羣回收
Failed:PV自動回收失敗
namespace是kubernetes系統中實現多租戶的資源隔離。Namespace經過將集羣內部的資源對象「分配」到不一樣的namespce中,造成邏輯上分組的不一樣項目、小組或者用戶組,便於不一樣的分組在共享使用整個集羣的資源的同時還能被分別管理。
咱們能夠在定義資源對象是,在他的metadata中指定他屬於的namespace:
apiVersion: v1 kind: PersistentVolume metadata: name: pv003 namespace: xxxx
同時在不一樣的namespace中,還能限定不一樣租戶能佔用的資源,若有CPU使用量、內存等等。
annotation與label相似,也使用key/value鍵值對的形式進行定義。不一樣的是,label具備嚴格的命名規則,他定義的是k8s對象的元數據,而且同於label selector。而annotation則是用戶任意定義的「附加信息」 ,以便於外部工具的查找。
大致來講,annotation定義以下信息:
- build信息、release信息、dicker鏡像地址等等
- 日誌庫、監控庫、分析庫等等資源庫的地址信息
- 程序調試工具信息,例如:工具名、版本號
- 團隊信息,如:聯繫電話、負責人名稱、網址等
[root@zy ~]# yum install -y etcd kubernetes
緣由:機器上安裝了docker,由於安裝kubernetes會自動安裝docker。
解決:卸載docker
[root@zy ~]# yum list installed | grep docke [root@zy ~]# yum remove -y docker-ce.x86_64 [root@zy ~]# rm -rf /var/lib/docker
[root@zy yaml_file]# kubectl create -f mysql-rc.yaml
緣由:k8s的認證問題。
[root@zy yaml_file]#systemctl restart kube-apiserver
緣由:查看pod的建立的報錯信息,發現是pod-infrastructure鏡像下載失敗,致使pod啓動失敗。
解決:
pod-infrastructure鏡像下載配置:
[root@zy yaml_file]# vim /etc/kubernetes/kubelet
發現:
發現國內是沒法經過這個連接下載到pod-infrastructure鏡像。
首先咱們:
[root@zy yaml_file]# docker search pod-infrastructure
下載咱們須要的鏡像:
[root@zy yaml_file]# docker pull docker.io/w564791/pod-infrastructure
而後將下載的鏡像推送到本身的私有倉庫:
[root@zy yaml_file]#docker tag docker.io/w564791/pod-infrastructure 127.0.0.1:5000/ pod-infrastructure:v1.0 [root@zy yaml_file]#docker push 127.0.0.1:5000/ pod-infrastructure:v1.0
修改拉取的pod-infrastructure鏡像的位置:
[root@zy yaml_file]# vim /etc/kubernetes/kubelet: 改成: KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=127.0.0.1:5000/ pod-infrastructure:v1.0"
最後重啓集羣:
#!/bin/bash
for SERVICES in kube-apiserver kube-controller-manager kube-scheduler; do
systemctl restart $SERVICES
done
systemctl restart kubelet
緣由:環境是CentOS Linux release 7.6.1810 (Core),可是因爲內核的版本和docker存在兼容性問題。
解決:升級內核:
#查看內核版本 [root@zy yaml_file]# uname -r #升級內核 #導入key [root@zy yaml_file]# rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org #安裝elrepo的yum源 [root@zy yaml_file]# rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm #安裝內核在yum的ELRepo源中,有mainline頒佈的,能夠這樣安裝: [root@zy yaml_file]# yum --enablerepo=elrepo-kernel install kernel-ml-devel kernel-ml -y #重啓Linux [root@zy yaml_file]#reboot