四、Kubernetes集群安装

参见:https://www.cnblogs.com/syuee/p/15057847.html

1、集群安装

一、 主机准备

1、设置主机名以及host文件的相互解析: 

hostnamectl set-hostname k8s-master01   

vi /etc/hosts        192.168.66.10  k8s-master01  (在大型环境建议通过DNS的方式,让主机名和ip能够相互解析)

2、安装必要的依赖包

yum install -y conntrack ntpdate ntp ipvsadm ipset jq iptables curl sysstat libseccomp wget vim net-tools git

3、设置防火墙为Iptables并设置空规则 

iptables 是一个功能强大的网络包过滤和转发工具,它可以帮助管理员配置和管理系统的网络安全策略,实现防火墙、网络地址转换和数据包修改等功能。通过合理配置 iptables 规则,可以增强系统的网络安全性和灵活性。

systemctl stop firewalld && systemctl disable firewalld

yum -y install ipatbles-service && systemctl start iptables && systemctl enable ipatbles && ipatbles -f && service ipatables save

(安装 iptables 服务,启动该服务。并设置 iptables 服务在系统启动时自动启动。最后,它会刷新规则、保存配置)

4、关闭SELINUX

swapoff -a && sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab     

(禁用系统上的所有 Swap 分区。在 /etc/fstab 文件中找到包含关键字 "swap" 的行,并将其替换为以 "#" 开头的注释行。)

setenforce 0 && sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config 

(这个命令用于将 SELinux 安全模块设置为 "Permissive" 模式。SELinux 是一种强制访问控制(MAC)机制,用于加强 Linux 系统的安全性。通过将 SELinux 设置为 "Permissive" 模式,系统仍然会记录违规行为,但不会阻止它们。这样可以临时禁用 SELinux 的强制访问控制,以便进行一些需要临时关闭 SELinux 的操作。将 /etc/selinux/config 文件中的 SELINUX 参数的值修改为 "disabled",从而永久禁用 SELinux。)  

5、调整内核参数,对于k8s

cat > kubernetes.conf <<EOF

net.bridge.bridge-nf-call-iptables=1 #开启网桥模式

net.bridge.bridge-nf-call-ip6tables=1 #开启网桥模式

net.ipv4.ip_forward=1 #设置包转发

net.ipv4.tcp_tw_recycle=0

vm.swappiness=0 # 禁止使用 swap 空间,只有当系统 OOM 时才允许使用它

vm.overcommit_memory=1 # 不检查物理内存是否够用

vm.panic_on_oom=0 # 开启 OOM

fs.inotify.max_user_instances=8192

fs.inotify.max_user_watches=1048576

fs.file-max=52706963

fs.nr_open=52706963

net.ipv6.conf.all.disable_ipv6=1 #关闭IPV6协议

net.netfilter.nf_conntrack_max=2310720

EOF

cp kubernetes.conf /etc/sysctl.d/kubernetes.conf

sysctl -p /etc/sysctl.d/kubernetes.conf    手动刷新生效

6、调整系统时区

# 设置系统时区为 中国/上海

timedatectl set-timezone Asia/Shanghai

# 将当前的 UTC 时间写入硬件时钟

timedatectl set-local-rtc 0

# 重启依赖于系统时间的服务

systemctl restart rsyslog

systemctl restart crond

7、关闭系统不需要服务

Postfix 是一个邮件传输代理(MTA),它用于发送、接收和路由电子邮件。

systemctl stop postfix && systemctl disable postfix

8、设置 rsyslogd 和 systemd journald

rsyslogd 和 systemd journald 是两种不同的日志管理系统,用于收集、存储和管理系统日志。主要区别:

rsyslogd 是传统的 syslog 系统,而 systemd journald 是 systemd 系统的一部分。

rsyslogd 使用文本文件存储日志,而 systemd journald 使用二进制格式存储日志。

rsyslogd 支持更广泛的日志转发和处理选项,而 systemd journald 提供了更强大的查询和过滤功能。

rsyslogd 可以与其他日志处理工具集成,而 systemd journald 是 systemd 系统的默认日志管理工具。

mkdir /var/log/journal # 持久化保存日志的目录

mkdir /etc/systemd/journald.conf.d

cat > /etc/systemd/journald.conf.d/99-prophet.conf <<EOF

[Journal]

# 持久化保存到磁盘

Storage=persistent

# 压缩历史日志

Compress=yes

SyncIntervalSec=5m

RateLimitInterval=30s

RateLimitBurst=1000

# 最大占用空间 10G

SystemMaxUse=10G

# 单日志文件最大 200M

SystemMaxFileSize=200M

# 日志保存时间 2 周

MaxRetentionSec=2week

# 不将日志转发到 syslog

ForwardToSyslog=no

EOF

systemctl restart systemd-journald

9、升级系统内核为4.44

CentOS 7.x 系统自带的 3.10.x 内核存在一些 Bugs,导致运行的 Docker、Kubernetes 不稳定,例如: rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm

rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm

# 安装完成后检查 /boot/grub2/grub.cfg 中对应内核 menuentry 中是否包含 initrd16 配置,如果没有,再安装 一次!

yum --enablerepo=elrepo-kernel install -y kernel-lt

# 设置开机从新内核启动

grub2-set-default 'CentOS Linux (4.4.189-1.el7.elrepo.x86_64) 7 (Core)'

grub2-set-default 'CentOS Linux (4.4.218-1.el7.elrepo.x86_64) 7 (Core)'

grub2-set-default 'CentOS Linux (4.4.219-1.el7.elrepo.x86_64) 7 (Core)'

查看所有可用内核

awk -F \' '$1=="menuentry " {print i++ " : " $2}' /etc/grub2.cfg

grub2-set-default 'CentOS Linux (4.4.248-1.el7.elrepo.x86_64) 7 (Core)'

二、 kube-proxy 开启ipvs的前置条件

modprobe br_netfilter

cat > /etc/sysconfig/modules/ipvs.modules << EOF

#!/bin/bash

modprobe -- ip_vs

modprobe -- ip_vs_rr

modprobe -- ip_vs_wrr

modprobe -- ip_vs_sh

modprobe -- nf_conntrack_ipv4

EOF

(modprobe -- ip_vs:这个命令用于加载名为 ip_vs 的内核模块。ip_vs 模块是 Linux 内核中的一个模块,提供了 IP 虚拟服务器(IPVS)的功能,用于实现负载均衡和集群服务。

modprobe -- ip_vs_rr、modprobe -- ip_vs_wrr、modprobe -- ip_vs_sh:这些命令用于加载与 IPVS 相关的调度器模块。ip_vs_rr 是基于轮询的调度器,ip_vs_wrr 是基于加权轮询的调度器,ip_vs_sh 是基于散列的调度器。这些调度器用于决定负载均衡时数据包的路由方式。

modprobe -- nf_conntrack_ipv4:这个命令用于加载名为 nf_conntrack_ipv4 的内核模块。nf_conntrack_ipv4 模块是 Linux 内核中的一个模块,提供了 IPv4 连接跟踪的功能,用于跟踪和管理网络连接状态。)

chmod 755 /etc/sysconfig/modules/ipvs.modules && \bash /etc/sysconfig/modules/ipvs.modules &&\lsmod | grep -e ip_vs -e nf_conntrack_ipv4

(加载和配置一些 IPVS 相关的内核模块 。使用 lsmod 命令列出当前加载的内核模块,并通过 grep 命令进行过滤,只显示包含 ip_vs 或 nf_conntrack_ipv4 的模块信息。)

三、 安装docker软件

yum install -y yum-utils device-mapper-persistent-data lvm2

yum-config-manager \

--add-repo \ http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

yum update -y && yum install -y docker-ce   ##先更新系统中已安装的软件包到最新版本,然后安装 Docker 社区版。

此时k8s的版本可能已经更改,uname -r 查看是否之前设置的4.44,如果不是,重新设置默认版本,再重启。grub2-set-default 'CentOS Linux (4.4.189-1.el7.elrepo.x86_64) 7 (Core)'  && reboot 

systemctl start docker  ##重启docker

systemctl enable docker ##设置开机自启

mkdir /etc/docker  ## 创建 /etc/docker 目录

# 配置 daemon.

cat > /etc/docker/daemon.json <<EOF

{

"exec-opts": ["native.cgroupdriver=systemd"],   ## 指定了 Docker 守护进程使用 systemd 作为 cgroup 驱动程序,用于管理容器的资源限制和隔离。 

"log-driver": "json-file",     ##指定了 Docker 容器的日志驱动程序为 json-file,即将容器的日志输出到文件中。

"log-opts": {

"max-size": "100m"

}

}

EOF

mkdir -p /etc/systemd/system/docker.service.d

# 重启docker服务

systemctl daemon-reload && systemctl restart docker && systemctl enable docker

四、 安装kubeadm(主从配置)

kubeadm是 Kubernetes 官方提供的一个命令行工具,用于在 Kubernetes 集群中初始化控制平面节点(Master 节点)和加入工作节点(Worker 节点)。

cat <<EOF > /etc/yum.repos.d/kubernetes.repo

[kubernetes]

name=Kubernetes

baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/

enabled=1

gpgcheck=1

repo_gpgcheck=1

gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg

EOF

yum -y install kubeadm-1.15.1 kubectl-1.15.1 kubelet-1.15.1

systemctl enable kubelet.service

五、 初始化主节点 

注意,此处可以先导入下载好的kubeadm 镜像(谷歌下载)

初始化 Kubernetes 集群,并根据指定的配置文件生成秘钥

kubeadm config print init-defaults > kubeadm-config.yaml

#更改kubeadm-config.yaml 文件

localAPIEndpoint:

advertiseAddress: 192.168.66.10 #更改为master的ip地址

kubernetesVersion: v1.15.1 #更改版本为当前版本

networking:

  podSubnet: "10.244.0.0/16" #添加flannel 网络不然后面麻烦

  serviceSubnet: 10.96.0.0/12

---

apiVersion: kubeproxy.config.k8s.io/v1alpha1

kind: KubeProxyConfiguration

featureGates:

  SupportIPVSProxyMode: true

mode: ipvs

做初始化并生成秘钥

kubeadm init --config=kubeadm-config.yaml --experimental-upload-certs | tee kubeadm-init.log

六、查看kubeadm-init.log \加入主节点以及其余工作节点

vim  kubeadm-init.log (如果第5步前,没有导入镜像,通过下载方式获取镜像,时间会比较久。防止卡主,可以开个子终端,通过docker images 查看镜像是否有新增)

通过观察日志,发现需要做以下操作:

mkdir -p $HOME/.kube

sudo cp -i /etc/kubernetes/admin.conf   $HOME/.kube/config

sudo chown $(id -u): $(id -g) $HOME/.kube/config

此时可以查看当前节点:kubectl get node

七、 部署网络,安装flannel

mkdir install-k8s

ls

mv kubeadm-init.log kubeadm-config.ymal install-k8s/

cd  install-k8s

mkdir core

mv *core/

mkdir plugin

cd plugin/

mkdir flannel

cd  flannel

wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube- flannel.yml

kubectl create -f  kube- flannel.yaml

kubectl get pod -n kube-system

备注:

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube- flannel.yml

kubectl apply -f 是在原有基础上升级

kubectl create -f 是直接新建

八、 加入其他节点

加入其他节点(在子节点执行 )(在主节点的日志文件里面找到命令):

kubeadmjoin192.168.66.10:6443--token abcdef.0123456789abcdef \--discovery-token-ca-cert-hash sha256:ed81ab06be57fa61df388ddce02b4a6d70d0e6a0be91b7b7382d8fd82970c964

kubectl get pod -n kube-system -o wide

kubectl get pod -n kube-system -w

mv install-k8s/ /usr/local/ 

rm -rf  * install-k8s



2、配置私有仓库Harbor

Harbor 提供了一个安全、可靠的容器镜像仓库,帮助组织和团队有效地存储、管理和分发容器镜像,并提供了访问控制、安全扫描和审计等功能,以增强容器化应用的安全性和可管理性。

一、安装docker

在 CentOS 系统上安装 Docker 和 Docker Compose,并升级 Python pip 工具。

sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

yum install docker-ce -y

yum install python-pip -y

pip install --upgrade pip

pip install docker-compose (单机编排工具)

二、更改vim /etc/docker/daemon.json 让其信任syuee.com 这个域名

注意,k8s机器也更改如下配置

{

  "exec-opts": ["native.cgroupdriver=systemd"], "log-driver": "json-file",

  "log-opts": {

    "max-size": "100m"

  },

  "registry-mirrors": ["https://f4573wwn.mirror.aliyuncs.com"],

  "insecure-registries": ["https://hub.syuee.com"]   ##认为它是安全的证书,省掉购买证书环节

}

yum -y install lrzsz  ##lrzsz 是一个用于在终端中进行文件传输的工具,它支持通过串口、Telnet、SSH 等协议进行文件传输。

将docker-compose拖进服务器

mv docker-compose /usr/local/bin/

chmod a+x /usr/local/bin/ docker-compose

三、创建证书

openssl genrsa -des3 -out server.key 2048    #生成私钥输入两次密码(4位以上)

openssl req -new -key server.key -out server.csr    #创建一个证书的请求

#第一个国家名:CN

#第二个省:SH

#第三个市:SH

#第四个组织:syuee

#第五个机构:syuee

#完全合规域名:hub.syuee.com

#管理员邮箱:sivan@syuee.com

#是否要改密码

cp server.key server.key.org   #备份私钥

openssl rsa -in server.key.org -out server.key   #去掉密码

openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt  #签名生成证书

mkdir /data/cert #创建/data/cert 目录 (存储ssl的目录)

chmod -R 777 /data/cert

四、上传harbor并解压

将habor-offline-installer-v1.2.0.tgz拖进服务器

tar -zvf habor-offline-installer-v1.2.0.tgz

mv harbor /usr/local/

更改配置文件vim /usr/local/harbor/harbor.cfg

cd /usr/local/harbor 

vim harbor.cfg

更改hostname

hostname = hub.syuee.com

更改访问为https

ui_url_protocol = https

默认证书的位置是

ssl_cert = /data/cert/server.crt

ssl_cert_key = /data/cert/server.key

安装harbor

./install.sh

五、其他配置

配置hosts 解析(包含Harbor本机以及其他k8s服务器)

C:\Windows\System32\drivers\etc 的hosts  默认账号密码是 admin\Harbor12345

cat /etc/hosts

echo "192.168.66.100 hub.syuee.com" >>  /etc/hosts

docker ps -a #查看运行的容器

启动后:https://hub.syuee.com 访问仓库

六、更改其他docker 指定仓库

{

  "exec-opts": ["native.cgroupdriver=systemd"],

  "log-driver": "json-file",

  "log-opts": {

    "max-size": "100m"

  },

  "insecure-registries": ["https://hub.syuee.com"]

}

七、验证

1、测试推送镜像到仓库

docker login https://hub.syuee.com   #测试docker是否能访问仓库   admin\Harbor12345

docker pull nginx  #下载一个镜像

docker tag nginx:latest hub.syuee.com/library/nginx:v1   #anHarbor标准,推送镜像需要 重新打标签

docker push hub.syuee.com/library/nginx:v1  #推送到仓库

hub.syuee.com/library/ingress-nginx-controller:v0.44.0

2、测试从k8s上拉取仓库中镜像

kubectl run nginx-deployment --image=hub.syuee.com/library/nginx:v1 --port=80 --replicas=1      #在 Kubernetes 集群中创建一个名为 nginx-deployment 的部署(Deployment)对象,并使用指定的镜像、端口和副本数量进行配置。从 Kubernetes 1.18 开始,kubectl run 命令的行为发生了变化。在新版本中,kubectl run 命令默认创建的是一个 Pod,而不是 Deployment。如果你使用的是较新的 Kubernetes 版本,可以使用 kubectl create deployment 命令来创建部署对象。

kubectl get deployment   #获取当前 Kubernetes 集群中的部署(Deployment)对象的信息。包含就绪副本数、最新副本数和可用副本数等信息。

kubectl get rs   #rs 是要获取信息的资源类型,表示 ReplicaSet 对象。包含期望副本数、当前副本数和可用副本数等信息

kubectl get pod

kubectl get pod -0 wide


3、k8s集群网络访问设置

kubectl scale --replicas=3 deployment/nginx-deployment  #对pod扩容成3个副本

kubectl get svc  #Service 是 Kubernetes 中用于提供网络访问和负载均衡的对象,用于将一组 Pod 暴露给集群内外的其他组件或用户。

问题1:怎么访问三个pod?传统通过nginx的upstream。k8s通过IPVS服务

kubectl expose deployment nginx-deployment --port=30000 --target-port=80  #在 Kubernetes 将创建一个 Service 对象,并将其与指定的 Deployment 对象关联起来。该 Service 对象将使用指定的端口号(这里是 30000)暴露服务,并将流量转发到与 Deployment 关联的 Pod 的指定端口号(这里是 80)。这样,通过访问 Service 的 IP 地址和端口号(例如,http://<Service-IP>:30000),可以访问到运行在 Deployment 中的 Pod 提供的服务。

ipvsadm -Ln | grep 10.97.154.59  #使用 ipvsadm 工具来列出 IPVS(IP Virtual Server)的配置。查找与指定 IP 地址相关的负载均衡规则或配置信息。通过执行该命令,可以查看与指定 IP 地址相关的负载均衡配置,例如目标服务器的 IP 地址、端口号、负载均衡算法等。

ipvsadm -Ln 

问题2:怎么通过外网访问nginx-deployment ?10.97.154.59是内网地址,无法访问,但是可以 通过将svc的type改为NodePort类型,自动暴露端口 。注意,此时通过https://192.168.66.10 :31859 、https://192.168.66.20 :31859 、https://192.168.66.21 :31859 可以访问到NodePord节点

NodePort:

NodePort 是一种 Service 类型,它在每个节点上使用一个固定的端口(NodePort)来公开服务。

当创建一个 NodePort 类型的 Service 时,Kubernetes 集群会为该 Service 在每个节点上选择一个端口,并将该端口映射到该 Service 的目标端口(TargetPort)。

外部用户可以通过访问任何节点的 <NodeIP>:<NodePort> 来访问 Service,流量会被转发到 Service 底层的 Pod。

NodePort 类型的 Service 具有两个 IP 地址:一个是 Service 的 ClusterIP(集群内部 IP),用于在集群内部访问 Service;另一个是每个节点的 IP 地址,用于在集群外部访问 Service。

ClusterIP:

ClusterIP 是另一种 Service 类型,它为 Service 分配一个虚拟 IP 地址(ClusterIP)。

ClusterIP 类型的 Service 只能在集群内部访问,外部用户无法直接访问该 Service。

ClusterIP 类型的 Service 将流量转发到底层的 Pod,但不会公开给集群外部。

ClusterIP 类型的 Service 可以通过其他 Service 或 Ingress 对象来公开给集群外部。

在 Kubernetes 中,NodePort、Port 和 TargetPort 是 Service(服务)对象中用于定义端口映射和流量转发的不同属性。

NodePort:

NodePort 是 Service 对象的一个属性,用于指定在每个节点上公开服务的端口。

它是一个大于30000且小于32767的整数值,由 Kubernetes 集群自动分配。

外部用户可以通过访问任何节点的 <NodeIP>:<NodePort> 来访问 Service,流量会被转发到 Service 底层的 Pod。

NodePort 是一种公开服务给集群外部访问的方式。

Port:

Port 是 Service 对象的另一个属性,用于指定 Service 对象的端口号。

它定义了 Service 对象的入口端口,用于接收流量。

Port 是 Service 对象对外公开的端口,可以在集群内外使用该端口来访问 Service。

TargetPort:

TargetPort 是 Service 对象的另一个属性,用于指定将流量转发到 Service 底层 Pod 的端口

它定义了 Service 对象将流量转发到哪个 Pod 的端口。

TargetPort 是 Service 对象与后端 Pod 之间的通信端口。

总结:

NodePort 是用于在每个节点上公开服务的端口,用于集群外部访问。

Port 是 Service 对象对外公开的端口,用于接收流量。

TargetPort 是 Service 对象将流量转发到后端 Pod 的端口。

  外网------------------------Service --------------------------pod

NodePort     ------------      Port         ------------     TargetPort 

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,383评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,522评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,852评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,621评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,741评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,929评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,076评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,803评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,265评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,582评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,716评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,395评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,039评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,027评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,488评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,612评论 2 350

推荐阅读更多精彩内容