Kubernetes之NetworkPolicy,F(xiàn)lannel和Calico

Pod是Kubernetes調(diào)度的最小單元爹橱。一個(gè)Pod可以包含一個(gè)或多個(gè)容器庶灿,因此它可以被看作是內(nèi)部容器的邏輯宿主機(jī)纵搁。Pod的設(shè)計(jì)理念是為了支持多個(gè)容器在一個(gè)Pod中共享網(wǎng)絡(luò)和文件系統(tǒng)。那么為什么Pod內(nèi)的容器能夠共享網(wǎng)絡(luò)往踢,IPC和PID命名空間腾誉?

原因:Kubernetes在每個(gè)Pod啟動時(shí),會自動創(chuàng)建一個(gè)鏡像為gcr.io/google_containers/pause:version的容器峻呕,所有處于該P(yáng)od中的容器在啟動時(shí)都會添加諸如--net=container:pause --ipc=contianer:pause --pid=container:pause的啟動參數(shù)利职,因此Pod內(nèi)所有容器共用pause容器的network,IPC和PID命名空間瘦癌。所有容器共享pause容器的IP地址猪贪,也被稱為Pod IP。因此處于同一個(gè)Pod內(nèi)的容器讯私,可以通過localhost進(jìn)行相互訪問热押。

在講K8s Pod間通信前,我們先復(fù)習(xí)一下Docker容器間的網(wǎng)絡(luò)通信斤寇。默認(rèn)情況下桶癣,Docker使用一種名為bridge的網(wǎng)絡(luò)模型。如下圖所示:

bridge.png

Docker引擎在啟動時(shí)娘锁,會在宿主機(jī)上創(chuàng)建一個(gè)名為docker0的虛擬網(wǎng)橋牙寞,這個(gè)虛擬網(wǎng)橋負(fù)責(zé)給所有容器分配不重復(fù)的ip地址以及容器間的網(wǎng)絡(luò)通信。首先致盟,Docker在創(chuàng)建一個(gè)容器時(shí)碎税,會執(zhí)行以下操作:

  1. 創(chuàng)建一對veth pair尤慰,一端置于容器中馏锡,一端置于docker0虛擬網(wǎng)橋中,從而實(shí)現(xiàn)網(wǎng)橋和容器的通信伟端。
  2. 將容器中的veth命名為eth0杯道,docker0網(wǎng)橋中的veth指定一個(gè)唯一的名字,例如veth0ac884e
  3. 從docker0網(wǎng)橋可用的地址段中選取一個(gè)分配給容器责蝠,并配置默認(rèn)路由到docker0網(wǎng)橋的veth0ac884e
  4. 這樣党巾,容器就能夠通過虛擬網(wǎng)卡eth0和其他容器進(jìn)行通信了。當(dāng)該容器結(jié)束后霜医,eth0會隨該容器的網(wǎng)絡(luò)命名空間一起被清除齿拂,相對應(yīng)的veth0ac884e也會被docker0網(wǎng)橋自動卸載掉。

通過這個(gè)docker0網(wǎng)橋肴敛,同一宿主機(jī)上的容器可以互相通信署海。然而由于宿主機(jī)的IP地址與容器veth pair的 IP地址均不在同一個(gè)網(wǎng)段吗购,故僅僅依靠veth pair和namespace的技術(shù),還不足以使宿主機(jī)以外的網(wǎng)絡(luò)主動發(fā)現(xiàn)容器的存在砸狞。為了使外界可以訪問容器中的進(jìn)程捻勉,docker采用了端口綁定的方式,也就是通過iptables的NAT刀森,將宿主機(jī)上的端口端口流量轉(zhuǎn)發(fā)到容器內(nèi)的端口上踱启。

K8s 中的網(wǎng)絡(luò)

K8s 默認(rèn)不提供網(wǎng)絡(luò)功能,所有Pod的網(wǎng)絡(luò)功能研底,都依賴于宿主機(jī)上的Docker埠偿。因此,Pod IP即是依靠docker0網(wǎng)橋分配給pause容器的虛擬IP榜晦。

同一個(gè)Node上Pod的通信

同一個(gè)Node內(nèi)胚想,不同的Pod都有一個(gè)docker0網(wǎng)橋分配的IP,可以直接通過這個(gè)IP進(jìn)行通信芽隆。Pod IP和docker0在同一個(gè)網(wǎng)段浊服。因此,當(dāng)同節(jié)點(diǎn)上的Pod-A發(fā)包給Pod-B時(shí)胚吁,包傳送路線如下:

pod-a的eth0—>pod-a的vethxxx—>bridge0—>pod-b的vethxxx—>pod-b的eth0

不同Node間Pod的通信

不同的Node之間牙躺,Node的IP相當(dāng)于外網(wǎng)IP,可以直接訪問腕扶,而Node內(nèi)的docker0和Pod的IP則是內(nèi)網(wǎng)IP孽拷,無法直接跨Node訪問。因此半抱,不同Node上的Pod間需要通信脓恕,需要滿足以下兩個(gè)條件:

  1. 對整個(gè)集群中的Pod-IP分配進(jìn)行規(guī)劃,不能有沖突
  2. 將Node-IP與該Node上的Pod-IP關(guān)聯(lián)起來窿侈,通過Node-IP再轉(zhuǎn)發(fā)到Pod-IP

因此炼幔,為了實(shí)現(xiàn)以上兩個(gè)需求,K8s提供了CNI(Container Network Interface)供第三方實(shí)現(xiàn)從而進(jìn)行網(wǎng)絡(luò)管理史简。由此出現(xiàn)了一系列開源的Kubernetes中的網(wǎng)絡(luò)插件與方案乃秀,包括:flannel,calico圆兵,cilium等等跺讯。這些網(wǎng)絡(luò)插件集中解決了以下需求:

  • 保證每個(gè)Pod擁有一個(gè)集群內(nèi)唯一的IP地址
  • 保證不同節(jié)點(diǎn)的IP地址劃分不會重復(fù)
  • 保證跨節(jié)點(diǎn)的Pod可以互相通信
  • 保證不同節(jié)點(diǎn)的Pod可以與跨節(jié)點(diǎn)的主機(jī)互相通信

CNI的介紹請參考這篇文章:https://jimmysong.io/kubernetes-handbook/concepts/cni.html

Flannel介紹

在默認(rèn)的Docker配置中,每個(gè)節(jié)點(diǎn)上的Docker服務(wù)會分別負(fù)責(zé)所在節(jié)點(diǎn)容器的IP分配殉农。這樣導(dǎo)致的一個(gè)問題是刀脏,不同節(jié)點(diǎn)上容器可能獲得相同的內(nèi)外IP地址。

Flannel的設(shè)計(jì)目的就是為集群中的所有節(jié)點(diǎn)重新規(guī)劃IP地址的使用規(guī)則超凳,從而使得不同節(jié)點(diǎn)上的容器能夠獲得“同屬一個(gè)內(nèi)網(wǎng)”且”不重復(fù)的”IP地址愈污,并讓屬于不同節(jié)點(diǎn)上的容器能夠直接通過內(nèi)網(wǎng)IP通信危队。

Flannel實(shí)質(zhì)上是一種“覆蓋網(wǎng)絡(luò)(overlay network)”,也就是將TCP數(shù)據(jù)包裝在另一種網(wǎng)絡(luò)包里面進(jìn)行路由轉(zhuǎn)發(fā)和通信钙畔,目前已經(jīng)支持UDP茫陆、VxLAN、AWS VPC和GCE路由等數(shù)據(jù)轉(zhuǎn)發(fā)方式擎析,默認(rèn)的節(jié)點(diǎn)間數(shù)據(jù)通信方式是UDP轉(zhuǎn)發(fā)簿盅。下圖展示了數(shù)據(jù)包在flannel中的流轉(zhuǎn):

flannel.png
flannel2.png
  1. 數(shù)據(jù)從源容器中發(fā)出后,經(jīng)由所在主機(jī)的docker0虛擬網(wǎng)卡轉(zhuǎn)發(fā)到flannel0虛擬網(wǎng)卡揍魂,這是個(gè)P2P的虛擬網(wǎng)卡桨醋,flanneld服務(wù)監(jiān)聽在網(wǎng)卡的另外一端。
  2. Flannel在Etcd服務(wù)維護(hù)了一張節(jié)點(diǎn)間的路由表现斋。
  3. 源主機(jī)的flanneld服務(wù)將原本的數(shù)據(jù)內(nèi)容UDP封裝后根據(jù)自己的路由表投遞給目的節(jié)點(diǎn)的flanneld服務(wù)喜最,數(shù)據(jù)到達(dá)以后被解包,然后直接進(jìn)入目的節(jié)點(diǎn)的flannel0虛擬網(wǎng)卡庄蹋,然后被轉(zhuǎn)發(fā)到目的主機(jī)的docker0虛擬網(wǎng)卡瞬内,最后就像本機(jī)容器通信一下的有docker0路由到達(dá)目標(biāo)容器。

更多關(guān)于flannel的解析限书,請參考:https://jimmysong.io/kubernetes-handbook/concepts/flannel.html

Calico介紹

Flannel是一種典型的Overlay網(wǎng)絡(luò)虫蝶,它將已有的物理網(wǎng)絡(luò)(Underlay網(wǎng)絡(luò))作為基礎(chǔ),在其上建立疊加的邏輯網(wǎng)絡(luò)倦西,實(shí)現(xiàn)網(wǎng)絡(luò)資源的虛擬化能真。Overlay網(wǎng)絡(luò)有一定額外的封包和解包等網(wǎng)絡(luò)開銷,對網(wǎng)絡(luò)通信的性能有一定損耗扰柠。

Calico是純?nèi)龑拥腟DN 實(shí)現(xiàn)粉铐,它基于BPG 協(xié)議和Linux自身的路由轉(zhuǎn)發(fā)機(jī)制,不依賴特殊硬件卤档,容器通信也不依賴iptables NAT或Tunnel 等技術(shù)蝙泼。能夠方便的部署在物理服務(wù)器、虛擬機(jī)(如 OpenStack)或者容器環(huán)境下裆装。同時(shí)calico自帶的基于iptables的ACL管理組件非常靈活踱承,能夠滿足比較復(fù)雜的安全隔離需求。

  • Calico創(chuàng)建和管理一個(gè)扁平的三層網(wǎng)絡(luò)(不需要overlay)哨免,每個(gè)容器會分配一個(gè)可路由的IP。由于通信時(shí)不需要解包和封包昙沦,網(wǎng)絡(luò)性能損耗小琢唾,易于排查,且易于水平擴(kuò)展盾饮。
  • 小規(guī)模部署時(shí)可以通過BGP client直接互聯(lián)采桃,大規(guī)模下可通過指定的BGP Route Reflector來完成懒熙,這樣保證所有的數(shù)據(jù)流量都是通過IP路由的方式完成互聯(lián)的。
  • Calico基于iptables還提供了豐富而靈活的網(wǎng)絡(luò)Policy普办,保證通過各個(gè)節(jié)點(diǎn)上的ACL來提供Workload的多租戶隔離工扎、安全組以及其他可達(dá)性限制等功能。

iptable是內(nèi)核中的一個(gè)網(wǎng)絡(luò)數(shù)據(jù)包處理模塊衔蹲,它具有網(wǎng)絡(luò)數(shù)據(jù)包修改肢娘,網(wǎng)絡(luò)地址轉(zhuǎn)換(NAT)等功能。而Routes路由表存儲著指向特定網(wǎng)絡(luò)地址的路徑舆驶,即下一跳的地址橱健。ACL其實(shí)是一種報(bào)文過濾器,根據(jù)ACL中的匹配條件對進(jìn)站和出站的報(bào)文進(jìn)行過濾處理沙廉。

calico.png
  • Etcd:負(fù)責(zé)存儲網(wǎng)絡(luò)信息
  • BGP client:負(fù)責(zé)將Felix配置的路由信息分發(fā)到其他節(jié)點(diǎn)
  • Felix:Calico Agent拘荡,每個(gè)節(jié)點(diǎn)都需要運(yùn)行,主要負(fù)責(zé)配置路由撬陵、配置ACLs珊皿、報(bào)告狀態(tài)
  • BGP Route Reflector:大規(guī)模部署時(shí)需要用到,作為BGP client的中心連接點(diǎn)巨税,可以避免每個(gè)節(jié)點(diǎn)互聯(lián)
calico2.png

Calico 還基于 iptables 還提供了豐富而靈活的網(wǎng)絡(luò) policy, 保證通過各個(gè)節(jié)點(diǎn)上的 ACLs 來提供 workload 的多租戶隔離亮隙、安全組以及其他可達(dá)性限制等功能。

calico3.png

calico4.png

核心問題是垢夹,nodeA怎樣得知下一跳的地址溢吻?答案是node之間通過BGP協(xié)議交換路由信息。

每個(gè)node上運(yùn)行一個(gè)軟路由軟件bird果元,并且被設(shè)置成BGP Speaker促王,與其它node通過BGP協(xié)議交換路由信息。

可以簡單理解為而晒,每一個(gè)node都會向其它node通知這樣的信息:

我是X.X.X.X蝇狼,某個(gè)IP或者網(wǎng)段在我這里,它們的下一跳地址是我倡怎。

通過這種方式每個(gè)node知曉了每個(gè)workload-endpoint的下一跳地址迅耘。

更多關(guān)于Calico的文章,請參考:
https://jimmysong.io/kubernetes-handbook/concepts/calico.html
https://blog.51cto.com/dengaosky/2069666
https://cloud.tencent.com/developer/article/1482739
https://qiankunli.github.io/2018/02/04/calico.html

K8s NetworkPoclicy

K8s NetworkPoclicy 用于實(shí)現(xiàn)Pod間的網(wǎng)絡(luò)隔離监署。在使用Network Policy前颤专,必須先安裝支持K8s NetworkPoclicy的網(wǎng)絡(luò)插件,包括:Calico钠乏,Romana栖秕,Weave Net,Trireme晓避,OpenContrail等簇捍。

Pod的網(wǎng)絡(luò)隔離

在未使用NetworkPolicy前只壳,K8s中所有的Pod并不存在網(wǎng)絡(luò)隔離,他們能夠接收任何網(wǎng)絡(luò)流量暑塑。一旦使用NetworkPolicy選中某個(gè)namespace下的某些Pod吼句,那么這些Pod只能接收特定來源的流量(由Ingress屬性定義),并且只能向特定出口發(fā)送網(wǎng)絡(luò)請求(由Egress屬性定義)事格。其他未被這個(gè)NetworkPolicy選中的Pod惕艳,依然不具備網(wǎng)絡(luò)隔離。

下面是一個(gè)NetworkPolicy的例子:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978
  • podSelector: 用于定義這個(gè)NetworkPolicy適用于哪些Pod分蓖。如果其值為空尔艇,則表示適用于所有此namespace下的Pod
  • policyTypes: 包含兩個(gè)可選值:用于控制進(jìn)入流量的Ingress和控制出口流量的Egress
  • ingress: 用于定義能夠進(jìn)入Pod的流量的規(guī)則。例子中允許三種流量與podSelector選中的Pod的6379端口進(jìn)行通信么鹤,三種流量分別為:ip地址位于172.17.0.0/16網(wǎng)段內(nèi)的流量(但不包括172.17.1.0/24)允許與目標(biāo)Pod通信终娃,任何擁有role=frontend的label的Pod的流量允許進(jìn)入,任何擁有l(wèi)abel "project=myproject"的namespace下的Pod的流量允許進(jìn)入蒸甜。其他任何進(jìn)入流量將被禁止棠耕。
  • egress: 用于定義允許的出口流量。上面的例子中表示podSelector選中的Pod能夠向10.0.0.0/24的5978端口發(fā)送TCP請求柠新。其他任何TCP出流量都將被禁止窍荧。

下面的例子表示默認(rèn)禁止所有Pod間的Ingress流量:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
spec:
  podSelector: {}
  policyTypes:
  - Ingress

默認(rèn)拒絕所有 Pod 之間 Egress 通信的策略為:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
spec:
  podSelector: {}
  policyTypes:
  - Egress

而默認(rèn)允許所有 Pod 之間 Ingress 通信的策略為:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all
spec:
  podSelector: {}
  ingress:
  - {}

默認(rèn)允許所有 Pod 之間 Egress 通信的策略為:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all
spec:
  podSelector: {}
  egress:
  - {}

calico 實(shí)例

以 calico 為例看一下 Network Policy 的具體用法。首先配置 kubelet 使用 CNI 網(wǎng)絡(luò)插件:

kubelet --network-plugin=cni --cni-conf-dir=/etc/cni/net.d --cni-bin-dir=/opt/cni/bin ...

安裝 calio 網(wǎng)絡(luò)插件:

kubectl apply -f https://docs.projectcalico.org/v3.0/getting-started/kubernetes/installation/hosted/kubeadm/1.7/calico.yaml

首先部署一個(gè) nginx 服務(wù)恨憎,此時(shí)蕊退,通過其他 Pod 是可以訪問 nginx 服務(wù)的:

$ kubectl run nginx --image=nginx --replicas=2
deployment "nginx" created
$ kubectl expose deployment nginx --port=80
service "nginx" exposed

開啟 default namespace 的 DefaultDeny Network Policy 后,其他 Pod(包括 namespace 外部)不能訪問 nginx 了:

$ cat default-deny.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
spec:
  podSelector: {}
  policyTypes:
  - Ingress

$ kubectl create -f default-deny.yaml

$ kubectl run busybox --rm -ti --image=busybox /bin/sh
Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false

Hit enter for command prompt

/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.100.0.16:80)
wget: download timed out
/ #

最后再創(chuàng)建一個(gè)運(yùn)行帶有 access=true label的 Pod 訪問的網(wǎng)絡(luò)策略:

$ cat nginx-policy.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: access-nginx
spec:
  podSelector:
    matchLabels:
      run: nginx
  ingress:
  - from:
    - podSelector:
        matchLabels:
          access: "true"

$ kubectl create -f nginx-policy.yaml
networkpolicy "access-nginx" created

# 不帶 access=true 標(biāo)簽的 Pod 還是無法訪問 nginx 服務(wù)
$ kubectl run busybox --rm -ti --image=busybox /bin/sh
Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false

Hit enter for command prompt

/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.100.0.16:80)
wget: download timed out
/ #


# 而帶有 access=true 標(biāo)簽的 Pod 可以訪問 nginx 服務(wù)
$ kubectl run busybox --rm -ti --labels="access=true" --image=busybox /bin/sh
Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false

Hit enter for command prompt

/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.100.0.16:80)
/ #

參考文章

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末憔恳,一起剝皮案震驚了整個(gè)濱河市瓤荔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌钥组,老刑警劉巖输硝,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異程梦,居然都是意外死亡点把,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門屿附,熙熙樓的掌柜王于貴愁眉苦臉地迎上來郎逃,“玉大人,你說我怎么就攤上這事拿撩∫吕澹” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵压恒,是天一觀的道長影暴。 經(jīng)常有香客問我,道長探赫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮员咽,結(jié)果婚禮上惹骂,老公的妹妹穿的比我還像新娘。我一直安慰自己毛仪,他們只是感情好搁嗓,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著箱靴,像睡著了一般腺逛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上衡怀,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天棍矛,我揣著相機(jī)與錄音,去河邊找鬼抛杨。 笑死够委,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的怖现。 我是一名探鬼主播茁帽,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼屈嗤!你這毒婦竟也來了潘拨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤恢共,失蹤者是張志新(化名)和其女友劉穎战秋,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體讨韭,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡脂信,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了透硝。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狰闪。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖濒生,靈堂內(nèi)的尸體忽然破棺而出埋泵,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布丽声,位于F島的核電站礁蔗,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏雁社。R本人自食惡果不足惜浴井,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望霉撵。 院中可真熱鬧磺浙,春花似錦、人聲如沸徒坡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽喇完。三九已至伦泥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間何暮,已是汗流浹背奄喂。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留海洼,地道東北人跨新。 一個(gè)月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像坏逢,于是被迫代替她去往敵國和親域帐。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355

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