docker入门笔记

《Docker技术入门与实践》笔记

2 核心概念

Docker的三个核心概念分别为:镜像、容器和仓库。

2.1 镜像

Docker镜像类似于虚拟机镜像,可以理解为一个只读的模板。

2.2 容器

容器的定义:容器有效地将由单个操作系统管理的资源划分到孤立的组中,以更好地在孤立的组之间平衡有冲突的资源使用需求。与虚拟化相比,这样既不需要指令级模拟,也不需要即时编译。容器可以在核心CPU本地运行指令,而不需要任何专门的解释机制。此外,也避免了准虚拟化和系统调用替换中的复杂性。

可以将Docker容器理解为一种轻量级的沙盒。每个容器内运行着一个应用,不同的容器相互隔离,容器之间也可以通过网络互相通信。容器的创建和停止都十分快速,几乎跟创建和终止原生应用一致;另外,容器自身对系统资源的额外需求也十分有限,远远低于传统虚拟机。很多时候,甚至直接把容器当作应用本身也没有任何问题。

沙盒是一种虚拟技术,多用于计算机安全技术,其原理是通过重定向技术,把程序生成和修改的文件重定向到自身文件夹中,当某个程序试图发挥作用时,安全软件可先让它在沙盒中运行,如有恶意行为,则禁止程序进一步运行,不会对系统造成危害。

2.3 仓库

注册服务器(Registry)与仓库(Repository)
  • docker仓库是集中存放镜像文件的场所
  • 仓库注册服务器(Registry)是存放仓库(Repository)的地方
  • 一个Registry可以存放多个Repository,每个Repository中存放一类镜像,用标签(tag)进行区分

3 使用docker镜像

docker运行容器前需要本地存在对应的镜像,如果镜像没保存在本地,docker会尝试先从默认镜像仓库(Docker Hub公共注册服务器中的仓库),用户也可以通过配置,使用自定义的镜像仓库。

3.1 获取镜像

官网Docker Hub(需要VPN才能注册)提供了镜像给用户下载。我们可以直接从官网拉下镜像,命令格式:

$ docker pull NAME[:TAG]

例子:
获取ubuntu 14.04的基础镜像:

$ docker pull ubuntu:14.04

若省略了TAG,则默认下载最新版本。严格的讲,镜像仓库名称还应该加上仓库地址(即注册服务器)作为前缀,只是默认从Docker Hub上下载,所以该前缀可以忽略,实际是:

$ docker pull registry.hub.docker.com/ubuntu:14.04

如果从非官方仓库下载镜像,则需要在仓库名称前指定完整的仓库地址。

镜像文件一般由若干层组成,每个层由一个唯一id(256位)表示。当不同镜像包括相同的层时,本地仅存储该层的一份内容,减少了存储空间。

利用镜像创建容器,运行bash应用:

$ docker run -it ubuntu:15.04 bash
root@3d5884dd705a:/# ls

bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

3.2 查看镜像信息

列出本地主机上已有镜像信息:

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              15.04               d1b55fd07600        2 years ago         131MB
  • REPOSITORY:来自哪个仓库。
  • TAG:标签信息,标记同一仓库的不同镜像。
  • IMAGE ID:镜像ID(唯一标志符),一般可以使用该ID的前若干个字符组成的可区分串来替代完整的ID。
  • CREATED:创建时间,说明镜像最后更新时间。
  • SIZE:镜像大小(逻辑大小),实际物理上占用的空间会小于各镜像的逻辑大小之和。

image子命令:

  • -a,--all=true|false:列出所有镜像文件(包括临时文件),默认为否
  • --digests=true|false:列出摘要,默认为否
  • -f,--filter=[]:过滤列出的镜像
  • --format="TEMPLATE":控制输出格式
  • --no-trunc=true|false:对输出结果中太长的部分是否进行截断,默认为是
  • -q,--quit=true|false:仅输出ID信息,默认为否

为镜像添加一个tag,与原先的tag指向同一个镜像,因此实际占用内存只有一个镜像大小:

$ docker tag ubuntu:15.04 myubuntu:15.04
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
myubuntu            15.04               d1b55fd07600        2 years ago         131MB
ubuntu              15.04               d1b55fd07600        2 years ago         131MB

查看一个镜像的详细信息:

$ docker inspect ubuntu:15.04

以上返回结果是json格式的消息,可以只获取其中一项,如操作系统:

$ docker inspect ubuntu:15.04 -f {{".Os"}}

查看镜像历史:

$ docker history ubuntu:15.04

3.3 搜索镜像

搜索远端仓库中共享的镜像,默认搜索官网仓库Docker Hub的镜像。

例子:搜索所有自动创建的星超过100的带ubuntu的镜像:

$ docker search --filter=is-automated=true --filter=stars=3 ubuntu
DESCRIPTION   STARS  OFFICIAL AUTOMATED
...

3.4 删除镜像

  1. 用标签删除镜像:
$ docker rmi [-f] ubuntu:15.04
  • 当同个镜像拥有多个标签时,docker rmi只是删除该镜像多个标签中的指定标签而已,并不影响镜像文件。
  • 但当镜像只剩下一个标签时,docker rmi会彻底删除镜像。
  1. 用ID删除镜像,会先尝试删除所有指向该镜像的标签,然后删除该镜像文件本身:
$ docker rmi [-f] d1b55fd07600

当镜像创建的容器存在时,镜像文件无法直接删除,需要增加-f参数。但正确的做法是先删除镜像的所有容器,再删除镜像。

3.5 创建镜像

创建镜像的主要方法有:

  • 基于已有镜像的容器创建
  • 基于本地模板导入
  • 基于Dockerfile创建
  1. 基于已有镜像的容器创建:
    先对已有镜像进行修改,然后再提交:
$ docker commit -m "... ..." -a "author name" 容器ID Name:TAG
  • -a,--author="":作者信息
  • -c,--change=[]:提交时执行Dockerfile指令
  • -m,--message="":提交消息
  • -p,--pause=true:提交时暂停容器运行
  1. 基于本地模板导入:
    可以直接从一个操作系统模板导入一个镜像,模板可以从OpenVZ下载。导入的方法如下:
$ docker import [OPTIONS] file|URL|-[REPOSITORY[:TAG]]

例子:

$ cat ubuntu-14.04-x86.tar.gz | docker import - ubuntu:14.04
或
$ docker import ubuntu-14.04-x86.tar.gz ubuntu:14.04

ubuntu-14.04-x86.tar.gz为下载的模板。

3.6 存出和载入镜像

  1. 存出镜像
    将镜像ubuntu:15.04导出为ubuntu_15.04.tar:
$ docker save -o ubuntu_15.04.tar ubuntu:15.04
  1. 载入镜像
$ docker load --input ubuntu_15.04.tar
或:
$ docker load < ubuntu_15.04.tar

3.7 上传镜像

需要先登陆:

$ docker login

添加标签:

$ docker tag ubuntu:15.04 hanzai/ubuntu:15.04       // hanzai是我的账号名

上传镜像:

$ dokcer push NAME[:TAG]   // 默认上传到Docker Hub官方仓库
或:
$ docker push [REGISTRY_HOST[:REGISTRY_PORT]/]NAME[:TAG]


$ docker push hanzai/ubuntu:15.04

4 操作Docker容器

容器是镜像的一个运行实例,不同的是,镜像是静态的只读文件,而容器带有运行时需要的可写文件层。

4.1 创建容器

$ docker create -it ubuntu:14.04   // 创建容器,会为该容器分配一个名称,可用docker ps查看,也可以用--name string参数来指定容器名称
d4f5a0e3ae733....                  // 容器ID
$ docker start  d4f5               // 启动容器

或
$ docker run -it ubuntu:14.04 /bin/bash   // 创建并启动容器
# exit 或 Ctrl+d                          // 退出容器

或
$ docker run -d ubuntu:14.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"                    
                                  // 后台以守护进程的形式运行
ab855a5b5af2b...                  // 容器ID
$ docker logs ab855               // 查看日志
hello world
hello world
...

使用docker run时,后台运行的标准操作为:

  • 检查本地是否存在制定的镜像,不存在就从公有仓库下载
  • 利用镜像创建,并启动一个容器
  • 分配一个文件系统给容器,并在只读的镜像层外面挂载一层可读写层
  • 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
  • 从网桥的地址池配置一个ip地址给容器
  • 执行用户指定的应用程序
  • 执行完毕后容器被自动终止

4.2 终止容器

$ docker stop [-t|--time[=10]] [CONTAINER]  // 等待一段时间(默认10秒)后关闭容器
$ docker restart [CONTAINER]                // 重启容器

4.3 进入容器

使用-d参数启动容器后会进入后台,用户无法看到容器中的信息,也无法进行操作.

  1. attach命令
$ docker attach [--detach-keys[=[]]] [--no-stdin] [--sig-proxy[=true]] CONTAINER_NAME   // CONTAINER_NAME可以使用docker ps查询
--detach-keys[=[]] : 退出attach模式的快捷键序列,默认CTRL-p或CTRL-q.
--no-stdin=true|false : 是否关闭标准输入,默认打开.
--sig-proxy=true|false : 是否代理收到的系统信号给应用进程,默认true.

当多个窗口同时使用attach连接到同一个容器时,所有窗口都会同步显示.

  1. exec命令
$ docker exec [-d|--detach] [--detach-keyss[=[]]] [-i|--interactive] [--privileged] [-t|--tty] [-u|--user[=USER]] CONTAINER COMMAND [ARG...]
-i,--interactive : 打开标准输入接受用户输入命令,默认false.
--privileged : 是否给执行命令最高权限,默认false.
-t,--tty : 分配伪终端,默认false.
-u,--user[=USER] : 执行命令的用户名或ID.

如:
$ docker exec -it ab855a5b5af2b /bin/bash

4.4 删除容器

删除处于终止或退出状态的容器:

$ docker rm [-f|--force] [-l|--link] [-v|--volumes] CONTAINER [CONTAINER...]
-f,--force : 是否强行终止并删除一个运行中的容器.
-l,--link : 删除容器连接,但保留容器.
-v,--volumes : 删除容器挂载的数据卷.

4.5 导入和导出容器

  1. 导出容器
    导出容器是指导出一个已经创建的容器到一个文件中,不管容器是否处于运行状态.
$ docker export -o filename.tar CONTAINER
或
$ docker export CONTAINER > filename.tar
  1. 导入容器
    导出的文件可以使用docker import导入变成镜像:
$ docker import [-c|--change[=[]]] [-m|--message[=MESSAGE]] file|URL|[REPOSITORY[:TAG]]
例如:
$ docker import filename.tar REPOSITORY:TAG

5 访问Docker仓库

  • docker仓库是集中存放镜像文件的场所,分公有仓库和私有仓库
  • 仓库注册服务器(Registry)是存放仓库(Repository)的地方
  • 一个Registry可以存放多个Repository,每个Repository中存放一类镜像,用标签(tag)进行区分

5.1 Docker Hub

登陆:

$ docker login

镜像资源分为两类:

  • 基础镜像/根镜像:由Docker公司创建,验证,支持,提供.往往使用一个单词作为镜像名称.
  • 用户创建的镜像:由Docker用户创建并维护,带有用户名称为前缀,表明是某用户下的某仓库.

docker支持自动创建功能,允许用户通过Docker Hub指定跟踪一个目标网站(目前支持Github或BitBucket)上的项目,一旦项目发生新的提交,则自动执行创建.

6 Docker数据管理

容器中的数据管理方式主要有:

  • 数据卷:容器内数据直接映射到本地主机环境;
  • 数据卷容器:使用特定容器维护数据卷。

6.1 数据卷

数据卷是一个可供容器使用的特殊目录,它将主机操作系统目录直接映射进容器。其提供了很多特性:

  • 数据卷可以在容器之间共享和重用,容器间传递数据将变得高效方便;
  • 对数据卷内数据的修改会立马生效,无论是容器内操作还是本地操作;
  • 对数据卷的更新不会影响镜像,解耦了应用和数据;
  • 卷会一直存在,直到没有容器使用,可以安全地卸载它。
  1. 在容器内创建一个数据卷:
使用ubuntu:14.04镜像创建一个ubuntu容器,使用-v参数创建一个数据卷挂载到容器的/hanry目录中:
$ docker run -it --name ubutnu -v /hanry ubuntu:14.04 /bin/bash
  1. 挂载一个主机目录作为数据卷:
使用ubuntu:14.04镜像创建一个ubuntu容器,使用-v参数指定挂载一个本地已有目录F:\forDocker到容器的/hanry目录中作为数据卷:
$ docker run -it --name ubutnu -v F:\forDocker:/hanry ubuntu:14.04 /bin/bash

docker挂载数据卷的默认权限是读写(rw),可以通过设置修改:

$ docker run -it --name ubutnu -v F:\forDocker:/hanry:ro ubuntu:14.04 /bin/bash

在这个过程中可能会遇到目录无法共享或防火墙问题,可参考以下方式解决:
解决共享磁盘问题的方案

6.2 数据卷容器

如果用户需要在多个容器之间共享一些持续更新的数据,最简单的方式是使用数据卷容器。数据卷容器也是一个容器,但它的目的是专门用来提供数据卷供其他容器挂载。

首先,创建一个数据卷容器dbdata,并在其中创建一个数据卷挂载到/dbdata:
$ docker run -it -v /dbdata --name dbdata ubuntu:14.04

然后,在其他容器中使用--volumes-from参数来挂载dbdata容器中的数据卷:
$ docker run -it --volumes-from dbdata --name db1 ubuntu:14.04
$ docker run -it --volumes-from dbdata --name db2 ubuntu:14.04

这样,在dbdata、db1、db2三个容器中的/dbdata目录下修改数据,其他容器都能看到。

若删除挂载的容器,数据卷不会自动删除。若要删除一个数据卷,必须在删除最后一个还挂载着它的容器时显式使用-v参数来删除:

$ docker rm -v CONTAINER   // 在删除容器时,顺便删除容器挂载的数据卷

6.3 利用数据卷容器来迁移数据

  1. 备份
1、从dbdata容器中挂载数据卷,也就是挂载到目录/dbdata
2、将本地目录F:\Docker2挂载到容器中的/backup目录作为数据卷
3、使用镜像ubuntu:14.04创建并启动一个worker容器
4、worker容器启动后,将/dbdata目录下内容打包压缩到容器内的/backup/backup.tar,也就是主机F:\Docker2目录下的backup.tar
$ docker run -it --volumes-from dbdata -v F:\Docker2:/backup --name worker ubuntu:14.04 tar cvf /backup/backup.tar /dbdata

或:
$ docker run -it --volumes-from dbdata -v F:\Docker2:/backup --name worker ubuntu:14.04 /bin/bash
# tar cvf /backup/backup.tar /dbdata
  1. 恢复
1、从dbdata容器中挂载数据卷,也就是挂载到目录/dbdata
2、将本地目录F:\Docker2挂载到容器中的/backup目录作为数据卷
3、使用镜像ubuntu:14.04创建并启动一个容器
4、容器启动后,将主机F:\Docker2目录下,也就是/backup目录下的backup.tar解压
$ docker run -it --volumes-from dbdata -v F:\Docker2:/backup ubuntu:14.04 tar xvf /backup/backup.tar

或:
$ docker run -it --volumes-from dbdata -v F:\Docker2:/backup ubuntu:14.04 /bin/bash
# tar xvf /backup/backup.tar

7 端口映射与容器 互联

Docker提供了两种满足服务访问的功能:

  • 允许映射容器内应用服务端口到本地宿主主机
  • 互联机制实现多个容器间通过容器名来快速访问

7.1 端口映射实现访问容器

当容器运行一些网络应用,要让外部访问这些应用时,可以通过-P或-p参数来指定映射端口。使用-P参数时,会随机映射一个端口到内部容器开放网络的端口(使用docker ps -l或者docker logs -f CONTAINER命令查看);使用-p参数可以指定要映射的端口,并且在一个指定端口上只能绑定一个容器,支持的格式有:

  • 映射到指定地址的指定端口 IP:HostPort:ContainerPort
  • 映射到指定地址的任意端口 IP::ContainerPort
  • 映射到所有接口地址 HostPort:ContainerPort
将本地端口映射到容器的端口,可以多次使用-p参数多次绑定:
$ docker run -d -p 5000:5000 -p 3000:80 training/webapp python app.py

映射一个特定的地址:
$ docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py
指定udp端口:
$ docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py

绑定127.0.0.1的任意端口到容器的5000端口,本地主机会自动分配一个端口:
$ docker run -d -p 127.0.0.1::5000 training/webapp python app.py

查看端口
$ docker port CONTAINER port

7.2 互联机制实现便捷访问

容器的互联会在源和接收容器之间创建连接关系,接收容器可以通过容器名快速访问到源容器,而不用指定具体的IP地址。

使用--link name:alias参数可以让容器之间安全地进行交互。name是要连接的容器的名称,alias是这个连接的别名。

$ docker run -d --name db training/postgres
$ docker run -d -P --name web --link db:db training/webapp python app.py

docekr通过两种方式为容器公开连接信息:

  • 更新环境变量:
$ docker run -rm --name web2 --link db:db training/webapp env
输出中DB_开头的环境变量是供web容器连接db容器使用的。
  • 更新/etc/hosts文件。
docker会添加host信息到父容器的/etc/hosts文件中:
$ docker run -it -rm --link db:db training/webapp /bin/bash
# cat /etc/hosts
// 里边包含两个host信息,一个是web容器,使用自己的id作为默认主机名;一个是db容器的IP和主机名。
# ping db   // 可以直接使用容器名进行通信。

8 使用Dockerfile创建镜像

Dockerfile是一个文本格式的配置文件,用户可以使用Dockerfile来快速创建自定义的镜像。

8.1 基本结构

Dockerfile由一行行命令语句组成,以#开头表示注释。一般包含四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。

# 使用的基础镜像,必须放在第一行
FROM ubutntu

# 维护者信息
MAINTAINER docker_user docker_user@email.com

# 镜像操作指令。
# RUN指令将对镜像执行跟随的命令。每执行一条RUN指令,镜像就添加新的一层,并提交。
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf

# 容器启动时执行的指令
CMD /usr/sbin/nginx

8.2 指令说明

指令1

指令2
  1. FROM
    FROM指令是最重要的一个且必须为Dockerfile文件开篇的第一个非注释行,用于为映像文件构建过程指定基准镜像,后续的指令运行于此基准镜像所提供的运行环境。如果本地不存在,则会从Docker Hub Registry上拉取所需的镜像文件。
    如果在同一个Dockerfile中创建多个镜像,可以使用多个FROM指令。
FROM <image>
FROM <image>:<tag>
FROM <image>@<digest>
  1. MAINTAINER
    指定维护者信息,会被写入生成镜像的Author属性中,格式:
MAINTAINER <name>
MAINTAINER image_creator@docker.com
  1. RUN
    运行指定命令。格式:
RUN <command>  // 默认在shell终端中运行命令
RUN ["<executable>","<param1>","<param2>"]  // 该指令会被解析为Json数组,必须使用双引号。使用exec执行,不启动shell。

每条RUN指令在当前镜像的基础上执行指定命令,并提交为新的镜像。若命令较长可以使用\来换行。

  1. CMD
    指定容器启动时默认执行的命令,格式:
CMD ["<executable>","<param1>","<param2>"] // 使用exec执行,推荐使用
CMD <command> <param1> <param2>  // 在/bin/sh中执行
CMD ["<param1>","<param2>"]

每个Dockerfile只能有一条CMD命令,若有多条CMD命令,则只执行最后一条。

  1. LABEL
    指定生成镜像的元数据标签信息,格式:
LABEL <key>=<value> <key>=<value> ...
  1. EXPOSE
    声明镜像内服务所监听的端口,格式:
EXPOSE <port> [<port> ...]

只是声明,并不会自动完成端口映射。

  1. ENV
    为镜像定义所需的环境变量,并可被Dockerfile文件中位于其后的其他指令(ENV、ADD、COPY等)所调用。格式:
ENV <key> <value>
ENV <key>=<value> ...
  1. ADD
    格式:
ADD <src> <dest>

复制指定的<src>路径下的内容到容器的<dest>路径下,其中<src>可以是Dockerfile所在目录的一个相对路径,也可以是一个URL,还可以是tar文件(会自动解压到<dest>路径下);<dest>可以是镜像内的绝对路径,或相对于工作目录(WORKDIR)的相对路径。

  1. COPY
    格式:
CPOY <src> <dest>

用于从Docker主机的<src>复制文件至创建的镜像的<dest>,若<dest>不存在则自动创建。

  1. ENTRYPOINT
    指定镜像的默认入口命令,会在启动容器时作为根命令执行,所有传入值作为该命令的参数,格式:
ENTRYPOINT  <command> <param1> <param2>
ENTRYPOINT ["executable","parm1","parm2"]

每个Dockerfile只能有一条ENTRYPOINT命令,若有多条ENTRYPOINT命令,则只执行最后一条。运行是可以被--entrypoint参数覆盖。

  1. VOLUME
    创建一个数据卷挂载点,格式:
VOLUME ["/data"]

可以从本地主机或其他容器挂载数据卷,一般用来存放数据库和需要保存的数据等。

  1. USER
    指定运行images的用户名或UID,默认的运行用户为root。后续指令也会用指定的身份。格式:
USER <UID> | <User_Name>
  1. WORKDIR
    为Dockerfile中所有的RUN、CMD、ENTRYPOINT、COPY和ADD设定工作目录。格式:
WORKDIR  <dirpath>

可以使用多个WORKDIR指令。后续命令若是相对路径,则会基于之前的命令指定的路径。

  1. ARG
    指定镜像内使用的参数,在执行docker build命令时才以--build-arg <varname>=<name>传入,格式:
ARG <name>[=<default value>]
  1. ONBUILD
    若所创建的镜像作为其他镜像的基础镜像时,所执行的创建操作指令。格式:
ONBUILD <instruction>
  1. STOPSIGNAL
    指定所创建镜像启动的容器接收退出的信号值。格式:
STOPSIGNAL signal
  1. HEALTHCHECK
    容器启动时如何进行健康检查,格式:
HEALTHCHECK [options] CMD command // 根据所执行命令返回值是否为0来判断
HEALTHCHECK NONE // 禁止基础镜像中的健康检查
  1. SHELL
    指定其他命令使用shell时的默认shell类型,格式:
SHELL ["executable","parm1","parm2"]
默认:SHELL ["/bin/sh","-c"]

8.3 创建镜像

$ docker build [options] path

读取path下的Dockerfile,并将该路径下的所以内容发送给Docker服务端,有服务端来创建镜像。

/tmp/docker_builder下的Dockerfile,-t指定生成镜像标签信息
$ docker build -t build_repo/first_image /tmp/docker_builder

8.4 .dockerignore文件

可以使用.dockerignore文件来让Docker忽略指定的目录和文件,如:

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

推荐阅读更多精彩内容