OCI Image Spec 鏡像格式規范

概述

參考OCI 官網 OCI 鏡像規范

OCI鏡像規范定義一個鏡像包含一個manifest、一個image index(可選)、一組文件系統layer和一個配置文件。

OCI 鏡像規范的主要目的:

統一標準化容器鏡像格式,讓標準鏡像能夠在各容器軟件下構建、傳遞及準備容器鏡像運行。

Image 規范的高層組件包含:

  • Image Manifest 清單文件是組成一個容器 image 的組件描述文檔

  • Image Index (可選) 更高層的manifest文件,指向一組 manifests 和 descriptors 列表

  • Image Layout 鏡像布局,表示一個鏡像的內容布局

  • Filesystem Layer 描述一個容器文件系統的一個"變化集合"

  • Image Configuration 配置文件包含如應用參數、環境等信息

  • Conversion 如何解析的描述文檔

  • Descriptor 描述了類型、元數據和內容尋址的格式描述文件

  • Signatures (可選 ) 簽名是基于簽名的圖像內容的地址

  • Naming (可選 ) 命名是聯合基于DNS,可以授權

OCI Media Type 文件類型:

Media Type 說明
application/vnd.oci.descriptor.v1+json Content Descriptor 內容描述文件
application/vnd.oci.layout.header.v1+json OCI Layout 布局描述文件
application/vnd.oci.image.index.v1+json Image Index 高層次的鏡像元信息文件
application/vnd.oci.image.manifest.v1+json Image Manifest 鏡像元信息文件
application/vnd.oci.image.config.v1+json Image Config 鏡像配置文件
application/vnd.oci.image.layer.v1.tar Image Layer 鏡像層文件
application/vnd.oci.image.layer.v1.tar+gzip Image Layer 鏡像層文件gzip壓縮
application/vnd.oci.image.layer.nondistributable.v1.tar Image Layer 非內容尋址管理
application/vnd.oci.image.layer.nondistributable.v1.tar+gzip Image Layer, gzip壓縮 非內容尋址管理

類型關系圖

media-types.png

OCI Content Descriptor
OCI 鏡像由幾部分組成,每個組件都是存儲在一個目錄結構中。每個組件之間都是通過內容尋址的方式互相引用。Content Descriptor 描述了一個目標內容的位置。Content Descriptor 包含:內容的類型、內容的標識符、內容的大小。Content Descriptor 必須通過嵌入到其他格式中使用。

Content Descriptor 屬性

  • mediaType string
  • digest string
  • size int64
  • urls array of strings
  • annotations string-string map
  • data string (保留字段)

摘要和校驗
digest屬性是Descriptor的核心,扮演了內容的標識符的角色。digest使用了防碰撞的哈希算法唯一的標識了內容。如果標識符能夠以安全的獲取。那么就算內容通過了不安全的來源獲取,也能獨立計算出標識符對內容的正確性進行確認。

digest的格式要求與示例:(sha256已經是一個廣泛使用的Hash算法)

digest      := algorithm ":" hex
algorithm   := /[a-z0-9_+.-]+/
hex         := /[a-f0-9]+/

sha256:6c3c624b58dbbcd3c0dd82b4c53f04194d1247c6eebdaab7c610cf7d66709b3b

Content Descriptor 示例
這個 Content Descriptor 描述了一個Manifest

{
  "mediaType": "application/vnd.oci.image.manifest.v1+json",
  "size": 7682,
  "digest": "sha256:5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270"
}

OCI Image Manifest 鏡像清單格式規范

參考

Manifest 的三大主要目標:

  1. 內容可尋址(通過 hash 算法為鏡像和它的組件生成唯一ID)

  2. 支持多種平臺的架構鏡像(由一個更上層的 manifest 說明包含的鏡像 manifests 其具體平臺的版本情況)

  3. 能被解析成為 OCI 運行時規范

image manifest 包括一個 Image Config 和 一組 Image Layers 。

application/vnd.oci.image.manifest.v1+json 定義:

字段名 類型 必須 說明
schemaVersion int 必須 當前版本
mediaType string 保留 用于標識當前文件是什么類型的
config descriptor 必須 用于標識鏡像的配置文件的位置<br />application/vnd.oci.image.config.v1+json
layers array of descriptor 列表中的每一個成員都是一個鏡像層,最底層的鏡像在列表的第一項,其他各層按照堆疊順序依次排列在后面。最終得到的文件系統應該和在一個空文件夾上堆疊各層得到的結果一樣。用于堆疊的空文件夾的各種權限是不確定的。鏡像層的mediaType,有比較多的選擇:
application/vnd.oci.image.layer.v1.tar
application/vnd.oci.image.layer.v1.tar+gzip
application/vnd.oci.image.layer.nondistributable.v1.tar
application/vnd.oci.image.layer.nondistributable.v1.tar+gzip
annotations string-string map 注釋

manifest 示例:

{
  "schemaVersion": 2,
  "config": {
    "mediaType": "application/vnd.oci.image.config.v1+json",
    "size": 7023,
    "digest": "sha256:b5b2b2c507a0944348e0303114d8d93aaaa081732b86451d9bce1f432a537bc7"
  },
  "layers": [
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "size": 32654,
      "digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f"
    },
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "size": 16724,
      "digest": "sha256:3c3a4604a545cdc127456d94e421cd355bca5b528f4a9c1905b15da2eb4a4c6b"
    },
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "size": 73109,
      "digest": "sha256:ec4b8955958665577945c89419d1af06b5f7636b4ac3da7f12184802ad867736"
    }
  ],
  "annotations": {
    "com.example.key1": "value1",
    "com.example.key2": "value2"
  }
}

OCI Image Index 鏡像索引格式規范

參考

Image Index是一個更高層次的Manifest,一般在一個鏡像需要提供多個平臺支持時使用。

MediaType:application/vnd.oci.image.index.v1+json

字段名 類型 必須 說明
schemaVersion int 必須 必須填2(為了兼容老版本的Docker)
mediaType string 保留 用于標識當前文件是什么類型的
manifests array of objects 必須 給出了對于特定平臺的Manifests列表
mediaType string Manifests string application/vnd.oci.image.manifest.v1+json
platform object 可選 描述了Manifest中描述的鏡像是運行
在哪一個指定的平臺
architecture string 必須 指定了CPU的架構類型
os string 必須 指定了操作系統的類型
os.version string 可選 指定操作系統的版本要求
os.features array of strings 可選 指定了一些對于系統的特殊要求
variant string 可選 指定了CPU的版本要求
features array of strings 可選 指定了一些對于CPU指令集的特殊要求。
(比如sse4、aes)
annotations string-string map 注解

index 示例:

{
  "schemaVersion": 2,
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "size": 7143,
      "digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f",
      "platform": {
        "architecture": "ppc64le",
        "os": "linux"
      }
    },
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "size": 7682,
      "digest": "sha256:5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270",
      "platform": {
        "architecture": "amd64",
        "os": "linux",
        "os.features": [
          "sse4"
        ]
      }
    }
  ],
  "annotations": {
    "com.example.key1": "value1",
    "com.example.key2": "value2"
  }
}

OCI Image Layout 鏡像布局規范

參考

OCI的鏡像布局是指內容尋址(blobs)和位置尋址(refs)的目錄結構。這個布局可以使用多種方式傳輸:歸檔文件如tar/zip、共享文件系統環境如nfs、網絡傳輸如http/ftp/rsync等

鏡像布局有以下部分組成:

  1. blobs directory 內容尋址的塊文件,目錄必須存在,但是可以為空。
  2. oci-layout file 文件必須存在、必須是JSON格式,文件中必須包含一個imageLayoutVersion字段文件中可以有其他字段作為擴展使用
  3. index.json file 文件必須存在、必須是JSON格式,文件中必須包含鏡像Index的基本屬性

示例

$ cd example.com/app/
$ find . -type f
./index.json
./oci-layout
./blobs/sha256/3588d02542238316759cbf24502f4344ffcc8a60c803870022f335d1390c13b4
./blobs/sha256/4b0bc1c4050b03c95ef2a8e36e25feac42fd31283e8c30b3ee5df6b043155d3c
./blobs/sha256/7968321274dc6b6171697c33df7815310468e694ac5be0ec03ff053bb135e768

blob文件名命名是通過內容計算的shasum

$ shasum -a 256 ./blobs/sha256/afff3924849e458c5ef237db5f89539274d5e609db5db935ed3959c90f1f2d51
afff3924849e458c5ef237db5f89539274d5e609db5db935ed3959c90f1f2d51 ./blobs/sha256/afff3924849e458c5ef237db5f89539274d5e609db5db935ed3959c90f1f2d51

Index.json 文件

index.json 文件相當于整個鏡像的入口。從這個文件可以獲取整個鏡像依賴到的所有文件的信息。 每一個在manifests 字段中的 descriptor 都指向一個 application/vnd.oci.image.index.v1+json 或 application/vnd.oci.image.manifest.v1+json 類型的文件。

一個通用的做法,org.opencontainers.image.ref.name 注解被認為是鏡像 Tag 的含義。表示鏡像的不同版本。

index.json 示例

{
  "schemaVersion": 2,
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.index.v1+json",
      "size": 7143,
      "digest": "sha256:0228f90e926ba6b96e4f39cf294b2586d38fbb5a1e385c05cd1ee40ea54fe7fd",
      "annotations": {
        "org.opencontainers.image.ref.name": "stable-release"
      }
    },
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "size": 7143,
      "digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f",
      "platform": {
        "architecture": "ppc64le",
        "os": "linux"
      },
      "annotations": {
        "org.opencontainers.image.ref.name": "v1.0"
      }
    },
    {
      "mediaType": "application/xml",
      "size": 7143,
      "digest": "sha256:b3d63d132d21c3ff4c35a061adf23cf43da8ae054247e32faa95494d904a007e",
      "annotations": {
        "org.freedesktop.specifications.metainfo.version": "1.0",
        "org.freedesktop.specifications.metainfo.type": "AppStream"
      }
    }
  ],
  "annotations": {
    "com.example.index.revision": "r124356"
  }
}

OCI-layout 文件

在鏡像規范中,這個文件特別簡單,只有一個布局版本的字段。

oci-layout 示例

{
    "imageLayoutVersion": "1.0.0"
}

Blobs 文件夾

blobs文件夾下的子文件夾是以Hash算法的名稱來命名的,這些子文件夾下包含了真正的實體文件。
一個塊被digest引用時(:,descriptor),這個塊必須存放在blobs/<alg>/<hex>目錄。
blobs文件夾下面可能會存放很多已經沒有任何引用的塊文件。
blobs文件夾下可以缺失一些被引用的塊文件,只要被其他額外的塊填滿就可以了。

Blobs 示例 Image Index

$ cat ./blobs/sha256/9b97579de92b1c195b85bb42a11011378ee549b02d7fe9c17bf2a6b35d5cb079 | jq
{
  "schemaVersion": 2,
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "size": 7143,
      "digest": "sha256:afff3924849e458c5ef237db5f89539274d5e609db5db935ed3959c90f1f2d51",
      "platform": {
        "architecture": "ppc64le",
        "os": "linux"
      }
    },
    ...

Blobs 示例 Image Manifest

$ cat ./blobs/sha256/afff3924849e458c5ef237db5f89539274d5e609db5db935ed3959c90f1f2d51 | jq
{
  "schemaVersion": 2,
  "config": {
    "mediaType": "application/vnd.oci.image.config.v1+json",
    "size": 7023,
    "digest": "sha256:5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270"
  },
  "layers": [
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "size": 32654,
      "digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f"
    },
    ...

Blobs 示例 Image Config

$ cat ./blobs/sha256/5b0bcabd1ed22e9fb1310cf6c2dec7cdef19f0ad69efa1f392e94a4333501270 | jq
{
  "architecture": "amd64",
  "author": "Alyssa P. Hacker <alyspdev@example.com>",
  "config": {
    "Hostname": "8dfe43d80430",
    "Domainname": "",
    "User": "",
    "AttachStdin": false,
    "AttachStdout": false,
    "AttachStderr": false,
    "Tty": false,
    "OpenStdin": false,
    "StdinOnce": false,
    "Env": [
      "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
    ],
    "Cmd": null,
    "Image": "sha256:6986ae504bbf843512d680cc959484452034965db15f75ee8bdd1b107f61500b",
    ...

Image Layer Blob

$ cat ./blobs/sha256/e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f
[tar stream]

Image Layer Filesystem Changeset 鏡像層規范

參考

如何序列化 文件系統 以及 文件系統的改變(如刪除文件) 到一個 blob 文件稱之為" layer ",由一個或多個layer層疊加構成一個完整的文件系統。

Image Filesystem Changeset文件系統改變集

每一個layer都會有對它相對于父layer增、刪、改的文件的一個存檔,使用諸如AUFS等聯合掛載文件系統,可以將一系列的image layer以單一的文件系統的形式呈現出來。

Change type 文件系統改變類型

Additions
Modifications
Removals

創建 Image Filesystem Changeset

  1. 創建根文件系統

    根文件系統是基礎或父 layer , 此處初始為空目錄結構,使用唯一的目錄名rootfs-c9d-v1

rootfs-c9d-v1/
  1. 創建初始文件與目錄
rootfs-c9d-v1/
    etc/
        my-app-config
    bin/
        my-app-binary
        my-app-tools

? rootfs-c9d-v1 目錄會被作為以下文件的打包存檔的入口(tar)

./
./etc/
./etc/my-app-config
./bin/
./bin/my-app-binary
./bin/my-app-tools
  1. 復制或快照初始文件系統

    以前面的根文件系統復制或快照,創建一個新的目錄和初始化文件系統,目錄名為rootfs-c9d-v1.s1

rootfs-c9d-v1.s1/
    etc/
        my-app-config
    bin/
        my-app-binary
        my-app-tools
  增加一個./etc/my-app.d目錄包含default.cfg文件,刪除存在的my-app-config文件。與此同時,改變./bin/my-app-tools二進制文件內容或屬性。
rootfs-c9d-v1.s1/
    etc/
        my-app.d/
            default.cfg
    bin/
        my-app-binary
        my-app-tools
  1. 檢測變化和表示變化項

    通過兩個目錄進行比較("rootfs-c9d-v1" VS "rootfs-c9d-v1.s1"),查詢文件是否有被增加、修改、刪除操作

Added:      /etc/my-app.d/
Added:      /etc/my-app.d/default.cfg
Modified:   /bin/my-app-tools
Deleted:    /etc/my-app-config
  1. 創建 changeset 文件

打包 tar 文件僅包含 changeset :

  • 增加與修改的文件和目錄完整打包
  • 刪除的文件或目錄由whiteout文件(.wh.命名)來標識
./etc/my-app.d/
./etc/my-app.d/default.cfg
./bin/my-app-tools
./etc/.wh.my-app-config

OCI Runtime Filesystem Bundle 運行時文件系統包

參考

OCI Image 可通過鏡像名稱發現、下載、hash值來驗證、簽名受信以及解包成 OCI 運行時 Bundle。一個標準的容器 bundle 包含容器加載和運行所需的所有信息,其包含如下:

  1. config.json 容器配置數據文件,必須與文件系統同目錄下,文件名必須為config.json
  2. root filesystem 容器 root 文件系統(啟動的只讀文件),在 config.json 文件內有指定 root.path。

config.json 配置文件說明

config樣例:

{
    "ociVersion": "1.0.1",
    "process": {
        "terminal": true,
        "user": {
            "uid": 1,
            "gid": 1,
            "additionalGids": [
                5,
                6
            ]
        },
        "args": [
            "sh"
        ],
        "env": [
            "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
            "TERM=xterm"
        ],
        "cwd": "/",
        "capabilities": {
            "bounding": [
                "CAP_AUDIT_WRITE",
                "CAP_KILL",
                "CAP_NET_BIND_SERVICE"
            ],
            "permitted": [
                "CAP_AUDIT_WRITE",
                "CAP_KILL",
                "CAP_NET_BIND_SERVICE"
            ],
            "inheritable": [
                "CAP_AUDIT_WRITE",
                "CAP_KILL",
                "CAP_NET_BIND_SERVICE"
            ],
            "effective": [
                "CAP_AUDIT_WRITE",
                "CAP_KILL"
            ],
            "ambient": [
                "CAP_NET_BIND_SERVICE"
            ]
        },
        "rlimits": [
            {
                "type": "RLIMIT_CORE",
                "hard": 1024,
                "soft": 1024
            },
            {
                "type": "RLIMIT_NOFILE",
                "hard": 1024,
                "soft": 1024
            }
        ],
        "apparmorProfile": "acme_secure_profile",
        "oomScoreAdj": 100,
        "selinuxLabel": "system_u:system_r:svirt_lxc_net_t:s0:c124,c675",
        "noNewPrivileges": true
    },
    "root": {
        "path": "rootfs",
        "readonly": true
    },
    "hostname": "slartibartfast",
    "mounts": [
        {
            "destination": "/proc",
            "type": "proc",
            "source": "proc"
        },
        {
            "destination": "/dev",
            "type": "tmpfs",
            "source": "tmpfs",
            "options": [
                "nosuid",
                "strictatime",
                "mode=755",
                "size=65536k"
            ]
        },
        {
            "destination": "/dev/pts",
            "type": "devpts",
            "source": "devpts",
            "options": [
                "nosuid",
                "noexec",
                "newinstance",
                "ptmxmode=0666",
                "mode=0620",
                "gid=5"
            ]
        },
        {
            "destination": "/dev/shm",
            "type": "tmpfs",
            "source": "shm",
            "options": [
                "nosuid",
                "noexec",
                "nodev",
                "mode=1777",
                "size=65536k"
            ]
        },
        {
            "destination": "/dev/mqueue",
            "type": "mqueue",
            "source": "mqueue",
            "options": [
                "nosuid",
                "noexec",
                "nodev"
            ]
        },
        {
            "destination": "/sys",
            "type": "sysfs",
            "source": "sysfs",
            "options": [
                "nosuid",
                "noexec",
                "nodev"
            ]
        },
        {
            "destination": "/sys/fs/cgroup",
            "type": "cgroup",
            "source": "cgroup",
            "options": [
                "nosuid",
                "noexec",
                "nodev",
                "relatime",
                "ro"
            ]
        }
    ],
    "hooks": {
        "prestart": [
            {
                "path": "/usr/bin/fix-mounts",
                "args": [
                    "fix-mounts",
                    "arg1",
                    "arg2"
                ],
                "env": [
                    "key1=value1"
                ]
            },
            {
                "path": "/usr/bin/setup-network"
            }
        ],
        "poststart": [
            {
                "path": "/usr/bin/notify-start",
                "timeout": 5
            }
        ],
        "poststop": [
            {
                "path": "/usr/sbin/cleanup.sh",
                "args": [
                    "cleanup.sh",
                    "-f"
                ]
            }
        ]
    },
    "linux": {
        "devices": [
            {
                "path": "/dev/fuse",
                "type": "c",
                "major": 10,
                "minor": 229,
                "fileMode": 438,
                "uid": 0,
                "gid": 0
            },
            {
                "path": "/dev/sda",
                "type": "b",
                "major": 8,
                "minor": 0,
                "fileMode": 432,
                "uid": 0,
                "gid": 0
            }
        ],
        "uidMappings": [
            {
                "containerID": 0,
                "hostID": 1000,
                "size": 32000
            }
        ],
        "gidMappings": [
            {
                "containerID": 0,
                "hostID": 1000,
                "size": 32000
            }
        ],
        "sysctl": {
            "net.ipv4.ip_forward": "1",
            "net.core.somaxconn": "256"
        },
        "cgroupsPath": "/myRuntime/myContainer",
        "resources": {
            "network": {
                "classID": 1048577,
                "priorities": [
                    {
                        "name": "eth0",
                        "priority": 500
                    },
                    {
                        "name": "eth1",
                        "priority": 1000
                    }
                ]
            },
            "pids": {
                "limit": 32771
            },
            "hugepageLimits": [
                {
                    "pageSize": "2MB",
                    "limit": 9223372036854772000
                },
                {
                    "pageSize": "64KB",
                    "limit": 1000000
                }
            ],
            "memory": {
                "limit": 536870912,
                "reservation": 536870912,
                "swap": 536870912,
                "kernel": -1,
                "kernelTCP": -1,
                "swappiness": 0,
                "disableOOMKiller": false
            },
            "cpu": {
                "shares": 1024,
                "quota": 1000000,
                "period": 500000,
                "realtimeRuntime": 950000,
                "realtimePeriod": 1000000,
                "cpus": "2-3",
                "mems": "0-7"
            },
            "devices": [
                {
                    "allow": false,
                    "access": "rwm"
                },
                {
                    "allow": true,
                    "type": "c",
                    "major": 10,
                    "minor": 229,
                    "access": "rw"
                },
                {
                    "allow": true,
                    "type": "b",
                    "major": 8,
                    "minor": 0,
                    "access": "r"
                }
            ],
            "blockIO": {
                "weight": 10,
                "leafWeight": 10,
                "weightDevice": [
                    {
                        "major": 8,
                        "minor": 0,
                        "weight": 500,
                        "leafWeight": 300
                    },
                    {
                        "major": 8,
                        "minor": 16,
                        "weight": 500
                    }
                ],
                "throttleReadBpsDevice": [
                    {
                        "major": 8,
                        "minor": 0,
                        "rate": 600
                    }
                ],
                "throttleWriteIOPSDevice": [
                    {
                        "major": 8,
                        "minor": 16,
                        "rate": 300
                    }
                ]
            }
        },
        "rootfsPropagation": "slave",
        "seccomp": {
            "defaultAction": "SCMP_ACT_ALLOW",
            "architectures": [
                "SCMP_ARCH_X86",
                "SCMP_ARCH_X32"
            ],
            "syscalls": [
                {
                    "names": [
                        "getcwd",
                        "chmod"
                    ],
                    "action": "SCMP_ACT_ERRNO"
                }
            ]
        },
        "namespaces": [
            {
                "type": "pid"
            },
            {
                "type": "network"
            },
            {
                "type": "ipc"
            },
            {
                "type": "uts"
            },
            {
                "type": "mount"
            },
            {
                "type": "user"
            },
            {
                "type": "cgroup"
            }
        ],
        "maskedPaths": [
            "/proc/kcore",
            "/proc/latency_stats",
            "/proc/timer_stats",
            "/proc/sched_debug"
        ],
        "readonlyPaths": [
            "/proc/asound",
            "/proc/bus",
            "/proc/fs",
            "/proc/irq",
            "/proc/sys",
            "/proc/sysrq-trigger"
        ],
        "mountLabel": "system_u:object_r:svirt_sandbox_file_t:s0:c715,c811"
    },
    "annotations": {
        "com.example.key1": "value1",
        "com.example.key2": "value2"
    }
}

~~ 本文 END ~~

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容