Dockerfile最佳實(shí)踐

感謝光顧,簡書停更,遷移至sengmentfault:https://segmentfault.com/a/1190000018108361

原文地址:https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/

Docker 可以從 Dockerfile 中讀取指令自動(dòng)構(gòu)建鏡像,Dockerfile是一個(gè)包含構(gòu)建指定鏡像所有命令的文本文件。Docker堅(jiān)持使用特定的格式并且使用特定的命令。你可以在 Dockerfile參考 頁面學(xué)習(xí)基本知識(shí)。如果你剛接觸Dockerfile 你應(yīng)該從哪里開始學(xué)習(xí)。

這個(gè)文檔囊括了Docker公司和Docker社區(qū)推薦的創(chuàng)建易于使用且實(shí)用的Dockerfile 的最佳實(shí)踐和方法。我們強(qiáng)烈建議你遵循這些規(guī)范(事實(shí)上,如果你創(chuàng)建一個(gè)官方鏡像,你必須堅(jiān)持這些實(shí)踐。)

你可以從 buildpack-deps Dockerifle看到許多這種實(shí)踐和建議。

注:本文檔提到的Dockerfile命令的更詳細(xì)的解釋見Dockerfile參考 頁面。

通用參考和建議

容器應(yīng)該是臨時(shí)性的

從你的Dockerfile定義的鏡像啟動(dòng)的容器應(yīng)該盡可能短暫。這里的『短暫』我們是說它可以被停止和銷毀并且一個(gè)新容器的構(gòu)建和替換可以絕對(duì)最小化的變更和配置下完成。你可能想看下 應(yīng)用方法論的12個(gè)事實(shí)中進(jìn)程 一節(jié)來了解以無狀態(tài)方式運(yùn)行容器的動(dòng)機(jī)。

使用 .dockerignore文件

在大多數(shù)情況下,最好把Dockerfile放在一個(gè)空目錄里。然后,只把構(gòu)建Dockerfile需要的文件追加到該目錄中。為了改進(jìn)構(gòu)建性能,你也可以增加一個(gè).dockerignore 文件來排除文件和目錄。該文件支持與 .gitignore 類似的排除模式。更多創(chuàng)建.dockerignore信息,見 .dockerignore

避免安裝不需要的包

為了減少復(fù)雜性,依賴,文件大小,和構(gòu)建時(shí)間,你應(yīng)該避免僅僅因?yàn)樗麄兒芎糜枚惭b一些額外或者不必要的包。例如,你不需要在一個(gè)數(shù)據(jù)庫鏡像中包含一個(gè)文本編輯器。

每個(gè)容器只關(guān)心一個(gè)問題

解耦應(yīng)用為多個(gè)容器使水平擴(kuò)容和復(fù)用容器更容易。例如,一個(gè)web應(yīng)用棧會(huì)包含3個(gè)獨(dú)立的容器,每個(gè)都有自己獨(dú)立的鏡像,以解耦的方式來管理web應(yīng)用,數(shù)據(jù)庫。

你可能聽說過"一個(gè)容器一個(gè)進(jìn)程"。這種說法有很好的意圖,一個(gè)容器應(yīng)該有一個(gè)操作系統(tǒng)進(jìn)程并非真的必要。除此之外,事實(shí)上現(xiàn)在容器可以 被init進(jìn)程啟動(dòng), 一些程序可能會(huì)自己產(chǎn)生其他額外的進(jìn)程。例如,Celery 可以產(chǎn)生多個(gè)工作進(jìn)程,或者 Apache 可能為每個(gè)請求創(chuàng)建一個(gè)進(jìn)程。當(dāng)然"一個(gè)容器一個(gè)進(jìn)程"通常是一個(gè)很好的經(jīng)驗(yàn)法則,??但它不是一個(gè)很難和快速的規(guī)則(it is not a hard and fast rule)?? 用你最好的判斷來保持容器盡可能的干凈和模塊化。

如果容器之間相關(guān)依賴,你可以使用 Docker容器網(wǎng)絡(luò) 來取吧哦容器之間可以通信。

最小化層數(shù)

你需要在Dockerfile可讀性(從而可以長時(shí)間維護(hù))和它用的層數(shù)最小化之間找到平衡。Be strategic 關(guān)注你使用的層數(shù)(and cautious about the number of layers you use).

對(duì)多行參數(shù)排序

無論何時(shí),以排序多行參數(shù)來緩解以后的變化(Whenever possible, ease later changes by sorting multi-line arguments alphanumerically. )。這將幫助你避免重復(fù)的包并且使里列表更容易更新。這也使得PR更容易閱讀和審查。在反斜線(\)前加一個(gè)空格也很有幫助。

這里有個(gè)來自 buildpack-deps 鏡像的實(shí)例:

RUN apt-get update && apt-get install -y \
  bzr \
  cvs \
  git \
  mercurial \
  subversion

構(gòu)建緩存

在構(gòu)建鏡像的過程中,Docker會(huì)逐句讀取你Dockerfile中的指令按指定的順序執(zhí)行。因?yàn)槊總€(gè)指令都會(huì)被檢查Docker會(huì)在它的緩存中查找可以重用的現(xiàn)有鏡像(As each instruction is examined Docker will look for an existing image in its cache that it can reuse),而不是創(chuàng)建一個(gè)新的(重復(fù)的)鏡像。如果你根本不像使用緩存,你可以對(duì) docker build 命令使用 --no-cache=ture參數(shù)。

然而,如果你使Docker使用緩存,那么理解它什么時(shí)候找到一個(gè)匹配的鏡像以及什么不找就非常重要了。Docker將遵循的基本規(guī)則如下:

  • 以一個(gè)已經(jīng)在緩存中的付鏡像開始,下一個(gè)指令與所有源自該基礎(chǔ)鏡像的子鏡像做對(duì)比,來查看鏡像中是否有一個(gè)使用了完全相同的鏡像構(gòu)建。如果沒有,緩存不可用。
  • 大多數(shù)情況下簡單對(duì)比Dockfile中的指令與子鏡像就足夠了。然而,一些特定的指令需要更多的檢查和解釋。
  • 比如ADDCOPY指令,鏡像中的文件內(nèi)容被檢查并且為每個(gè)文件計(jì)算校驗(yàn)和。這些文件的最終修改和訪問時(shí)間將不被考慮到校驗(yàn)和內(nèi)。在查找緩存期間,校驗(yàn)和將被用于與已存在的鏡像校驗(yàn)和進(jìn)行對(duì)比。如果文件中有任何變化,比如內(nèi)容或者元數(shù)據(jù),那么緩存失效。
  • 除了ADDCOPY命令以外,緩存檢查將不會(huì)檢查容器中的文件來確定緩存匹配。比如,當(dāng)處理一個(gè)RUN apt-get -y update容器中的文件更新將不會(huì)被檢查來確定是否命中已存在緩存。在這種情況下只有命令字符串自己將被用來查找匹配。

一旦緩存失效,所有的后面的Dockerfile命令將會(huì)生成新的鏡像而且不會(huì)使用緩存。

Dcokerfile指令

下面你會(huì)找到寫Dockerfile里可用的各種指令的建議以及最佳方法。

FROM

Dockerfile參考之FROM指令

無論何時(shí)只要可能使用當(dāng)前官方倉庫鏡像作為你的基礎(chǔ)鏡像。我們推薦Debian鏡像, 因?yàn)樗粐?yán)格控制并且保持最?。壳靶∮?MB),同時(shí)是一個(gè)完整的發(fā)行版。

LABEL

理解labels對(duì)象

你可以給你的鏡像增加標(biāo)簽(labels)來協(xié)助通過項(xiàng)目組織鏡像,記錄授權(quán)信息,幫助自動(dòng)化,或者其他原因。每一個(gè)標(biāo)簽都以LABEL開頭并且跟著一對(duì)或多對(duì)鍵值對(duì)。以下實(shí)例展示了可接受的不同格式。解釋性意見也包括在內(nèi)(Explanatory comments are included inline.)。

注:如果你的字符串包含空格,它必須被引號(hào)引起來或者空格必須被轉(zhuǎn)義。如果你的字符串包含內(nèi)部引號(hào)字符("),他們需要轉(zhuǎn)義。

# Set one or more individual labels
LABEL com.example.version="0.0.1-beta"
LABEL vendor="ACME Incorporated"
LABEL com.example.release-date="2015-02-12"
LABEL com.example.version.is-production=""

# Set multiple labels on one line
LABEL com.example.version="0.0.1-beta" com.example.release-date="2015-02-12"

# Set multiple labels at once, using line-continuation characters to break long lines
LABEL vendor=ACME\ Incorporated \
      com.example.is-beta= \
      com.example.is-production="" \
      com.example.version="0.0.1-beta" \
      com.example.release-date="2015-02-12"

查看 理解labels對(duì)象 獲取可接受的標(biāo)簽鍵和值指導(dǎo)。
For information about querying labels, refer to the items related to filtering in Managing labels on objects.

RUN

Dockerfile參考 之 RUN 指令

跟之前一樣,為了讓你的Dockerfile具有更高的可讀性,更易于理解和維護(hù),使用反斜線()將較長的或者復(fù)雜的RUN語句拆分為多行。

APT-GET

可能RUN最常見的使用場景就是apt-get的應(yīng)用程序了。RUN apt-get命令,因?yàn)槭褂盟惭b軟件包有幾個(gè)需要注意的問題。

你應(yīng)該避免使用RUN apt-get upgrade或者dis-upgrade, 因?yàn)楦哥R像中許多"基本的"(essential)包不能在容器中升級(jí)。如果父鏡像中有個(gè)軟件包過期了,你應(yīng)該聯(lián)系它的維護(hù)者。如果你知道有個(gè)特定的軟件包,foo,需要升級(jí),使用apt-get install -y foo來自動(dòng)升級(jí)。

通常把RUN apt-get updateapt-get install合并到一個(gè)相同的RUN語句中,例如:

RUN apt-get update && apt-get install -y \
        package-bar \
        package-baz \
        package-foo

在一個(gè)RUN語句中單獨(dú)試用apt-get update會(huì)引起緩存問題并且導(dǎo)致后面的apt-get install指令執(zhí)行失敗。例如,你現(xiàn)在有個(gè)Dockerfile:

FROM ubuntu:14.04
RUN apt-get update
RUN apt-get install -y curl

鏡像構(gòu)建完成以后,所有的層都在Docker緩存中。假設(shè)你后來修改apt-get install增加了其他的軟件包:

FROM ubuntu:14.04
RUN apt-get update
RUN apt-get install -y curl nginx

Docker將最初的指令和修改后的指令視為相同的指令(指apt-get update這行)并且使用上一步的緩存。結(jié)果就是apt-get update沒有執(zhí)行因?yàn)槭褂昧司彺娴陌姹具M(jìn)行構(gòu)建。因?yàn)?code>apt-get update沒有執(zhí)行,你的構(gòu)建可能會(huì)安裝一個(gè)過時(shí)版本的curlngin。

使用RUN apt-get update && apt-get install -y可以確保你的Dockerfile安裝最新版本的軟件包而無需編碼或手動(dòng)干預(yù)。這個(gè)技巧被稱為"緩存破解"。你也可以通過指定軟件包版本來破解緩存。這被稱為固定版本,例如:

RUN apt-get update && apt-get install -y \
        package-bar \
        package-baz \
        package-foo=1.3.*

固定版本在構(gòu)建時(shí)強(qiáng)制查找指定版本的軟件包而不管緩存有什么。這個(gè)技巧可以減少因?yàn)橐蕾嚢奈粗兏鼘?dǎo)致的失敗。

下面是一個(gè)格式規(guī)范的RUN指令,實(shí)踐了apt-get的所有建議。

RUN apt-get update && apt-get install -y \
    aufs-tools \
    automake \
    build-essential \
    curl \
    dpkg-sig \
    libcap-dev \
    libsqlite3-dev \
    mercurial \
    reprepro \
    ruby1.9.1 \
    ruby1.9.1-dev \
    s3cmd=1.1.* \
 && rm -rf /var/lib/apt/lists/*

s3cmd指令指定了版本1.1.*。 如果前一個(gè)鏡像使用了一個(gè)老版本,指定新版本會(huì)引起apt-get update的緩存破解以確保安裝新版本。每行列出一個(gè)軟件包可以避免包重復(fù)錯(cuò)誤。

另外,你可以通過刪除 /var/lib/apt/lists 清理apt緩存來減小鏡像大小,因?yàn)閍pt緩存不會(huì)保存在層里。由于RUN語句以apt-get update開頭,所以在緩存apt-get之前,包緩存將始終被刷新。

注:Debian和Ubuntu的鏡像自動(dòng)運(yùn)行apt-get clean,所以不需要顯式調(diào)用。

USING PIPES

一些RUN命令依賴使用管道符號(hào)(|)把一個(gè)命令的輸出到另外一個(gè)命令的能力,比如以下實(shí)例:

RUN wget -O - https://some.site | wc -l > /number

Docker試用/bin/sh -c解釋器執(zhí)行這些命令,它只計(jì)算管道最后一個(gè)操作的退出代碼來確定是否成功。在上面這個(gè)例子中只要wc -l命令執(zhí)行成功這一步就構(gòu)建成功并且生成一個(gè)新的鏡像,即使wget命令失敗也是如此。

如果你想讓管道中出現(xiàn)任意錯(cuò)誤命令都返回錯(cuò)誤,在命令前加上set -o pipefail &&來確保避免出現(xiàn)未知錯(cuò)誤時(shí)鏡像也能構(gòu)建成功。例如:

RUN set -o pipefail && wget -O - https://some.site | wc -l > /number

注:并非所有的shell都支持-o pipefaile選項(xiàng)。在這種情況下(比如dash shell, 它是基于Debian鏡像的默認(rèn)shell),考慮使用RUN的exec形式來顯式選擇一個(gè)支持pipefail選項(xiàng)的shell。例如:

RUN ["/bin/bash", "-c", "set -o pipefail && wget -O - https://some.site | wc -l > /number"]

CMD

Dockerfile參考 之 CMD指令

CMD 指令用于運(yùn)行你鏡像包含中的軟件,連同任意參數(shù)。CMD應(yīng)該盡可能都是用這種形式 CMD [“executable”, “param1”, “param2”…]。然而,如果是一個(gè)作為服務(wù)的鏡像,比如Apache和Rails,你應(yīng)該像這樣執(zhí)行CMD ["apache2","-DFOREGROUND"]。實(shí)際上,實(shí)際上,這種形式的指令是推薦用于任何基于服務(wù)的鏡像。

在其他大多數(shù)情況下,CMD應(yīng)該給一個(gè)交互式Shell,比如bash,python 和 perl。例如,CMD ["perl", "-de0"], CMD ["python"], 或者 CMD [“php”, “-a”]。試用這種形式就意味著當(dāng)你執(zhí)行類似docker run -it python的一些東西,你將得到一個(gè)可用的shell(you’ll get dropped into a usable shell, ready to go)。CMD應(yīng)該很少以CMD [“param”, “param”]的形式和ENTRYPOINT一起試用,除非你和你的目標(biāo)用戶已經(jīng)非常熟悉ENTRYPOINT工作原理。

EXPOSE

Dockerfile參考之 EXPOSE 指令

EXPOSE指令指示容器將監(jiān)聽鏈接的端口。因此,你應(yīng)該為你的應(yīng)用程序試用通用的傳統(tǒng)的端口。例如,一個(gè)包含Apache Web服務(wù)器的鏡像應(yīng)該EXPOSE 80, 而一個(gè)包含MongoDB的鏡像應(yīng)該使用EXPOSE 27017等。

對(duì)于外部訪問,您的用戶可以使用指示如何將指定端口映射到所選端口的標(biāo)志來執(zhí)行docker run
???For container linking, Docker provides environment variables for the path from the recipient container back to the source (ie, MYSQL_PORT_3306_TCP).???

ENV

Dockerfile參考 之 ENV指令

為了讓軟件更便于運(yùn)行,你可以使用ENV來修改環(huán)境變量將軟件安裝目錄加到PATH。例如:ENV PATH /usr/local/nginx/bin:$PATH將使 CMD [“nginx”] 可以工作。

ENV指令也可用于給要容器化的服務(wù)所需的環(huán)境變量,比如Postgre的PGDATA。

最后,ENV也可用于指定通用版本號(hào),這樣版本易于維護(hù),如下實(shí)例所示:

ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH

和程序中的常量變量類似(和硬編碼值相反),這種方法讓你可以修改一個(gè)單獨(dú)的ENV指令在容器中自動(dòng)更新容器中的軟件版本。

ADD or COPY

Dockerfile參考之 ADD指令
Dockerfile參考之 COPY指令

盡管ADDCOPY指令功能相似,一般而言,最好使用COPY。是因?yàn)樗?code>ADD更透明。COPY只支持最基本的從本地復(fù)制文件到容器中,而ADD有更多功能(比如本地tar解壓和遠(yuǎn)程URL支持)并不是即刻課件的。因此,用ADD最好的方式是本地tar文件自動(dòng)提取到鏡像,比如:ADD rootfs.tar.xz /

如果你有多個(gè)Dockerfile步驟在你的上下文使用不同的文件,單獨(dú)COPY他們,而不是一次復(fù)制所有。這將確保每一步的構(gòu)建緩存(強(qiáng)制這一步重新運(yùn)行)只有當(dāng)它特定的依賴文件變化時(shí)失效。

例如:

COPY requirements.txt /tmp/
RUN pip install --requirement /tmp/requirements.txt
COPY . /tmp/

結(jié)論就是如果把COPY . /tmp/放在RUN之前失效緩存更少。

因?yàn)殓R像大小很重要,使用ADD來獲取遠(yuǎn)程URLs是強(qiáng)烈反對(duì)的;你應(yīng)該使用curlwget替代。這種方式你可以在解壓后不需要時(shí)刪除這些文件并且你不會(huì)在你的鏡像增加額外一層。例如,你應(yīng)該避免這么做:

ADD http://example.com/big.tar.xz /usr/src/things/
RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things
RUN make -C /usr/src/things all

并且以此種方式替代:

RUN mkdir -p /usr/src/things \
    && curl -SL http://example.com/big.tar.xz \
    | tar -xJC /usr/src/things \
    && make -C /usr/src/things all

對(duì)于不需要ADD tar自動(dòng)提取功能的其他項(xiàng)目(文件,目錄),應(yīng)始終使用COPY。

ENTRYPOINT

Dockerfile參考 之 ENTRYPOINT指令

使用ENTRYPOINT最好的方式是設(shè)置鏡像主命令,允許鏡像把它作為命令運(yùn)行(然后使用CMD作為默認(rèn)標(biāo)識(shí))。

我們從一個(gè)命令行工具s3cmd鏡像的例子開始:

ENTRYPOINT ["s3cmd"]
CMD ["--help"]

現(xiàn)在可以像這樣運(yùn)行鏡像來顯示命令的幫助:

$ docker run s3cmd

或者使用正確的參數(shù)來執(zhí)行一個(gè)命令:

$ docker run s3cmd ls s3://mybucket

這樣有用,因?yàn)殓R像名稱可以復(fù)用為二進(jìn)制文件的引用,如上面命令所示。

ENTRYPOINT指令也可以與輔助腳本組合使用,允許其以類似于上述命令的方式運(yùn)行,即使啟動(dòng)工具可能需要多于一個(gè)步驟。

例如,Postgres官方鏡像 使用以下腳本作為它的 ENTRYPOINT:

#!/bin/bash
set -e

if [ "$1" = 'postgres' ]; then
    chown -R postgres "$PGDATA"

    if [ -z "$(ls -A "$PGDATA")" ]; then
        gosu postgres initdb
    fi

    exec gosu postgres "$@"
fi

exec "$@"

注:這個(gè)腳本使用exec Bash命令 以便最終運(yùn)行的應(yīng)用程序成為容器PID 1。這樣做允許應(yīng)用程序接受發(fā)送給容器的Unix信號(hào)。查看ENTRYPOINT幫助獲取更多細(xì)節(jié)。

幫助腳本被拷貝到容器并且當(dāng)容器啟動(dòng)時(shí)通過ENTRYPOINT運(yùn)行。

COPY ./docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]

此腳本允許用戶以多種方式與Postgres進(jìn)行交互。

它可以簡單的啟動(dòng)Postgres:

$ docker run postgres

或者,可以運(yùn)行Postgres并且傳遞參數(shù)給服務(wù)器:

$ docker run postgres postgres --help

最后,它也可以被用于啟動(dòng)一個(gè)完全不同的工具,比如Bash:

$ docker run --rm -it postgres bash

VOLUME

Dockerfile參考 之 VOLUME指令

VOLUME指令應(yīng)該用于暴露任意數(shù)據(jù)庫存儲(chǔ)區(qū),配置存儲(chǔ),或者docker容器創(chuàng)建的文件/目錄等。強(qiáng)烈建議您將VOLUME用于鏡像的任何可變和/或用戶可維護(hù)的部分。

USER

Dockerfile參考 之 USER指令

如果服務(wù)可以沒有權(quán)限運(yùn)行,使用USER變?yōu)橐粋€(gè)非root用戶。像如下命令一樣開始在Dockerfile中創(chuàng)建用戶和組:

RUN groupadd -r postgres && useradd --no-log-init -r -g postgres postgres

注:??? (Users and groups in an image get a non-deterministic UID/GID in that the “next” UID/GID gets assigned regardless of image rebuilds. )???所以,如果很重要的話,你需要顯式指定UID/GID。

注:由于Go存檔/ tar包處理稀疏文件中的一個(gè)未解決的bug, 在docker容器里創(chuàng)建一個(gè)UID足夠大的用戶會(huì)在容器層中將/var/log/faillog寫滿NUL (\0)而導(dǎo)致磁盤耗盡。傳--no-log--init標(biāo)記來創(chuàng)建用戶可以繞開這個(gè)問題。Debian/Ubuntu的adduser包不支持--no-log-init標(biāo)記所以應(yīng)該避免使用。

你應(yīng)該避免安裝和使用sudo,因?yàn)樗豢深A(yù)知的TTY和信號(hào)轉(zhuǎn)發(fā)行為帶來的問題比解決的問題多。如果你確實(shí)需要類似sudo的功能(例如:以root用戶初始化但是以非root用戶運(yùn)行),你可以使用"gosu"。

最后,減少你的層和復(fù)雜性,避免切換用戶(Lastly, to reduce layers and complexity, avoid switching USER back and forth frequently.)。

WORKDIR

Dockerfile參考之 WORKDIR

為了清晰可靠,你應(yīng)該在使用WORDDIR時(shí)應(yīng)該一直使用絕對(duì)路徑。你也應(yīng)該使用WORKDIR而不是使用像RUN cd .. && do-something這樣難以閱讀、調(diào)錯(cuò)和維護(hù)的增量指令。

ONBUILD

Dockerfile參考 之 ONBUILD指令

ONBUILD命令在當(dāng)前Dockerfile構(gòu)建完成之后執(zhí)行。ONBUILD會(huì)在任意一個(gè)從當(dāng)前鏡像派生的子鏡像執(zhí)行。可以把ONBUOLD命令想象成為一個(gè)父級(jí)Dockerfile賦予子Dockerfile的指令。

Docker構(gòu)建在子Dockerfile中的任何命令之前執(zhí)行ONBUILD命令。

ONBUILD is useful for images that are going to be built FROM a given image. For example, you would use ONBUILD for a language stack image that builds arbitrary user software written in that language within the Dockerfile, as you can see in Ruby’s ONBUILD variants.

Images built from ONBUILD should get a separate tag, for example: ruby:1.9-onbuild or ruby:2.0-onbuild.

當(dāng)在ONBUILD中使用ADD或者COPY時(shí)要小心。如果新構(gòu)建的上下文丟失了增加的資源,"onbuild"的鏡像將會(huì)嚴(yán)重失敗。如上所述,添加單獨(dú)的標(biāo)簽,允許Dockerfile的作者自己選擇有助于緩解這種情況。

官方倉庫實(shí)例

這些官方倉庫有典型的示范(These Official Repositories have exemplary Dockerfiles):

其他資源

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

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

  • docker基本概念 1. Image Definition 鏡像 Image 就是一堆只讀層 read-only...
    慢清塵閱讀 8,789評(píng)論 1 21
  • Docker — 云時(shí)代的程序分發(fā)方式 要說最近一年云計(jì)算業(yè)界有什么大事件?Google Compute Engi...
    ahohoho閱讀 15,564評(píng)論 15 147
  • 轉(zhuǎn)載自 http://blog.opskumu.com/docker.html 一、Docker 簡介 Docke...
    極客圈閱讀 10,520評(píng)論 0 120
  • 五、Docker 端口映射 無論如何,這些 ip 是基于本地系統(tǒng)的并且容器的端口非本地主機(jī)是訪問不到的。此外,除了...
    R_X閱讀 1,774評(píng)論 0 7
  • 首先在這里要說一下,我是一個(gè),不夠合格的媽媽,每天沒有及時(shí),給孩子寫感賞日記。 昨天兒子也是一天的好習(xí)慣,珍惜每一...
    玲燕閱讀 239評(píng)論 2 3