再次了解kubernetes的基本概念和術(shù)語(yǔ)

再次了解kubernetes的基本概念和術(shù)語(yǔ)

1、kubernetes整體概要

在Kubernetes中绍哎,Service(服務(wù))是分布式集群架構(gòu)的一個(gè)核心,一個(gè)Service對(duì)象擁有如下特征孽查。

  • 擁有一個(gè)唯一指定的名字(如mysql-server)酥馍。
  • 擁有一個(gè)虛擬IP(Cluster IP、Service IP或VIP)板熊。
  • 能夠提供某個(gè)遠(yuǎn)程服務(wù)的能力框全。
  • 被印射到了提供這種服務(wù)能力的一組容器應(yīng)用之上。

Service的服務(wù)進(jìn)程目前都是居于Socker通信方式對(duì)外提供服務(wù)邻邮,如Redis竣况、Memcache克婶、Mysql筒严、Web Service丹泉,或是實(shí)現(xiàn)了某個(gè)具體業(yè)務(wù)的一個(gè)特定的TCP Server進(jìn)程。雖然一個(gè)Service通常由多個(gè)相關(guān)的服務(wù)進(jìn)程來(lái)提供服務(wù)鸭蛙,每個(gè)服務(wù)進(jìn)程都有一個(gè)Endpoint(ip+port)訪問(wèn)點(diǎn)摹恨,但kubernetes能夠讓我們通過(guò)Service(虛擬Cluster IP + Service Port)連接到指定的Service上面。

kubernetes內(nèi)建的透明負(fù)載均衡娶视、故障恢復(fù)機(jī)制及service創(chuàng)建后ip不變化晒哄,基于此可以向用戶提供穩(wěn)定的服務(wù)。

容器提供了強(qiáng)大的隔離功能肪获,所以有必要把Service提供服務(wù)的這組進(jìn)程放到容器中進(jìn)行隔離寝凌。為此,kubernetes設(shè)計(jì)了Pod對(duì)象孝赫,將每個(gè)服務(wù)進(jìn)程包裝到相應(yīng)的Pod中较木,使其成為Pod中運(yùn)行的一個(gè)容器(Container)。為了建立Service和Pod間的關(guān)聯(lián)聯(lián)系青柄,kubernetes首先給每個(gè)Pod貼上一個(gè)標(biāo)簽(Label)伐债,如給運(yùn)行mysql的Pod貼上name=mysql的標(biāo)簽,然后給相應(yīng)的Service定義標(biāo)簽選擇器(Label Selector)致开,如mysql的Service的標(biāo)簽選擇器的選擇條件為name=mysql峰锁,意為Service下所有包含name-=mysql的Label的Pod上。

說(shuō)到Pod双戳,簡(jiǎn)單介紹其概念虹蒋。首先,Pod運(yùn)行在一個(gè)我們稱之為節(jié)點(diǎn)(Node)的環(huán)境中飒货,這個(gè)節(jié)點(diǎn)可能是物理機(jī)或虛擬機(jī)千诬,通常一個(gè)節(jié)點(diǎn)上上面運(yùn)行幾百個(gè)Pod;其次每個(gè)Pod運(yùn)行著一個(gè)特殊的被稱之為Pause的容器膏斤,其它的容器被稱為業(yè)務(wù)容器徐绑,這些業(yè)務(wù)容器共享Pause容器的網(wǎng)絡(luò)棧和Volume掛載卷,因此它們之間的通信和數(shù)據(jù)交換效率更為高效莫辨。在設(shè)計(jì)時(shí)我們可以充分利用這一特性將一組密切相關(guān)的服務(wù)進(jìn)程放到同一個(gè)Pod中傲茄。最后需要注意的是并不是每一個(gè)Pod和它里面運(yùn)行的容器都能映射到一個(gè)Service上,只有那些提供服務(wù)的一組Pod才會(huì)被映射成一個(gè)服務(wù)沮榜。

在集群管理方面盘榨,kubernetes將集群中的機(jī)器劃分為一個(gè)Master節(jié)點(diǎn)和一群工作節(jié)點(diǎn)(Node)。其中Master節(jié)點(diǎn)運(yùn)行著集群管理的一組進(jìn)程kube-apiserver蟆融、kube-controller-manage草巡、kube-scheduler。這些進(jìn)程實(shí)現(xiàn)了整個(gè)集群的資源管理型酥、Pod調(diào)度山憨、彈性收縮查乒、安全控制、系統(tǒng)控制和糾錯(cuò)等管理功能郁竟,并且全是自動(dòng)完成的玛迄。Node作為一個(gè)集群中的工作節(jié)點(diǎn),運(yùn)行真正的應(yīng)用程序棚亩,在Node上kubernetes管理的最小單元是Pod蓖议。Node運(yùn)行著kubernetes的kubeletkube-proxy服務(wù)進(jìn)程讥蟆,這些服務(wù)進(jìn)程負(fù)責(zé)Pod的創(chuàng)建勒虾、啟動(dòng)、監(jiān)控瘸彤、重啟和銷毀从撼,以及實(shí)現(xiàn)軟件模式的均衡負(fù)載。

解決傳統(tǒng)的服務(wù)擴(kuò)容和服務(wù)升級(jí)兩個(gè)難題里钧栖,kubernetes集群中低零,我們只需要為擴(kuò)容的service關(guān)聯(lián)的Pod創(chuàng)建一個(gè)Replication Controller(簡(jiǎn)稱RC),在這個(gè)RC定義文件中寫好下面幾個(gè)關(guān)鍵信息:

  • 目標(biāo)Pod的定義拯杠。
  • 目標(biāo)Pod需要運(yùn)行的副本數(shù)量(Replicas)掏婶。
  • 要監(jiān)控目標(biāo)Pod的標(biāo)簽(Label)。

在創(chuàng)建好RC(系統(tǒng)將自動(dòng)創(chuàng)建好Pod)后潭陪,kubernetes會(huì)通過(guò)RC中定義的Label篩選出對(duì)應(yīng)的Pod實(shí)例并全自動(dòng)實(shí)時(shí)監(jiān)控其狀態(tài)和數(shù)量雄妥。

pod - pod位置示意

2、基本概念和術(shù)語(yǔ)

kubernetes中大部分概念如Node依溯、Pod老厌、Replication ControllerService等都可以被看作一種資源對(duì)象黎炉,幾乎所有的資源對(duì)象都可以通過(guò)kubernetes提供的kubectl工具(或API編程調(diào)用)執(zhí)行增刪改查等操作枝秤,并將其保存在etcd中持久化存儲(chǔ)。從這個(gè)角度來(lái)看慷嗜,kubernetes其實(shí)是一個(gè)高度自動(dòng)化的資源控制系統(tǒng)淀弹,它通過(guò)跟蹤對(duì)比保存在etcd庫(kù)里的“資源期望狀態(tài)”和當(dāng)前環(huán)境中的“實(shí)際資源狀態(tài)”的差異來(lái)實(shí)現(xiàn)自動(dòng)控制和自動(dòng)糾錯(cuò)的高級(jí)功能。

2.1 Master

kubernetes里的Master指的是集群控制節(jié)點(diǎn)庆械。每個(gè)kubernetes集群里都需要一個(gè)Master節(jié)點(diǎn)來(lái)負(fù)責(zé)整個(gè)集群的管理和控制薇溃,基本上kubernetes所有的控制命令都是發(fā)給它,它來(lái)負(fù)責(zé)具體的執(zhí)行過(guò)程缭乘,我們后面所有的執(zhí)行的命令基本上都是在Master節(jié)點(diǎn)上運(yùn)行的沐序。Master節(jié)點(diǎn)通常會(huì)占據(jù)一個(gè)獨(dú)立的服務(wù)器或虛擬機(jī),就是它的重要性體現(xiàn),一個(gè)集群的大腦策幼,如果它宕機(jī)邑时,那么整個(gè)集群將無(wú)法響應(yīng)控制命令。

Master節(jié)點(diǎn)上運(yùn)行著以下幾組關(guān)鍵進(jìn)程:

  • Kubernetes API Server(kube-apiserver):提供了HTTP rest接口的關(guān)進(jìn)服務(wù)進(jìn)程垄惧,是Kubernetes里所有資源增刪改查等操作的唯一入口,也是集群管理的入口進(jìn)程绰寞。
  • Kubernetes Controller Manage(kube-controller-manage):Kubernetes里所有資源對(duì)象的自動(dòng)化控制中心到逊,可以理解為資源對(duì)象的“大總管”。
  • Kubernetes Scheduler(kube-scheduler):負(fù)責(zé)資源的調(diào)度(Pod調(diào)度)的進(jìn)程滤钱。

Master還啟動(dòng)了一個(gè)etcd server進(jìn)程觉壶,因?yàn)閗ubernetes里所有的資源對(duì)象的數(shù)據(jù)都是保存在etcd中的。

2.2 Node

除了Master件缸,kubernetes集群的其它機(jī)器也被稱為Node節(jié)點(diǎn)铜靶,在較早的版本也被稱為Monion。同樣的它也是一臺(tái)物理機(jī)或是虛擬機(jī)他炊。Node節(jié)點(diǎn)才是Kubernetes集群中工作負(fù)載節(jié)點(diǎn)争剿,每個(gè)Node都會(huì)被Master分配一些工作負(fù)載(Docker容器),當(dāng)某個(gè)Node宕機(jī)之后痊末,其上的工作負(fù)載會(huì)被Master自動(dòng)轉(zhuǎn)移到其它節(jié)點(diǎn)上面去蚕苇。

每個(gè)Node節(jié)點(diǎn)運(yùn)行著以下幾個(gè)關(guān)鍵進(jìn)程:

  • kubelet:負(fù)責(zé)pod對(duì)應(yīng)的同期創(chuàng)建、啟動(dòng)停止等任務(wù)凿叠,同時(shí)與Master節(jié)點(diǎn)密切協(xié)作涩笤,實(shí)現(xiàn)集群管理的基本功能。
  • kube-proxy:實(shí)現(xiàn)Kubernetes Service的通信與負(fù)載均衡的重要組件盒件。
  • Docker-Engine(docker):docker引擎蹬碧,負(fù)責(zé)本機(jī)容器的創(chuàng)建和管理工作。

Node節(jié)點(diǎn)可以在運(yùn)行期間動(dòng)態(tài)增加到Kubernetes集群中炒刁,前提是這個(gè)節(jié)點(diǎn)已經(jīng)正確安裝恩沽、配置和啟動(dòng)的上述關(guān)鍵進(jìn)程。在默認(rèn)情況下kubenet會(huì)向Master注冊(cè)自己翔始,這也是kubernetes推薦的管理方式飒筑。一旦Node被納入集群管理范圍,kubelet進(jìn)程就會(huì)定時(shí)向Master節(jié)點(diǎn)匯報(bào)自身的情況绽昏,包括操作系統(tǒng)协屡、Docker版本、機(jī)器cpu和內(nèi)存情況及有哪些pod在運(yùn)行全谤。這樣Master可以獲知Node的資源使用情況并實(shí)現(xiàn)高效均衡的資源調(diào)度策略肤晓。而某個(gè)Node超過(guò)時(shí)間不進(jìn)行上報(bào)信息時(shí),master將會(huì)將其標(biāo)記為失聯(lián)(Not Ready),隨后會(huì)觸發(fā)資源轉(zhuǎn)移的自動(dòng)流程。

2.3 Pod

Pod是Kubernets最重要也是最基礎(chǔ)的概念补憾,其由下圖示意組成:

pod的組成與容器的關(guān)系.png

需求推動(dòng)發(fā)展漫萄,下面解釋為何會(huì)有pod的設(shè)計(jì)和其如此特殊的結(jié)構(gòu)。

  • 一組容器作為單元的情況下盈匾,難以去對(duì)“整體”進(jìn)行簡(jiǎn)單判斷并采取有效的行動(dòng)腾务。如一個(gè)容器掛了,是算整體服務(wù)掛了削饵,還是算N/M的死亡率岩瘦。引入業(yè)務(wù)無(wú)關(guān)并且不易掛掉的Pause容器作為Pod的根容器,以它的狀態(tài)作為整體容器組的狀態(tài)窿撬,就簡(jiǎn)單巧妙的解決了這個(gè)問(wèn)題启昧。
  • Pod多個(gè)業(yè)務(wù)容器共享Pause容器的IP族购,共享Pause容器掛接的Volume卷供鸠。這樣既簡(jiǎn)化了密切關(guān)聯(lián)業(yè)務(wù)容器之間的通信問(wèn)題,還很好地解決了它們之間文件共享的問(wèn)題旷档。

k8s為每個(gè)Pod都都分配了唯一的ip跛璧,稱之為Pod IP严里,一個(gè)Pod里的多個(gè)容器共享Pod IP地址。k8s要求底層網(wǎng)絡(luò)支持集群內(nèi)任意兩個(gè)Pod之間的TCP/IP直接通信追城,這通常采用虛擬二層網(wǎng)絡(luò)技術(shù)來(lái)實(shí)現(xiàn)田炭,如Flannel、Openswith等漓柑,牢記在k8s中教硫,一個(gè)Pod容器與另外主機(jī)上的Pod容器能夠直接通信。

Pod其實(shí)有兩種類型:普通的Pod及靜態(tài)的Pod(static Pod)辆布,后者比較特殊瞬矩,并不存放在k8s的etcd里面存儲(chǔ),而是存放在某一個(gè)具體的Node上的一個(gè)文件中锋玲,并且只在此Node上啟動(dòng)運(yùn)行景用。而普通的Pod一旦被創(chuàng)建,就會(huì)被放入到etcd中存儲(chǔ)惭蹂,隨后會(huì)被k8s Master調(diào)度到某個(gè)具體的Node上面進(jìn)行綁定(Binding)伞插,隨后該P(yáng)od被對(duì)應(yīng)的Node上的kubblet進(jìn)程實(shí)例化成一組的Docker容器并啟動(dòng)起來(lái)。默認(rèn)情況下盾碗,當(dāng)Pod里的某個(gè)容器停止時(shí)媚污,k8s會(huì)自動(dòng)檢測(cè)這個(gè)問(wèn)題并重啟啟動(dòng)這個(gè)Pod(Pod里面的所有容器),如果Pod所在的Node宕機(jī)廷雅,則會(huì)將這個(gè)Node上的所有Pod重新調(diào)度到其它節(jié)點(diǎn)上耗美。Pod京髓、容器與Node的關(guān)系如下:

pod、node和容器之間的關(guān)系.png

k8s里的所有的資源對(duì)象都可以采用yaml或JSON格式的文件定義或描述商架,下面是某個(gè)Pod文件的資源定義文件堰怨。

apiSerdion: v1
kind: Pod
matadata:
  name: myweb
  labels:
    name: myweb
  spec:
    containers:
    - name: myweb
      image: kubeguide/tomcat-app:v1
      ports:
      - containerPort: 8080
      env:
      - name: MYSQL_SERVICE_HOST
        value: 'mysql'
      - name: MYSQL_SERVICE_PORT
        value: '3306'

kind為Pod表明這是一個(gè)Pod的定義;matadata的name屬性為Pod的名字蛇摸,還能定義資源對(duì)象的標(biāo)簽Label备图,這里聲明myweb擁有一個(gè)name=myweb的標(biāo)簽。Pod里面所包含的容器組的定義則在spec中聲明赶袄,這里定義一個(gè)名字為myweb揽涮,鏡像為kubeguide/tomcat-app:v1的容器,該容器注入了名為MYSQL_SERVICE_HOST='mysql'MYSQL_SERVICE_PORT='3306'的環(huán)境變量(env關(guān)鍵字)弃鸦。Pod的IP加上這里的容器端口(containerPort)就組成了一個(gè)新的概念Endpoint(端口)绞吁,它代表Pod的一個(gè)服務(wù)進(jìn)程對(duì)外的通信地址幢痘。一個(gè)Pod也存在著具有多個(gè)Endpoint的情況唬格,比如tomcat定義pod時(shí)候,可以暴露管理端口和服務(wù)端口兩個(gè)Endpoint颜说。

我們所熟悉的Docker Volume在k8s中也有相應(yīng)的概念 - Pod Volume购岗,后者有一些幻化,比如可以用分布式系統(tǒng)GlusterFS實(shí)現(xiàn)后端存儲(chǔ)功能门粪;Pod Volume是定義在Pod之上喊积,然后被各個(gè)容器掛載到自己的文件系統(tǒng)中的。

最后是k8s中Event的概念玄妈,Event是一個(gè)事件的記錄乾吻,記錄了時(shí)間的最早產(chǎn)生時(shí)間、最后重現(xiàn)時(shí)間拟蜻、重復(fù)次數(shù)绎签、發(fā)起者、類型及導(dǎo)致此次事件的原因等總舵信息酝锅。Event通常會(huì)關(guān)聯(lián)到某個(gè)具體的資源對(duì)象上诡必,是排查故障的重要信息參考信息。Node描述信息包含Event搔扁,而Pod同樣有Event記錄爸舒。當(dāng)我們發(fā)現(xiàn)某個(gè)Pod遲遲無(wú)法創(chuàng)建時(shí),可以用kubectl describe pod name來(lái)查看它的信息稿蹲,用來(lái)定位問(wèn)題的原因扭勉。

每個(gè)Pod都可以對(duì)其能使用的服務(wù)器上的計(jì)算資源設(shè)置限額,當(dāng)前可以設(shè)置的限額的計(jì)算資源有CPU和Memory兩種苛聘,其中CPU的資源單位為CPU(core)核數(shù)剖效,一個(gè)絕對(duì)值嫉入。

一個(gè)cpu的配額對(duì)絕大多數(shù)容器去是一個(gè)相當(dāng)大的資源配額,所以在k8s中璧尸,通常以千分之一的cpu配額為最小單位咒林,用m來(lái)表示,即一個(gè)容器的限額為100-300m爷光,即占用0.1-0.3個(gè)cpu限額垫竞。由于它是絕對(duì)值,所以無(wú)論在1個(gè)cpu的機(jī)器還是多個(gè)cpu的機(jī)器蛀序,這個(gè)100m的配額都是一樣的欢瞪。類似的Memory配額也是一個(gè)絕對(duì)值,單位是內(nèi)存字節(jié)數(shù)徐裸。

在k8s中遣鼓,一個(gè)計(jì)算資源進(jìn)行配額限定需要設(shè)定下面兩個(gè)參數(shù):

  • Request;該資源的最小申請(qǐng)量重贺,系統(tǒng)必須滿足要求骑祟。
  • Limits:該資源允許最大的使用量,不能被突破气笙,當(dāng)容器視圖使用超出這個(gè)量的資源時(shí)次企,可能會(huì)被k8s殺死并重啟。

通常會(huì)把Request設(shè)置為一個(gè)比較小的數(shù)值潜圃,符合同期平時(shí)的工作負(fù)載情況下的資源要求缸棵,而把Limit設(shè)置為峰值負(fù)載情況下資源占用的最大量。如下面的設(shè)定:

spec:
  containers:
  - name: db
    image: mysql
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

即表明mysql容器在申請(qǐng)最少0.25個(gè)cpu及64Mib的內(nèi)存谭期,在運(yùn)行過(guò)程中mysql容器所能使用的資源配額為0.5個(gè)cpu及128Mib的內(nèi)存堵第。

pod及周邊對(duì)象.png

2.4 Label(標(biāo)簽)

Label是k8s系統(tǒng)中另一個(gè)核心的概念。一個(gè)Label是一個(gè)key=value的鍵值對(duì)隧出,其中key和value由用戶自己指定踏志。Label對(duì)象可以附加到各種資源對(duì)象上面,如Node鸳劳、Pod狰贯、Service、RC等赏廓,一個(gè)資源對(duì)象可以定義任意數(shù)量的Label涵紊,同一個(gè)Label也可以被添加到任意資源對(duì)象上去,Label通常在資源對(duì)象定義時(shí)確定幔摸,也可以通過(guò)對(duì)象創(chuàng)建之后動(dòng)態(tài)添加或刪除摸柄。

我們可以通過(guò)給指定的資源對(duì)象捆綁一個(gè)或多個(gè)不同的Label來(lái)實(shí)現(xiàn)多維度的資源分組管理功能,以便于靈活既忆、方便地進(jìn)行資源分配驱负、調(diào)度嗦玖、配置和布署等管理工作。一些常用的label如下:

  • 版本控制:"release": "stable", "release": "canary"
  • 環(huán)境標(biāo)簽:"environment": "dev", "environment": "qa", "environment": "production"
  • 架構(gòu)標(biāo)簽:"tier": "frontend", "release": "backend", "release": "middkeware"
  • 分區(qū)標(biāo)簽:"partition": "customerA"
  • 質(zhì)量管控標(biāo)簽:"track": "daily", "track": "weekly"

給某個(gè)資源對(duì)象定義一個(gè)Label跃脊,隨后可以通過(guò)Label Selector(標(biāo)簽選擇器)查詢和篩選擁有某些Label的資源對(duì)象宇挫,k8s通過(guò)這種方式實(shí)現(xiàn)了類是SQL的簡(jiǎn)單通用的對(duì)象查詢方式。

當(dāng)前有兩種Label Selector的表達(dá)式:基于等式的(Equality-based)和基于集合(Set-based)酪术。

基于等式的表達(dá)式匹配標(biāo)簽實(shí)例:

  • name=redis-slave:匹配所有具有標(biāo)簽name=redis-slave的資源對(duì)象器瘪。
  • env!=production: 匹配不具有標(biāo)簽name=production的資源對(duì)象。

基于集合方式的表達(dá)式匹配標(biāo)簽實(shí)例:

  • name in (redis-slave, redis-master):匹配所有具有標(biāo)簽name=redis-slave或name=redis-master的資源對(duì)象绘雁。
  • name not in (php-frontend):匹配不具有標(biāo)簽name=php-frontend的資源對(duì)象橡疼。

可以通過(guò)多個(gè)Label Selector表達(dá)式的組合實(shí)現(xiàn)復(fù)雜的條件選擇,多個(gè)表達(dá)式之間用“,”分隔即可庐舟,幾個(gè)條件是and的關(guān)系欣除,即同時(shí)滿足多個(gè)條件,如:

  • name=redis-slave, env!=production
  • name not in (php-frontend), env!=production

Label Selector在k8s中重要使用場(chǎng)景有下面幾處:

  • kube-controller-manage進(jìn)程通過(guò)資源對(duì)象RC上定義的Label Selector來(lái)篩選要監(jiān)控的Pod副本的數(shù)量挪略。
  • kube-proxy進(jìn)程通過(guò)Service的Label Selector來(lái)選擇對(duì)于那個(gè)的Pod历帚,自動(dòng)建立起Service對(duì)應(yīng)每個(gè)Pod的請(qǐng)求轉(zhuǎn)發(fā)路由表,從而實(shí)現(xiàn)Service的智能負(fù)載均衡機(jī)制瘟檩。
  • 通過(guò)對(duì)某些Node定義特定的Label抹缕,并且Pod定義文件中使用NodeSelector這種標(biāo)簽調(diào)度策略澈蟆,kube-schedule進(jìn)程可以實(shí)現(xiàn)Pod“定向調(diào)度”的特性墨辛。

總結(jié):使用Label可以給資源對(duì)象創(chuàng)建多組標(biāo)簽,Label和Label Selector共同構(gòu)成了k8s系統(tǒng)中最核心的應(yīng)用模型趴俘,使得被管理對(duì)象能夠被精細(xì)地分組管理睹簇,同時(shí)實(shí)現(xiàn)了整個(gè)集群的高可用性。

2.5 Replication Controller(RC)

前面部分對(duì)Replication Controller(簡(jiǎn)稱RC)的定義和作用做了一些說(shuō)明寥闪,本節(jié)對(duì)RC的概念再進(jìn)行深入研究下太惠。

RC是k8s系統(tǒng)中的核心概念之一,簡(jiǎn)單來(lái)說(shuō)疲憋,它是定義了一個(gè)期望的場(chǎng)景凿渊。即聲明某種Pod的副本數(shù)量在任意時(shí)刻都符合某個(gè)預(yù)期值,所以RC的定義包含如下幾個(gè)部分:

  • Pod期待的副本數(shù)(replicas)缚柳。
  • 用于篩選目標(biāo)Pod的Label Selector埃脏。
  • 當(dāng)Pod的副本數(shù)量小于預(yù)期數(shù)量的時(shí)候,用于創(chuàng)建新Pod的Pod模版(templates)秋忙。

下面是一個(gè)完整的RC定義的例子彩掐,即確保擁有tier=frontend標(biāo)簽的這個(gè)Pod(運(yùn)行Tomcat容器)在整個(gè)集群中始終只有一個(gè)副本。

apiVersion: v1
kind: ReplicationController
metadata:
  name: frontend
spec:
  replicas: 1
  selector:
    tier: frontend
  templete:
    metadata:
      labels:
        app: app-demo
        tier: frontend
    spec:
      containers:
      - name: tomcat-demo
        image: tomcat
        imagePullPolicy: IfNotPresent
        env:
        - name: GET_HOSTS_FROM
          value: dns
        ports:
        - containerPort: 80

當(dāng)我們定義了一個(gè)RC并提交到k8s集群中以后灰追,Master節(jié)點(diǎn)上的Controller Manager組件就得到了通知堵幽,定期巡檢系統(tǒng)中當(dāng)前存活目標(biāo)的Pod狗超,并確保目標(biāo)Pod實(shí)例的數(shù)量剛好等于此RC的期望值。如果有過(guò)多的Pod副本在進(jìn)行朴下,系統(tǒng)就會(huì)停掉一些Pod努咐,否則系統(tǒng)會(huì)自動(dòng)創(chuàng)建一些Pod∨闺剩可以說(shuō)麦撵,通過(guò)RC,k8s實(shí)現(xiàn)了用戶應(yīng)用集群的高可用性溃肪,并且大大減少了系統(tǒng)管理員在傳統(tǒng)環(huán)境中完成許多的運(yùn)維工作(主機(jī)監(jiān)控免胃、應(yīng)用監(jiān)控、故障恢復(fù))惫撰。

需要注意的有幾點(diǎn):刪除RC并不會(huì)影響已經(jīng)通過(guò)該RC創(chuàng)建好的Pod羔沙。為了刪除所有的Pod,可以設(shè)置replicas為0厨钻,然后更新RC扼雏。另外,kubectl提供了stop和delete命令來(lái)一次性刪除RC和RC控制的全部Pod夯膀。

當(dāng)我們應(yīng)用升級(jí)時(shí)诗充,通常會(huì)通過(guò)Build一個(gè)新的Docker鏡像,并用新的鏡像版本來(lái)代替舊的版本方式達(dá)到目的诱建。在系統(tǒng)升級(jí)的過(guò)程中蝴蜓,我們希望是平滑的方式,如系統(tǒng)中10個(gè)對(duì)應(yīng)舊版本的Pod俺猿,最佳的方式就是就舊版本的Pod每次停止一個(gè)茎匠,同時(shí)創(chuàng)建一個(gè)新版本的Pod,在整個(gè)升級(jí)的過(guò)程中押袍,此消彼長(zhǎng)诵冒,而運(yùn)行中的Pod始終是10個(gè),幾分鐘后谊惭,當(dāng)所有的Pod都是新版本之后汽馋,升級(jí)過(guò)程完成。通過(guò)RC的機(jī)制圈盔,k8s很容易就實(shí)現(xiàn)這種高級(jí)實(shí)用的特性豹芯,被稱為“滾動(dòng)升級(jí)”(Rolling Update)

由于Replication Controller與k8s代碼中的模塊Replication Controller同名药磺,同時(shí)這個(gè)詞又無(wú)法準(zhǔn)確表達(dá)它的本意告组,所以在k8s1.2的時(shí)候,它就升級(jí)成了另外一個(gè)新的概念 - Replica Set癌佩,官網(wǎng)解釋為“下一代的RC”木缝。與當(dāng)前RC區(qū)別在于:Replica Sets支持基于集合的Label Selector(Set-based selector)便锨,而當(dāng)前RC只支持基于等式的Label Selector(equality-based selector)。

當(dāng)前我們很少使用Replica Set我碟,它主要被Deployment這個(gè)更高層的資源對(duì)象使用放案,從而形成一整套Pod的創(chuàng)建、刪除矫俺、更新的編排機(jī)制吱殉。當(dāng)我們使用Deployment時(shí),無(wú)需關(guān)系它是如何創(chuàng)建和維護(hù)Replica Set厘托,都是自動(dòng)完成的友雳。

Replica Set與Deployment這兩個(gè)重要的資源對(duì)象逐步替換了之前RC的作用,是k8s1.3 Pod自動(dòng)擴(kuò)容(伸縮)這個(gè)告警功能實(shí)現(xiàn)的基礎(chǔ)铅匹。

最后總結(jié)RC(Replica Set)的的一些特性與作用

  • 多數(shù)情況下押赊,我們通過(guò)定義一個(gè)RC實(shí)現(xiàn)Pod的創(chuàng)建過(guò)程及副本數(shù)量的自動(dòng)控制,可以實(shí)現(xiàn)Pod的彈性收縮包斑。
  • RC里包括完整的Pod定義模版流礁。
  • RC通過(guò)Label Selector機(jī)制實(shí)現(xiàn)對(duì)Pod的自動(dòng)控制。
  • 通過(guò)改變RC里Pod模版的鏡像版本罗丰,可以實(shí)現(xiàn)Pod的滾動(dòng)升級(jí)功能神帅。

2.6 Deployment

Deployment是k8s 1.2之后引入的新概念,引入的目的就是為了更好的解決Pod的編排問(wèn)題萌抵。為此找御,Deployment在內(nèi)部使用了Replica Set來(lái)實(shí)現(xiàn)目的,可以看作是RC的一次升級(jí)谜嫉。

Deployment典型使用場(chǎng)景有以下幾個(gè):

  • 創(chuàng)建一個(gè)Deployment對(duì)象來(lái)生成對(duì)應(yīng)的Replica Set并完成Pod副本的創(chuàng)建過(guò)程萎坷。
  • 檢查Deployment的狀態(tài)來(lái)看布署動(dòng)作是否完成(Pod副本的數(shù)量是否達(dá)到預(yù)期值)凹联。
  • 更新Deployment以創(chuàng)建新的Pod(如鏡像升級(jí))沐兰。
  • 如果當(dāng)前Deployment不穩(wěn)定,則回滾到早先的Deployment版本蔽挠。
  • 掛起或恢復(fù)一個(gè)Deployment住闯。

下面是一個(gè)實(shí)例,文件名為tomcat-deployment.yaml:

apiVersion:  extension/v1beta1
kind: Deployment
matadata:
  name: frontend
spec:
  replica: 1
  selector:
    matchLabels:
      tier: frontend
    matchExpressions:
      - {key: tier, operator: In, values: [frontend]}
  template:
    matadata:
      labels:
        app: app-demo
        tier: frontend
      spec:
        containers:
        - name: tomcat-demo
          image: tomcat
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 8080

命令kubectl create -f tomcat-deployment.yaml澳淑,命令以后再嘗試比原。

2.7 Horizontal Pod Autoscaler(HPA)

之前提到過(guò),通過(guò)手工執(zhí)行kubectl scale的命令杠巡,我們可以實(shí)現(xiàn)Pod擴(kuò)容或縮容量窘,但谷歌對(duì)k8s的定位是自動(dòng)化、智能化氢拥,即分布式系統(tǒng)要能根據(jù)當(dāng)前負(fù)載情況變化自動(dòng)觸發(fā)水平擴(kuò)展或縮容的行為蚌铜,因?yàn)檫@過(guò)程是頻繁發(fā)生锨侯、不可預(yù)料的。

k8s 1.1版本中首次發(fā)布這一特性:Horizontal Pod Autoscaling冬殃,隨后在1
2版本中HPA被升級(jí)為穩(wěn)定版本(apiVersion: autoscaling/v1)囚痴,但同時(shí)仍保留舊版本(apiVersion: extension/v1beta1),官方計(jì)劃是1.3移除舊版本审葬,1.4徹底移除舊版本的支持深滚。

Horizontal Pod Autoscaling(HPA),意味Pod的橫向自動(dòng)擴(kuò)容涣觉,與之前RC痴荐、Deployment一樣,也是k8s資源對(duì)象的一種官册。通過(guò)分析RC控制的所有目標(biāo)Pod的負(fù)載變化情況蹬昌,來(lái)確定是否需要針對(duì)性地調(diào)整目標(biāo)Pod的副本數(shù),即HPA的實(shí)現(xiàn)原理攀隔。當(dāng)前有下兩種方式作為Pod負(fù)載的度量指標(biāo)皂贩。

  • CPU Utilization Percentage。
  • 應(yīng)用程序自定義度量指標(biāo)昆汹,如服務(wù)每秒內(nèi)相應(yīng)的請(qǐng)求數(shù)(TPS或QPS)明刷。

CPU Utilization Percentage是一個(gè)算術(shù)平均值,即目標(biāo)Pod所有副本的CPU利用率的平均值满粗。一個(gè)Pod自身的CPU利用率是該P(yáng)od當(dāng)前CPU的使用量除以它的Pod Resquest的值辈末。如我們定義一個(gè)Pod的Pod Resquest為0.4,而當(dāng)前Pod的CPU使用量是0.2映皆,即它的CPU使用率是50%挤聘,如此我們就可以算出一個(gè)RC所控制的所有Pod副本的CPU利用率的算術(shù)平均值了。某一時(shí)刻捅彻,CPU Utilization Percentage的值超過(guò)80%组去,則意味著當(dāng)前Pod副本數(shù)量可能不支持接下來(lái)所有的請(qǐng)求,需要進(jìn)行動(dòng)態(tài)擴(kuò)容步淹,而請(qǐng)求高峰時(shí)段過(guò)去后从隆,Pod利用率又會(huì)降下來(lái),對(duì)應(yīng)Pod副本也會(huì)減少數(shù)量缭裆。

CPU Utilization Percentage 計(jì)算過(guò)程中使用到的Pod的COU的量通常是1分鐘的平均值键闺,目前通過(guò)查詢Heapster擴(kuò)展組件來(lái)得到這個(gè)值,所以需要安裝布署Heapster澈驼,這樣便增加了系統(tǒng)的復(fù)雜度和實(shí)施HPA特性的復(fù)雜度辛燥。未來(lái)的計(jì)劃是實(shí)現(xiàn)一個(gè)自身性能數(shù)據(jù)采集的模塊。

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
matadata:
  name: php-apache
  namespace: default
spec:
  maxReplica: 10
  minReplica: 1
  scaleTargetRef:
    kind: Deployment
    name: php-apache
  targetCPUUtilizationPercentage: 90

2.8 Service(服務(wù))

2.8.1 概述

Service同樣也是k8s核心資源對(duì)象之一,它即是我們常提起微服務(wù)構(gòu)架的一個(gè)“微服務(wù)”挎塌,之前我們說(shuō)的Pod畅铭、RC等資源對(duì)象其實(shí)都是為這節(jié)所說(shuō)的Service(服務(wù))做準(zhǔn)備的。

Pod勃蜘、RC與Service的關(guān)系.png

k8s的Service定義了一個(gè)服務(wù)的訪問(wèn)入口地址硕噩,前端的應(yīng)用(Pod)通過(guò)這個(gè)入口地址訪問(wèn)其背后由Pod副本組成的集群實(shí)例,Service和其后端Pod副本集群之間則是通過(guò)Label Selector來(lái)實(shí)現(xiàn)無(wú)縫對(duì)接的缭贡;RC的作用實(shí)際是保證Service的服務(wù)能力與服務(wù)質(zhì)量始終處于預(yù)期的標(biāo)準(zhǔn)炉擅。

通過(guò)分析、識(shí)別并建模系統(tǒng)中的所有服務(wù)為微服務(wù) - kubernetes Service阳惹,最終系統(tǒng)由多個(gè)提供不同業(yè)務(wù)能力而又彼此獨(dú)立的微服務(wù)單元所組成谍失,服務(wù)之間通過(guò)TCP/IP進(jìn)行通信,從而形成強(qiáng)大而又靈活的彈性網(wǎng)絡(luò)莹汤,擁有了強(qiáng)大的分布式能力快鱼、彈性擴(kuò)展能力、容錯(cuò)能力纲岭,同時(shí)程序架構(gòu)也變得靈活很多抹竹。

既然每個(gè)Pod都會(huì)被分配一個(gè)單獨(dú)的IP地址,而且每個(gè)Pod都提供了一個(gè)獨(dú)立Endpoint(Pod IP+ContainerPort)以被客戶端訪問(wèn)止潮,現(xiàn)在多個(gè)Pod副本組成了一個(gè)集群來(lái)提供服務(wù)窃判,一般的做法都是布署一個(gè)負(fù)載局衡器(軟件或硬件),為這組Pod開(kāi)啟一個(gè)對(duì)外的服務(wù)端口8000喇闸,并將這些Pod的Endpoint列表加入8000端口的轉(zhuǎn)發(fā)列表中袄琳,客戶端就可以通過(guò)負(fù)載均衡器的對(duì)外IP地址+服務(wù)器端口來(lái)訪問(wèn)此服務(wù),而客戶端的請(qǐng)求最后會(huì)被轉(zhuǎn)發(fā)到那個(gè)Pod燃乍,則由負(fù)載均衡器的算法決定唆樊。

k8s也遵循了上述做法,運(yùn)行在每個(gè)Node上的kube-proxy進(jìn)程其實(shí)就是只能的軟件負(fù)載均衡器刻蟹,它負(fù)責(zé)把對(duì)Service的請(qǐng)求轉(zhuǎn)發(fā)到后端的某個(gè)Pod上面逗旁,并在內(nèi)部實(shí)現(xiàn)服務(wù)的負(fù)載均衡和會(huì)話保持機(jī)制。但k8s發(fā)明了一種巧妙影響深遠(yuǎn)的設(shè)計(jì):Service不是共用一個(gè)負(fù)載均衡器的IP地址座咆,而是每個(gè)Service分配了一個(gè)全局唯一的虛擬IP地址痢艺,這個(gè)IP地址又被稱為Cluster IP。這樣的話,雖然Pod的Endpoint會(huì)隨著Pod的創(chuàng)建和銷毀而發(fā)生改變剧防,但是Cluster IP會(huì)伴隨Service的整個(gè)生命周期搞乏,只要通過(guò)Service的Name和Cluster IP進(jìn)行DNS域名映射,Pod的服務(wù)發(fā)現(xiàn)通過(guò)訪問(wèn)Service即可解決蚁吝。

2.8.2 k8s的服務(wù)發(fā)現(xiàn)機(jī)制

任何分布式系統(tǒng)都會(huì)有服務(wù)發(fā)現(xiàn)的基礎(chǔ)問(wèn)題,大部分的分布式系統(tǒng)通過(guò)提供特定的API接口黔帕,但這增加了系統(tǒng)的可侵入性某残。

最早k8s采用Linux環(huán)境變量去解決這個(gè)問(wèn)題国撵,即每個(gè)Service生成一些對(duì)應(yīng)的Linux變量(ENV),并在每個(gè)Pod容器在啟動(dòng)時(shí)玻墅,自動(dòng)注入這些環(huán)境變量介牙。后來(lái)k8s通過(guò)Add-On增值包的方式引入了DNS系統(tǒng),把服務(wù)名作為DNS域名澳厢,這樣程序就可以直接使用服務(wù)名來(lái)建立通信連接环础。

2.8.3 外部系統(tǒng)訪問(wèn)Service的問(wèn)題

為了更加深入的理解和掌握k8s,我們要弄明白k8s的三個(gè)IP的關(guān)鍵問(wèn)題:

  • Node IP:Node節(jié)點(diǎn)的IP地址剩拢。
  • Pod IP:Pod的IP地址线得。
  • Cluster IP:Service的IP地址。

Node IP是k8s集群中每個(gè)節(jié)點(diǎn)物理網(wǎng)卡的IP地址徐伐,這是一個(gè)真是存在的物理網(wǎng)絡(luò)贯钩,所有屬于這個(gè)網(wǎng)絡(luò)的服務(wù)器之間都能通過(guò)這個(gè)網(wǎng)絡(luò)直接通信,不管它們中是否有部分節(jié)點(diǎn)不屬于這個(gè)k8s集群办素。這也表明了k8s集群之外的節(jié)點(diǎn)訪問(wèn)的k8s集群內(nèi)的某個(gè)節(jié)點(diǎn)或者TCP/IP服務(wù)的時(shí)候角雷,必須通過(guò)Node IP進(jìn)行通信。

Pod IP是每個(gè)Pod的IP地址性穿,它是Docker Engine根據(jù)docker0網(wǎng)橋的IP地址段進(jìn)行分配的谓罗,通常是一個(gè)虛擬的二層網(wǎng)絡(luò)。前面說(shuō)過(guò)季二,k8s要求Pod里的容器訪問(wèn)另一個(gè)Pod的容器時(shí)檩咱,就是通過(guò)Pod IP所在的虛擬二層網(wǎng)絡(luò)進(jìn)行通信的,而真實(shí)的TCP/IP流量則是通過(guò)Node IP所在的物理網(wǎng)卡流出的胯舷。這個(gè)參考docker通信相關(guān)的細(xì)節(jié)刻蚯。

最后看Service的Cluster IP,它也是一個(gè)虛擬的IP桑嘶。更像一個(gè)假的IP:

  • Cluster IP僅僅作用域k8s Service這個(gè)對(duì)象炊汹,并由k8s管理和分配IP地址(來(lái)源Cluster IP地址池)。
  • Cluster IP無(wú)法被ping逃顶,因?yàn)闆](méi)有一個(gè)“網(wǎng)絡(luò)實(shí)體對(duì)象”來(lái)響應(yīng)讨便。
  • Cluster IP只能結(jié)合Service Port組成一個(gè)具體的通信端口,單獨(dú)的Cluster IP不具備TCP/IP通信的基礎(chǔ)以政,并且它們屬于k8s集群這樣一個(gè)封閉的空間霸褒,集群之外節(jié)點(diǎn)若想訪問(wèn)這個(gè)通信端口,需要做額外的操作盈蛮。
  • 在k8s集群之內(nèi)废菱,Node IP網(wǎng)、Pod IP網(wǎng)與Cluster IP網(wǎng)之間的通信,采用的是k8s自己設(shè)計(jì)的一種編程方式的特殊的路由規(guī)則殊轴,和我們熟知的IP路由有很大的不同衰倦。

那么基于上述,我們知道:Service的Cluster IP屬于k8s集群內(nèi)部的地址旁理,無(wú)法在集群外部直接使用這個(gè)地址樊零。那么矛盾在實(shí)際中就是開(kāi)發(fā)的業(yè)務(wù)肯定是一部分提供給k8s集群外部的應(yīng)用或用戶使用的,典型的就是web孽文,那用戶如何訪問(wèn)驻襟。

采用NodePort是解決上述最直接、最常用叛溢、最有效的方法塑悼。

apiVersion: v1
kind: Service
metadata:
  name: tomcat-service
spec:
  type: NodePort
  ports:
  - port: 8080
    nodePort: 31002
  selector:
    tier: frontend

nodePort: 31002這個(gè)屬性表名我們手動(dòng)指定tomcat-service的NodePort為31002,否則k8s就會(huì)自動(dòng)分配一個(gè)可用的端口楷掉,這個(gè)端口我們可以直接在瀏覽器中訪問(wèn):http://<nodePort IP>:31002厢蒜。

NodePort的實(shí)現(xiàn)方式就是在k8s集群里每個(gè)Node上為外部訪問(wèn)的Service開(kāi)啟一個(gè)對(duì)應(yīng)的TCP監(jiān)聽(tīng)端口,外部系統(tǒng)只要用任意一個(gè)Node的IP地址和具體的NodePort端口號(hào)就能訪問(wèn)這個(gè)服務(wù)烹植。在任意的Node上運(yùn)行netstat命令斑鸦,我們就能看到NodePort端口被監(jiān)聽(tīng)。

但NodePort并沒(méi)有完全解決Service的所有問(wèn)題草雕,如負(fù)載均衡的問(wèn)題巷屿。假如我們的集群中10個(gè)Node,則此時(shí)最好有一個(gè)均衡負(fù)載器墩虹,外部的請(qǐng)求只需要訪問(wèn)此負(fù)載均衡器的IP地址嘱巾,則負(fù)載均衡器負(fù)責(zé)轉(zhuǎn)發(fā)流量到后面某個(gè)Node的NodePort上面。

NodePort與Load Balance.png

Load Balance組件獨(dú)立于k8s集群之外诫钓,通常是一個(gè)硬件的負(fù)載均衡器或是軟件方式實(shí)現(xiàn)的旬昭,如HAProxy或Nginx。對(duì)每個(gè)Service菌湃,我們通常配置一個(gè)對(duì)應(yīng)的Load Balance的實(shí)例來(lái)轉(zhuǎn)發(fā)流量到后端的Node上问拘,這增加了工作量即出錯(cuò)的概率。

未完惧所、待續(xù)……

2.9 Volume(存儲(chǔ)卷)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末骤坐,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子下愈,更是在濱河造成了極大的恐慌纽绍,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件驰唬,死亡現(xiàn)場(chǎng)離奇詭異顶岸,居然都是意外死亡腔彰,警方通過(guò)查閱死者的電腦和手機(jī)叫编,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門辖佣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人搓逾,你說(shuō)我怎么就攤上這事卷谈。” “怎么了霞篡?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵世蔗,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我朗兵,道長(zhǎng)污淋,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任余掖,我火速辦了婚禮寸爆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘盐欺。我一直安慰自己赁豆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布冗美。 她就那樣靜靜地躺著魔种,像睡著了一般。 火紅的嫁衣襯著肌膚如雪粉洼。 梳的紋絲不亂的頭發(fā)上节预,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音属韧,去河邊找鬼安拟。 笑死,一個(gè)胖子當(dāng)著我的面吹牛挫剑,可吹牛的內(nèi)容都是我干的去扣。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼樊破,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼愉棱!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起哲戚,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤奔滑,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后顺少,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體朋其,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡王浴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了梅猿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片氓辣。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖袱蚓,靈堂內(nèi)的尸體忽然破棺而出钞啸,到底是詐尸還是另有隱情,我是刑警寧澤喇潘,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布体斩,位于F島的核電站,受9級(jí)特大地震影響颖低,放射性物質(zhì)發(fā)生泄漏絮吵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一忱屑、第九天 我趴在偏房一處隱蔽的房頂上張望蹬敲。 院中可真熱鬧,春花似錦想幻、人聲如沸粱栖。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)闹究。三九已至,卻和暖如春食店,著一層夾襖步出監(jiān)牢的瞬間渣淤,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工吉嫩, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留价认,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓自娩,卻偏偏與公主長(zhǎng)得像用踩,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子忙迁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容