周旭龙11

<p>在之前我有专门写两篇文章介绍过<a href="https://www.cnblogs.com/edisonchou/p/exceptionless_deployment_on_production_env_introduction.html" target="_blank">Exceptionless这款开源日志项目的使用和部署</a>,但是当时是基于4.1.0版本(2017年的release),时隔两年多Exceptionless也推出了5.0.0版本。</p>

<h1>一、关于Exceptionless 5.0.0</h1>
<p>  Exceptionless 是一个开源的实时的好用的日志收集框架,它将日志收集变得简单易用并且不需要了解太多的相关技术细节及配置。但是之前的版本将其Web和API绑定在了Windows平台通过IIS运行,对于已经步入云原生时代的我们显得有点格格不入。5.0.0的发布解决了这一痛点,其最大的变化就是基于ASP.NET Core重写并支持跨平台,也就是说当初我们设想的要是能够基于Docker部署在Linux服务器下就更好了的愿望已经实现了,在此真心<em><strong>感谢Exceptionless项目的各位贡献者</strong></em>。本文就Exceptionless 5.0.0版本介绍一下快速地部署开发环境和生产环境,相信对有兴趣的朋友会有一点帮助。</p>
<p>  至此我也可以将我们之前的Exceptionless从Windows Server迁移到Linux上了!</p>
<h1>二、快速本地部署步骤</h1>
<h2>2.1 安装Docker 18.09+</h2>
<p>  由于Exceptionless 5.0.0的一个前置要求是Docker版本(CE)在18.09及以上,因此我们需要安装一个18.09+的Docker CE版本到Linux服务器上,如果你之前安装了可以跳过此步骤,但如果版本小于18.09,那么请清理掉老版本升级到新版本,升级版本可以参考以下步骤。</p>
<p>  实验环境:<a href="https://www.aliyun.com/product/ecs" target="_blank">阿里云ECS主机</a>,CentOS 7.4</p>
<p>  (1)清理已有Docker老版本</p>
<p>  停止Docker老版本:</p>
<div class="cnblogs_code">
<pre>systemctl stop docker</pre>
</div>
<p>  卸载软件包:</p>
<div class="cnblogs_code"><div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a href="javascript:void(0);" onclick="copyCnblogsCode(this)" title="复制代码"><img src="//common.cnblogs.com/images/copycode.gif" alt="复制代码"></a></span></div>
<pre><span style="color: #0000ff;">yum</span><span style="color: #000000;"> erase docker
docker</span>-<span style="color: #000000;">client
docker</span>-client-<span style="color: #000000;">latest
docker</span>-<span style="color: #000000;">common
docker</span>-<span style="color: #000000;">latest
docker</span>-latest-<span style="color: #000000;">logrotate
docker</span>-<span style="color: #000000;">logrotate
docker</span>-<span style="color: #000000;">selinux
docker</span>-engine-<span style="color: #000000;">selinux
docker</span>-<span style="color: #000000;">engine
docker</span>-ce</pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a href="javascript:void(0);" onclick="copyCnblogsCode(this)" title="复制代码"><img src="//common.cnblogs.com/images/copycode.gif" alt="复制代码"></a></span></div></div>
<p>  删除相关配置文件:</p>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">find</span> /etc/systemd -name <span style="color: #800000;">'</span><span style="color: #800000;">docker</span><span style="color: #800000;">'</span> -exec <span style="color: #0000ff;">rm</span> -<span style="color: #000000;">f {} ;
</span><span style="color: #0000ff;">find</span> /etc/systemd -name <span style="color: #800000;">'</span><span style="color: #800000;">docker</span><span style="color: #800000;">'</span> -exec <span style="color: #0000ff;">rm</span> -<span style="color: #000000;">f {} ;
</span><span style="color: #0000ff;">find</span> /lib/systemd -name <span style="color: #800000;">'</span><span style="color: #800000;">docker</span><span style="color: #800000;">'</span> -exec <span style="color: #0000ff;">rm</span> -<span style="color: #000000;">f {} ;
</span><span style="color: #0000ff;">rm</span> -rf /var/lib/<span style="color: #000000;">docker #删除以前已有的镜像和容器,非必要,慎删
</span><span style="color: #0000ff;">rm</span> -rf /var/run/docker </pre>
</div>
<p>  (2)安装Docker 18.09+</p>
<p>  软件包安装:</p>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">yum</span> <span style="color: #0000ff;">install</span> -y <span style="color: #0000ff;">yum</span>-utils device-mapper-persistent-data lvm2</pre>
</div>
<p>  添加yum源:</p>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">yum</span>-config-<span style="color: #000000;">manager
</span>--add-<span style="color: #000000;">repo
https:</span><span style="color: #008000;">//</span><span style="color: #008000;">download.docker.com/linux/centos/docker-ce.repo</span></pre>
</div>
<p>  查看可安装的版本:目前最新版本已经是19.03</p>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">yum</span> list docker-ce --showduplicates | <span style="color: #0000ff;">sort</span> -r</pre>
</div>
<p>  安装指定版本:18.09</p>
<div class="cnblogs_code">
<pre><span style="color: #0000ff;">yum</span> <span style="color: #0000ff;">install</span> docker-ce docker-ce-18.09.9-3.el7 -y</pre>
</div>
<p>  启动Docker并设置开机自启动:</p>
<div class="cnblogs_code">
<pre><span style="color: #000000;">systemctl start docker
systemctl enable docker</span></pre>
</div>
<p>  查看Docker版本:</p>
<div class="cnblogs_code">
<pre>docker version </pre>
</div>
<p>  你可以看到已经是18.09版本了:</p>
<p>  <img style="width: 70%; border: 1px solid #dddddd; border-radius: 5px;" src="https://img2018.cnblogs.com/blog/381412/201909/381412-20190929225710500-226633119.png" alt=""></p>
<h2>2.2 下载Exceptionless 5.0.0 Release包</h2>
<p>  传送门:<a href="https://github.com/exceptionless/Exceptionless/releases" target="_blank">Exceptionless release</a></p>
<p>   <img style="width: 60%; border: 1px solid #dddddd; border-radius: 5px;" src="https://img2018.cnblogs.com/blog/381412/201909/381412-20190930143735712-2018898135.png" alt=""></p>
<h2>2.3 安装Exceptionless 5.0.0</h2>
<p>  (1)修改docker-compose.yml文件,设置外部访问地址/域名(适配你的服务器IP地址 或 域名+SSL证书,这里我直接修改为我的阿里云服务器的外网IP地址,参考我的注释)</p>
<div class="cnblogs_code"><div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a href="javascript:void(0);" onclick="copyCnblogsCode(this)" title="复制代码"><img src="//common.cnblogs.com/images/copycode.gif" alt="复制代码"></a></span></div>
<pre>version: <span style="color: #800000;">'</span><span style="color: #800000;">3.4</span><span style="color: #800000;">'</span><span style="color: #000000;">

services:
api:
depends_on:
</span>-<span style="color: #000000;"> elasticsearch
</span>-<span style="color: #000000;"> redis
build:
context: .
target: api
image: exceptionless</span>/<span style="color: #000000;">api:latest
restart: on</span>-<span style="color: #000000;">failure
environment:
EX_AppMode: Production
EX_BaseURL: http:</span><span style="color: #008000;">//</span><span style="color: #008000;">192.168.16.170:5100 #UI地址,修改这里的IP地址为你的服务器IP地址</span>
EX_ConnectionStrings__Cache: provider=<span style="color: #000000;">redis
EX_ConnectionStrings__Elasticsearch: server</span>=http:<span style="color: #008000;">//</span><span style="color: #008000;">elasticsearch:9200</span>
#EX_ConnectionStrings__Email: smtps:<span style="color: #008000;">//</span><span style="color: #008000;">user:password@smtp.host.com:587</span>
EX_ConnectionStrings__MessageBus: provider=<span style="color: #000000;">redis
#EX_ConnectionStrings__Metrics: provider</span>=statsd;server=<span style="color: #000000;">statsd;
EX_ConnectionStrings__Queue: provider</span>=<span style="color: #000000;">redis
EX_ConnectionStrings__Redis: server</span>=redis,abortConnect=<span style="color: #0000ff;">false</span><span style="color: #000000;">
EX_ConnectionStrings__Storage: provider</span>=folder;path=/app/<span style="color: #000000;">storage
EX_RunJobsInProcess: </span><span style="color: #800000;">'</span><span style="color: #800000;">false</span><span style="color: #800000;">'</span><span style="color: #000000;">
ports:
</span>- <span style="color: #800080;">5000</span>:<span style="color: #800080;">80</span> # This can be commented out <span style="color: #0000ff;">if</span><span style="color: #000000;"> using reverse proxy.
volumes:
</span>- appdata:/app/<span style="color: #000000;">storage

jobs:
depends_on:
</span>-<span style="color: #000000;"> api
build:
context: .
target: job
image: exceptionless</span>/<span style="color: #000000;">job:latest
restart: on</span>-<span style="color: #000000;">failure
environment:
EX_AppMode: Production
EX_BaseURL: http:</span><span style="color: #008000;">//</span><span style="color: #008000;">192.168.16.170:5100 #UI地址,修改这里的IP地址为你的服务器IP地址</span>
EX_ConnectionStrings__Cache: provider=<span style="color: #000000;">redis
EX_ConnectionStrings__Elasticsearch: server</span>=http:<span style="color: #008000;">//</span><span style="color: #008000;">elasticsearch:9200</span>
#EX_ConnectionStrings__Email: smtps:<span style="color: #008000;">//</span><span style="color: #008000;">user:password@smtp.host.com:587</span>
EX_ConnectionStrings__MessageBus: provider=<span style="color: #000000;">redis
#EX_ConnectionStrings__Metrics: provider</span>=statsd;server=<span style="color: #000000;">statsd;
EX_ConnectionStrings__Queue: provider</span>=<span style="color: #000000;">redis
EX_ConnectionStrings__Redis: server</span>=redis,abortConnect=<span style="color: #0000ff;">false</span><span style="color: #000000;">
EX_ConnectionStrings__Storage: provider</span>=folder;path=/app/<span style="color: #000000;">storage
volumes:
</span>- appdata:/app/<span style="color: #000000;">storage

ui:
image: exceptionless</span>/<span style="color: #000000;">ui:latest
environment:
AppMode: Production
EX_ApiUrl: http:</span><span style="color: #008000;">//</span><span style="color: #008000;">192.168.16.170:5000 #API地址,修改这里的IP地址为你的服务器IP地址</span>
#EX_Html5Mode: <span style="color: #800000;">'</span><span style="color: #800000;">false</span><span style="color: #800000;">'</span><span style="color: #000000;">
#EX_EnableSsl: </span><span style="color: #800000;">'</span><span style="color: #800000;">false</span><span style="color: #800000;">'</span><span style="color: #000000;">
#EX_EnableAccountCreation: </span><span style="color: #800000;">'</span><span style="color: #800000;">false</span><span style="color: #800000;">'</span><span style="color: #000000;">
ports:
</span>- <span style="color: #800080;">5100</span>:<span style="color: #800080;">80</span> # This can be commented out <span style="color: #0000ff;">if</span><span style="color: #000000;"> using reverse proxy.

reverseproxy:

depends_on:

</span>-<span style="color: #000000;"> api

</span>-<span style="color: #000000;"> ui

image: valian</span>/docker-nginx-auto-<span style="color: #000000;">ssl

restart: on</span>-<span style="color: #000000;">failure

ports:

</span>- <span style="color: #800080;">80</span>:<span style="color: #800080;">80</span><span style="color: #000000;">

</span>- <span style="color: #800080;">443</span>:<span style="color: #800080;">443</span><span style="color: #000000;">

volumes:

</span>- ssldata:/etc/resty-auto-<span style="color: #000000;">ssl

environment:

ALLOWED_DOMAINS: </span><span style="color: #800000;">'</span><span style="color: #800000;">(ex-ui|ex-api).mydomainn.com</span><span style="color: #800000;">'</span><span style="color: #000000;">

SITES: </span><span style="color: #800000;">'</span><span style="color: #800000;">ex-ui.mydomainn.com=ui;ex-api.mydomainn.com=api</span><span style="color: #800000;">'</span><span style="color: #000000;">

elasticsearch:
image: exceptionless</span>/elasticsearch:<span style="color: #800080;">1</span><span style="color: #000000;">
restart: on</span>-<span style="color: #000000;">failure
environment:
cluster.name: </span><span style="color: #800000;">'</span><span style="color: #800000;">exceptionless</span><span style="color: #800000;">'</span><span style="color: #000000;">
bootstrap.memory_lock: </span><span style="color: #800000;">'</span><span style="color: #800000;">true</span><span style="color: #800000;">'</span><span style="color: #000000;">
discovery.type: single</span>-<span style="color: #000000;">node
ES_JAVA_OPTS: </span><span style="color: #800000;">'</span><span style="color: #800000;">-Xms512m -Xmx512m</span><span style="color: #800000;">'</span><span style="color: #000000;">
xpack.security.enabled: </span><span style="color: #800000;">'</span><span style="color: #800000;">false</span><span style="color: #800000;">'</span><span style="color: #000000;">
xpack.graph.enabled: </span><span style="color: #800000;">'</span><span style="color: #800000;">false</span><span style="color: #800000;">'</span><span style="color: #000000;">
xpack.watcher.enabled: </span><span style="color: #800000;">'</span><span style="color: #800000;">false</span><span style="color: #800000;">'</span><span style="color: #000000;">
ports:
</span>- <span style="color: #800080;">9200</span>:<span style="color: #800080;">9200</span>
- <span style="color: #800080;">9300</span>:<span style="color: #800080;">9300</span><span style="color: #000000;">
ulimits:
memlock:
soft: </span>-<span style="color: #800080;">1</span><span style="color: #000000;">
hard: </span>-<span style="color: #800080;">1</span><span style="color: #000000;">
volumes:
</span>- esdata:/usr/share/elasticsearch/<span style="color: #000000;">data

kibana:
depends_on:
</span>-<span style="color: #000000;"> elasticsearch
image: exceptionless</span>/kibana:<span style="color: #800080;">1</span><span style="color: #000000;">
restart: on</span>-<span style="color: #000000;">failure
environment:
xpack.security.enabled: </span><span style="color: #800000;">'</span><span style="color: #800000;">false</span><span style="color: #800000;">'</span><span style="color: #000000;">
ports:
</span>- <span style="color: #800080;">5601</span>:<span style="color: #800080;">5601</span><span style="color: #000000;">

redis:
image: redis:alpine
restart: on</span>-<span style="color: #000000;">failure
ports:
</span>- <span style="color: #800080;">6379</span>:<span style="color: #800080;">6379</span><span style="color: #000000;">

volumes:
esdata:
driver: local
appdata:
driver: local
ssldata:
driver: local</span></pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a href="javascript:void(0);" onclick="copyCnblogsCode(this)" title="复制代码"><img src="//common.cnblogs.com/images/copycode.gif" alt="复制代码"></a></span></div></div>
<blockquote>
<p><em><strong>Note:</strong></em>在这个docker-compose.yml中定义了Exceptionless的最小化运行环境,但官方建议生产环境使用ElasticSearch集群,并适当修改ElasticSearch的内存限制。如果你的量很小真的不大,那么这个最小化的运行环境也够用了,没必要为了高可用而高可用。  </p>
</blockquote>
<p>  此外,貌似官方已经将exceptionless/elasticsearch:1这个镜像移除了,大家可以使用这个镜像:<strong>edisonsaonian/exceptionless-elasticsearch:1</strong></p>
<p>  (2)将Release包上传到阿里云服务器,然后通过SSH执行一下shell命令(首先cd到这个release包的目录下)启动Exceptionless 5.0.0。</p>
<div class="cnblogs_code">
<pre>docker-compose up -d</pre>
</div>
<p>  整个过程会比较漫长,因为会经过34个Steps,拉取很多镜像,类似于Redis,ElasticSearch,Kibana及.NET Core SDK等等,请耐心等待。最终效果如下所示:</p>
<p>  <img style="width: 60%; border: 1px solid #dddddd; border-radius: 5px;" src="https://img2018.cnblogs.com/blog/381412/201909/381412-20190930144146148-1348602911.png" alt=""></p>
<p>  <img style="width: 70%; border: 1px solid #dddddd; border-radius: 5px;" src="https://img2018.cnblogs.com/blog/381412/201909/381412-20190930144232365-1751032748.png" alt=""></p>
<h2>2.4 使用Exceptionless 5.0.0</h2>
<p>  (1)访问你的服务器IP:5100 即可访问Exceptionless Web管理登录界面,如果你能看到,那么代表部署成功了。注册一个账号,然后登陆吧。</p>
<p>  <img style="width: 70%; border: 1px solid #dddddd; border-radius: 5px;" src="https://img2018.cnblogs.com/blog/381412/201909/381412-20190930144336477-464695945.png" alt="" width="738" height="312"></p>
<p>  (2)可以看到主页是全新的中文管理界面,感谢贡献者的努力</p>
<p>  <img style="width: 70%; border: 1px solid #dddddd; border-radius: 5px;" src="https://img2018.cnblogs.com/blog/381412/201909/381412-20190930144419343-853462229.png" alt="" width="688" height="308"></p>
<p>  <img style="width: 50%; border: 1px solid #dddddd; border-radius: 5px;" src="https://img2018.cnblogs.com/blog/381412/201909/381412-20190930144440956-1851854497.png" alt=""></p>
<p>  (3)创建一些示例项目,如“XDP.Product.API”,并获取API Key</p>
<p>  <img style="width: 50%; border: 1px solid #dddddd; border-radius: 5px;" src="https://img2018.cnblogs.com/blog/381412/201909/381412-20190930144546508-572370284.png" alt=""></p>
<p>  (4)在你的ASP.NET Core WebAPI项目中配置API Key,并向Exceptionless API(这里是5000端口)发送Log</p>
<p>  (5)在Exceptionless中查看Log</p>
<p>  <img style="width: 70%; border: 1px solid #dddddd; border-radius: 5px;" src="https://img2018.cnblogs.com/blog/381412/201909/381412-20190930144628540-1858599463.png" alt="" width="687" height="256"></p>
<p>  <img style="width: 70%; border: 1px solid #dddddd; border-radius: 5px;" src="https://img2018.cnblogs.com/blog/381412/201909/381412-20190930144646360-749223515.png" alt="" width="783" height="411"></p>
<h1>三、遗留问题:Email通知配置</h1>
<p>  使用过Exceptionless的童鞋都知道,Exceptionless提供了强大的Email通知机制,可以为用户提供及时的严重错误通知和每日报告。</p>
<p>  <img style="width: 50%; border: 1px solid #dddddd; border-radius: 5px;" src="https://img2018.cnblogs.com/blog/381412/201909/381412-20190930144751848-1328868168.png" alt="" width="531" height="411"></p>
<p>  在上面介绍的安装基础上,根据官方Wiki文档,按理说我们只需要确保docker-compose.yml中的api和jobs的AppMode为Production模式并设置SMTP就可以开启Email通知。</p>
<div id="7338-1569824950029" class="block-view code-view yne-code-theme-default" data-language="javascript" data-theme="default">
<div class="para-text">
<div class="cnblogs_code">
<pre><span style="color: #000000;">EX_AppMode: Production
EX_ConnectionStrings__Email: smtps:</span><span style="color: #008000;">//</span><span style="color: #008000;">edisonchou7%40qq.com:zltqvl2321ed@smtp.qq.com:465</span></pre>
</div>
</div>
</div>
<div>  这里的%40是@的转义替代,在Exceptionless中会使用Decode进行解码为@,原因好像是因为它是通过@符号分割前方的用户名+密码和后方的Host+Port,也是醉了。</div>
<div>  设置完成后,通过以下命令重启docker:</div>
<div id="8469-1569825103131" class="block-view code-view yne-code-theme-default" data-language="javascript" data-theme="default">
<div class="para-text">
<div class="cnblogs_code">
<pre>docker-compose up -d</pre>
</div>
</div>
</div>
<div>  docker-compose会自动帮我们重启更改过的容器,比如api和jobs。</div>
<div>  但是,我试了很多次都发现还是无法正常发送Email通知,由于不影响使用,也就暂时没去深究了,有解决的朋友可以告知并<strong>分享一下解决办法</strong>,谢谢。</div>
<h1>四、小结</h1>
<p>  本文介绍了Exceptionless 5.0.0的容器化本地部署,主要参考自Exceptionless的Self-Host文档。</p>
<h1>参考资料</h1>
<p>1、<a href="https://github.com/exceptionless/Exceptionless/releases" target="_blank">Exceptionless release</a></p>
<p>2、<a href="https://github.com/exceptionless/Exceptionless/wiki/Self-Hosting" target="_blank">Exceptionless Self-Hosting Documention</a></p>
<p> </p>
<div id="Copyright">

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

推荐阅读更多精彩内容