【轉(zhuǎn)一個朋友的dockerfile筆記

基于Dockerfile構(gòu)建鏡像

1. Dockerfile:source code for building Docker file

Docker可以通過從Dockerfile文件中讀取指令自動構(gòu)建鏡像

Dockerfile是一個文本文檔贞绳,它包含用戶可以在命令行上調(diào)用的所有命令來組裝映像

使用Docker build命令浇辜,用戶可以通過逐條執(zhí)行幾條命令自動創(chuàng)建鏡像

2. Dockerfile語法格式:

首行必須是以#開頭的行

不區(qū)分大小寫听哭,但約定俗成的慣例都是使用全部大寫厘灼。

Docker按順序在Dockerfile中運(yùn)行指令

第一個指令必須是“FROM”这吻,以便指定要從其中構(gòu)建的基本映像

3. 環(huán)境變量(使用ENV語句聲明)也可以在某些指令中使用,作為由Dockerfile解釋的變量巢墅。

在Dockerfile中讲冠,環(huán)境變量可以是$variable_name或${variable_name}

${variable_name}語法還支持一些標(biāo)準(zhǔn)bash修飾符

${variable:-word}表示,如果設(shè)置了變量俭正,那么結(jié)果將是該值胁出。如果變量未設(shè)置,則結(jié)果為word段审。

${variable:+word}表示如果設(shè)置了變量全蝶,那么結(jié)果將是word,否則結(jié)果將是空字符串寺枉。

4. .dockerignore文件

在工作目錄中若有子目錄抑淫,而子目錄中有些文件不想引用,就可以用.dockerignore來隱藏文件姥闪。

.dockerignore文件內(nèi)指明不引用的文件始苇。

5. FROM

用來指定基礎(chǔ)鏡像,若指定的鏡像不存在筐喳,會先到Docker Hub中下載

語法:

FROM <image> [AS <name>] #[AS <name>]:別名

FROM <image>[:<tag>] [AS <name>] #tag:標(biāo)簽

FROM <image> [@<digest>] [AS <name>] #digest:哈希碼

6. docker build命令

Build an image from a Dockerfile

Options

-t, --tag list Name and optionally a tag in the 'name:tag' format

-m, --memory bytes Memory limit

-c, --cpu-shares int CPU shares (relative weight)

7. LABEL

添加鏡像文件的元數(shù)據(jù),可出現(xiàn)多次催式,強(qiáng)烈建議只使用一條函喉,因為一條指令會添加一個層,層數(shù)越多荣月,運(yùn)行效率越低管呵。

語法格式:

LABEL <key>=<value> <key>=<value> <key>=<value>... #可指定多個LABEL

LABEL <key> <value> #只可指定一個LABEL,第一個空格后的內(nèi)容都會被當(dāng)作value

示例

只修改一個鏡像的FROM哺窄、LABEL

創(chuàng)建工作目錄image

[root@docker ~]# mkdir image[root@docker ~]# cd image

編輯Dockerfile文件捐下,添加以下內(nèi)容:

[root@docker image]# vim Dockerfile#Test Image BuildFROM alpineLABEL maintainer="lixinkuan <lixinkuan@163.com>"

制作鏡像:

[root@docker image]# docker build .Sending build context to Docker daemon? 2.048kBStep 1/2 : FROM alpine ---> 3fd9065eaf02Step 2/2 : LABEL maintainer="lixinkuan " --->Runningine1ce9acfc453Removing intermediate container e1ce9acfc453 ---> 1deb17a1af32Successfully built 1deb17a1af32

查看:REPOSITORY和TAG都為空的即為新創(chuàng)建的鏡像文件

[root@docker image]#dockerimagelsREPOSITORYTAGIMAGEIDCREATEDSIZE? ? ? ? ? ? ? ? ? ? ? ? ? ? 1deb17a1af325minutesago4.15MBnginxlatestcd5239a0906a3weeksago109MBbusyboxlatest8c811b4aec355weeksago1.15MBhttpd2.4fb2f3851a9718weeksago178MBalpinelatest3fd9065eaf025monthsago4.15MB

創(chuàng)建docker鏡像時,可使用-t后跟 'name:tag' 指定TAG

也可用如下命令添加標(biāo)簽:

[root@docker image]# docker image tag 1deb17a1af32 alpine:lxk[root@docker image]# docker imagesREPOSITORY? ? ? ? ? ? ? ? ? TAG? ? ? ? ? ? ? ? IMAGE ID? ? ? ? ? ? CREATED? ? ? ? ? ? SIZEalpine? ? ? ? ? ? ? ? ? ? ? lxk1deb17a1af325minutes ago4.41MB

8. COPY

用于從Docker宿主機(jī)復(fù)制文件至創(chuàng)建的新映像文件

語法:

COPY <src> ... <dest>

COPY ["",... ""]

<src>:要復(fù)制的源文件或目錄萌业,支持使用通配符

<dest>:目標(biāo)路徑坷襟,即正在創(chuàng)建的image的文件系統(tǒng)路徑;建議為<dest>使用絕對路徑生年,否則婴程,COPY指定則以WORKDIR為其起始路徑

注意:在路徑中有空白字符時,通常使用第二種格式

文件復(fù)制準(zhǔn)則:

<src>必須是build上下文中的路徑抱婉,不能是其父目錄中的文件

如果<src>是目錄排抬,則其內(nèi)部文件或子目錄會被遞歸復(fù)制,但<src>目錄自身不會被復(fù)制

如果指定了多個<src>授段,或在<src>中使用了通配符,則<dest>必須是一個目錄番甩,且必須以/結(jié)尾

如果<dest>事先不存在侵贵,它將會被自動創(chuàng)建,這包括其父目錄路徑

示例:復(fù)制單個文件

在image目錄下為index.html添加內(nèi)容:

[root@docker image]#? echo '<h1>hello,docker!</h1>' > index.html

編輯Dockerfile文件,添加語句:

[root@docker image]# vim Dockerfile #Test Image BuildFROM alpineLABEL maintainer="lixinkuan <lixinkuan@163.com>"COPY index.html/var/www/html/

用alpine啟動一個容器,查看是否有/var/www/html目錄

[root@docker image]# docker run -it --name a1 alpine/# ps aux PID? USER? ? TIME? COMMAND1root0:00/bin/sh7root0:00ps aux/# ls /var/www/htmlls: /var/www/html: No such fileordirectory

制作鏡像

[root@docker image]# docker build -t cpindex:latest .Sending build context to Docker daemon? 3.072kBStep 1/3 : FROM alpine ---> 3fd9065eaf02Step 2/3 : LABEL maintainer="lixinkuan " --->Runningin9d96e0655a82Removing intermediate container 9d96e0655a82 ---> 56049399eb78Step 3/3 : COPY index.html /var/www/html/ ---> bace8e55c97bSuccessfully built bace8e55c97bSuccessfully tagged cpindex:latest

查看制作的鏡像:

[root@docker image]# docker image lsREPOSITORY? ? ? ? ? TAG? ? ? ? ? ? ? ? IMAGE ID? ? ? ? ? ? CREATED? ? ? ? ? ? SIZEcpindex? ? ? ? ? ? latest? ? ? ? ? ? ? bace8e55c97b52seconds ago4.15MB

以制作的鏡像啟動一個容器,并查看文件是否存在

[root@docker image]# docker run --name copyfile -it --rm cpindex:latest/# ls /var/www/htmlindex.html/# cat /var/www/html/index.html

hello,docker!

示例:復(fù)制目錄下的多個文件至目錄

復(fù)制一個目錄至/root/image下

[root@docker image]# cp -r /etc/default/ ./ [root@docker image]# lsdefaultDockerfile? index.html[root@docker image]# ls default/grub? kibana? nss? useradd

修改Dockerfile文件為以下內(nèi)容:

#Test Image BuildFROM alpineLABEL maintainer="lixinkuan <lixinkuan@163.com>"COPYdefault/tmp/

制作鏡像:

[root@docker image]# docker build -t cpdir:latest ./Sending build context to Docker daemon? 9.216kBStep 1/3 : FROM alpine ---> 3fd9065eaf02Step 2/3 : LABEL maintainer="lixinkuan " ---> Using cache ---> 56049399eb78Step 3/3 : COPY default /tmp/ ---> 18cacf50aef9Successfully built 18cacf50aef9Successfully tagged cpdir:latest

查看并驗證:

[root@docker image]# docker image lsREPOSITORY? ? ? ? ? TAG? ? ? ? ? ? ? ? IMAGE ID? ? ? ? ? ? CREATED? ? ? ? ? ? SIZEcpdir? ? ? ? ? ? ? latest18cacf50aef924seconds ago4.15MB[root@docker image]# docker run --name cpdir -it --rm cpdir:latestWARNING: IPv4 forwardingisdisabled. Networking willnotwork./# ls /tmpgrub? ? kibana? nss? ? ? useradd

示例:使用數(shù)組格式創(chuàng)建配置文件

修改配置文件如下:

#Test Image BuildFROMalpineLABEL maintainer="lixinkuan <lixinkuan@163.com>"COPY ["default","/tmp/default"]

創(chuàng)建鏡像并驗證

[root@docker image]# docker build -t cp:latest ./Sending build context to Docker daemon9.216kBStep1/3: FROM alpine --->3fd9065eaf02Step2/3: LABEL maintainer="lixinkuan <lixinkuan@163.com>"---> Using cache --->56049399eb78Step3/3: COPY ["default","/tmp/default"] ---> bf0799319943Successfully built bf0799319943Successfully tagged cp:latest[root@docker image]# docker run --name cp -it --rm cp:latest/# cd /tmp/tmp# lsdefault/tmp # cd default//tmp/default# lsgrub? ? kibana? nss? ? ? useradd/tmp/default# exit

9. ADD

ADD類似于COPY指令,ADD支持tar文件和URL路徑

Syntax

ADD <src>...<dest>

ADD ["<src>"..."<dest>"]

操作準(zhǔn)則:

同COPY指令

如果<src>為URL且<dest>不以/結(jié)尾缘薛,則<src>指定的文件將被下載并直接被創(chuàng)建為<dest>窍育;如果<dest>以/結(jié)尾,則文件名URL指定的文件將被直接下載并保存為<dest>/<filename>

如果<src>是一個本地系統(tǒng)上的壓縮格式的tar文件宴胧,它將被展開為一個目錄漱抓,其行為類似于“tar -x”命令;然而恕齐,通過URL獲取到的tar文件將不會自動展開乞娄;

如果<src>有多個,或其間接或直接使用了通配符显歧,則<dest>必須是一個以/結(jié)尾的目錄路徑仪或;如果<dest>不以/結(jié)尾,則其被視作一個普通文件士骤,<src>的內(nèi)容將被直接寫入到<dest>

示例:下載一個文件至鏡像文件

在工作目錄下編寫Dockerfile文件(使用URL時,用ftp協(xié)議失敗)

#Test Image BuildFROM alpineLABEL maintainer="lixinkuan <lixinkuan@163.com>"COPY ["default","/tmp/default"]ADDhttps://mirrors.aliyun.com/centos/7.5.1804/os/x86_64/Packages/zsh-5.0.2-28.el7.x86_64.rpm /tmp/

創(chuàng)建鏡像文件

[root@docker image]# docker build -t zsh:latest ./Sending build context to Docker daemon? 9.216kBStep 1/4 : FROM alpine ---> 3fd9065eaf02Step 2/4 : LABEL maintainer="lixinkuan " ---> Using cache ---> 56049399eb78Step 3/4 : COPY ["default","/tmp/default"] ---> Using cache ---> bf0799319943Step 4/4 : ADD https://mirrors.aliyun.com/centos/7.5.1804/os/x86_64/Packages/zsh-5.0.2-28.el7.x86_64.rpm /tmp/Downloading [==================================================>]? 2.494MB/2.494MB ---> 538ab9c6983eSuccessfully built 538ab9c6983eSuccessfully tagged zsh:latest

創(chuàng)建容器并查看

[root@docker image]# docker run -it --name zsh --rm zsh:latest/# cd /tmp/tmp# lsdefaultzsh-5.0.2-28.el7.x86_64.rpm

示例:ADD一個壓縮包至鏡像文件

復(fù)制壓縮包至工作目錄,并在工作目錄編輯Dockerfile文件

[root@docker image]# cp /root/wordpress-4.8.1-zh_CN.tar.gz ./[root@docker image]# vim Dockerfile #Test Image BuildFROM alpineLABEL maintainer="lixinkuan <lixinkuan@163.com>"ADD wordpress-4.8.1-zh_CN.tar.gz/tmp/

制作鏡像文件

[root@docker image]# docker build -t wordpress:latest ./Sending build context to Docker daemon? 8.652MBStep 1/3 : FROM alpine ---> 3fd9065eaf02Step 2/3 : LABEL maintainer="lixinkuan " ---> Using cache ---> 56049399eb78Step 3/3 : ADD wordpress-4.8.1-zh_CN.tar.gz /tmp/ ---> 58c32caba31eSuccessfully built 58c32caba31eSuccessfully tagged wordpress:latest

創(chuàng)建容器并查看

[root@docker image]# docker run --name a1 -it --rm wordpress:latest/# ls /tmp/wordpress/index.php? ? ? ? ? ? wp-admin? ? ? ? ? ? ? wp-content? ? ? ? ? ? wp-load.php? ? ? ? ? wp-signup.phplicense.txt? ? ? ? ? wp-blog-header.php? ? wp-cron.php? ? ? ? ? wp-login.php? ? ? ? ? wp-trackback.phpreadme.html? ? ? ? ? wp-comments-post.php? wp-includes? ? ? ? ? wp-mail.php? ? ? ? ? xmlrpc.phpwp-activate.php? ? ? wp-config-sample.php? wp-links-opml.php? ? wp-settings.php/# exit

10. WORKDIR

用于為Dockerfile中所有的RUN范删、CMD、ENTRYPOINT拷肌、COPY和ADD指定設(shè)定工作目錄

Syntax

WORKDIR

在Dockerfile文件中到旦,WORKDIR指令可出現(xiàn)多次旨巷,其路徑也可以為相對路徑,不過添忘,其是相對此前一個WORKDIR指令指定的路徑

另外采呐,WORKDIR也可調(diào)用由ENV指定定義的變量

例如:

WORKDIR /var/log

WORKDIR $STATEPATH

示例

在工作目錄下編輯Dockerfile文件:

#Test Image BuildFROMalpineLABEL maintainer="lixinkuan <lixinkuan@163.com>"WORKDIR /tmpADD wordpress-4.8.1-zh_CN.tar.gz src

創(chuàng)建鏡像:

[root@docker image]# docker build -t wordpress:v0.1 ./Sending build context to Docker daemon? 8.652MBStep 1/4 : FROM alpine ---> 3fd9065eaf02Step 2/4 : LABEL maintainer="lixinkuan " ---> Using cache ---> 56049399eb78Step 3/4 : WORKDIR /tmpRemoving intermediate container 08bef4630472 ---> 54f97eda6b49Step 4/4 : ADD wordpress-4.8.1-zh_CN.tar.gz src ---> 0811aff4fa7dSuccessfully built 0811aff4fa7dSuccessfully tagged wordpress:v0.1

創(chuàng)建容器后,默認(rèn)工作路徑就是WORKDIR所指的目錄/tmp

[root@docker image]# docker run --name a1 -it --rm wordpress:v0.1/tmp# lssrc/tmp # ls src/wordpress/tmp # ls src/wordpress/index.php? ? ? ? ? ? wp-admin? ? ? ? ? ? ? wp-content? ? ? ? ? ? wp-load.php? ? ? ? ? wp-signup.phplicense.txt? ? ? ? ? wp-blog-header.php? ? wp-cron.php? ? ? ? ? wp-login.php? ? ? ? ? wp-trackback.phpreadme.html? ? ? ? ? wp-comments-post.php? wp-includes? ? ? ? ? wp-mail.php? ? ? ? ? xmlrpc.phpwp-activate.php? ? ? wp-config-sample.php? wp-links-opml.php? ? wp-settings.php/tmp# exit

11. VOLUME

用于在image中創(chuàng)建一個掛載點目錄,以掛載Docker host上的卷或其它容器上的卷

Syntax

VOLUME <mountpoint>

VOLUME ["<mountpoint>"]

如果掛載點目錄路徑下此前有文件存在昔汉,docker run命令會把原文件隱藏.

如果此前掛載點不存在,docker 會自動創(chuàng)建該目錄.

掛載點下文件變化都可以在宿主機(jī)查看

查看方法:

docker volume ls #查看宿主機(jī)所有掛載的目錄

docker inspect -f {{.Mounts}} a1 #通過查看指定容器信息查看掛載點路徑

示例

在需要掛載的目錄下提供文件

[root@docker image]# echo "hello,test dockerfile" > /var/www/html/index.html

在工作目錄下編輯Dockerfile文件

#Test Image BuildFROM alpineLABEL maintainer="lixinkuan "#WORKDIR /tmp#ADD wordpress-4.8.1-zh_CN.tar.gz src/VOLUME /var/www/html

創(chuàng)建鏡像文件

[root@docker image]# docker build -t file:v0.1 ./Sending build context to Docker daemon? 8.651MBStep 1/3 : FROM alpine ---> 3fd9065eaf02Step 2/3 : LABEL maintainer="lixinkuan " ---> Using cache ---> 56049399eb78Step 3/3 : VOLUME /var/www/html ---> [Warning] IPv4 forwarding is disabled. Networking will not work. --->Runninginda84d9f4ca1eRemoving intermediate container da84d9f4ca1e ---> b26c2d7ea64cSuccessfully built b26c2d7ea64cSuccessfully tagged file:v0.1

創(chuàng)建容器:

[root@docker image]# docker run --name a1 -it --rm file/# cd /var/www/html//var/www/html# echo abc > index.html/var/www/html# cat index.htmlabc

查看宿主機(jī)上的文件:

[root@docker ~]# docker volume ls? ? ? #查看本機(jī)所有容器掛載的目錄DRIVER? ? ? ? ? ? ? VOLUME NAMElocal6368d0a0b462f5329a4b3bdcb7030e0d6f724bf9f801386f87fdac7660cd1735[root@docker ~]# docker inspect -f {{.Mounts}} a1? ? ? #查看a1容器的掛載文件路徑[{volume6368d0a0b462f5329a4b3bdcb7030e0d6f724bf9f801386f87fdac7660cd1735 /var/lib/docker/volumes/6368d0a0b462f5329a4b3bdcb7030e0d6f724bf9f801386f87fdac7660cd1735/_data /var/www/htmllocaltrue }][root@docker ~]# cd /var/lib/docker/volumes/6368d0a0b462f5329a4b3bdcb7030e0d6f724bf9f801386f87fdac7660cd1735/_data/[root@docker _data]# lsindex.html[root@docker _data]# cat index.html abc#該內(nèi)容與容器中index.html內(nèi)容一樣

12. EXPOSE

用于為容器打開指定要監(jiān)聽的端口以實現(xiàn)與外部通信

實質(zhì)是通過iptables添加DNAT規(guī)則,把外網(wǎng)主機(jī)訪問宿主機(jī)的請求轉(zhuǎn)發(fā)至指定容器.

需要宿主機(jī)開啟核心轉(zhuǎn)發(fā)功能.

可通過iptables -t nat -nvL查看添加的規(guī)則.

通過Dockerfile制作鏡像時若不用EXPOSE指定要暴露的端口,可用以下兩種方法暴露端口:

容器運(yùn)行后,自行添加DNAT規(guī)則實現(xiàn)端口暴露.

docker run時使用-p選項指定暴露的端口.

docker run時使用-P選項暴露所有容器內(nèi)監(jiān)聽的端口.

docker run時,使用-p選項指定的優(yōu)先級要高于Dockerfile制作鏡像時指定要暴露的端口.

Syntax

EXPOSE [/] [[/] ...]

<protocol>用于指定傳輸層協(xié)議懈万,可為tcp或udp二者之一,默認(rèn)為TCP協(xié)議

EXPOSE指令可一次指定多個端口靶病,例如

EXPOSE 11211/udp 11211/tcp

不用EXPOSE時,宿主機(jī)內(nèi)容器若要被外網(wǎng)主機(jī)訪問的情況

下載redis:4-alpine

[root@docker ~]# docker pull redis:4-alpine4-alpine: Pulling from library/redisff3a5c916c92: Pull complete 5fbab8756652: Pull complete ff7d4663b06c: Pull complete 0b5cf71258c2: Pull complete 54bbb9bad8ba: Pull complete 8fe9a341d124: Pull complete Digest: sha256:686ab026fae07b3b99a8e74210c361714a80311ecc55f23b349ae930ed2f5a95Status: Downloaded newer image for redis:4-alpine[root@docker ~]# docker imagesREPOSITORY? ? ? ? ? TAG? ? ? ? ? ? ? ? IMAGE ID? ? ? ? ? ? CREATED? ? ? ? ? ? SIZEredis? ? ? ? ? ? ? 4-alpine? ? ? ? ? ? caaeda72bf8f? ? ? ? 12 days ago? ? ? ? 27.8MB

運(yùn)行redis鏡像

[root@docker ~]# docker run --name db1 -d --rm -p 6379 redis:4-alpine881d5648c7388449a39c67024206c5710b1538f4c941039fa3905bb601b09699[root@docker ~]# docker exec -it db1 ifconfigeth0Linkencap:Ethernet? HWaddr02:42:AC:11:00:02inetaddr:172.17.0.2Bcast:172.17.255.255Mask:255.255.0.0UP BROADCAST RUNNING MULTICASTMTU:1500Metric:1RXpackets:8errors:0dropped:0overruns:0frame:0TXpackets:0errors:0dropped:0overruns:0carrier:0collisions:0txqueuelen:0RXbytes:648(648.0B)? TXbytes:0(0.0B)lo? ? ? ? Linkencap:Local Loopback? ? ? ? ? ? inetaddr:127.0.0.1Mask:255.0.0.0UP LOOPBACK RUNNINGMTU:65536Metric:1RXpackets:0errors:0dropped:0overruns:0frame:0TXpackets:0errors:0dropped:0overruns:0carrier:0collisions:0txqueuelen:1RXbytes:0(0.0B)? TXbytes:0(0.0B)[root@docker ~]# docker exec -it db1 /bin/sh/data# netstat -tnlActive Internet connections (only servers)Proto Recv-Q Send-Q Local Address? ? ? ? ? Foreign Address? ? ? ? State? ? ? tcp000.0.0.0:63790.0.0.0:*LISTEN? ? ? tcp00:::6379:::*LISTEN? ? ? /data#

查看映射的端口

[root@docker ~]# docker container port db16379/tcp ->0.0.0.0:32768

外網(wǎng)主機(jī)訪問本地宿主機(jī)容器

[root@node1 tmp]#redis-cli-h192.168.1.106-p32768192.168.1.106:32768>select1OK192.168.1.106:32768[1]>setmykeyhiOK192.168.1.106:32768[1]>keys*1) "mykey"192.168.1.106:32768[1]>exit

查看本地容器內(nèi)是否有數(shù)據(jù)

[root@docker ~]# docker exec -it db1 /bin/sh/data# redis-cli 127.0.0.1:6379>select1OK127.0.0.1:6379[1]>keys *1)"mykey"127.0.0.1:6379[1]>exit/data# exit

開啟自動端口暴露

在工作目錄下編寫Dockerfile文件

#Test Image BuildFROMredis:4-alpineLABEL maintainer="lixinkuan <lixinkuan@163.com>"EXPOSE6379/tcp26379/tcp

制作鏡像文件

[root@docker images]# docker build -t expose_db:latest ./Sending build context to Docker daemon? 8.645MBStep 1/3 : FROM redis:4-alpine ---> caaeda72bf8fStep 2/3 : LABEL maintainer="lixinkuan " --->Runninginf43f9e43b27aRemoving intermediate container f43f9e43b27a ---> e98bb940a8a2Step 3/3 : EXPOSE 6379/tcp 26379/tcp --->Runninginf53a9be4f661Removing intermediate container f53a9be4f661 ---> ea40417716a0Successfully built ea40417716a0Successfully tagged expose_db:latest

運(yùn)行并查看效果

[root@docker images]# docker run --name a1 -d --rm -P redis_expose:latestad1225390f8f246cc5bde693ea99b120ee3a2f474416603b0797cda94787cc03[root@docker images]# docker container port a16379/tcp ->0.0.0.0:32772

換一臺主機(jī)連接數(shù)據(jù)庫查看

[root@node1 ~]#redis-cli-h192.168.200.45-p32772192.168.200.45:32772>select1OK192.168.200.45:32772[1]>keys*(emptylistorset)192.168.200.45:32772[1]>settestdockerfileOK192.168.200.45:32772[1]>keys*1) "test"192.168.200.45:32772[1]>gettest"dockerfile"

在a1容器上查看:

[root@docker images]# docker exec -it a1 /bin/sh/data# redis-cli 127.0.0.1:6379>select1OK127.0.0.1:6379[1]>get test"dockerfile"

示例:驗證Dockerfile與docker run時使用-p的優(yōu)先級

編輯Dockerfile

[root@docker images]# cat Dockerfile #Test Image BuildFROM redis:4-alpineLABEL maintainer="lixinkuan <lixinkuan@163.com>"EXPOSE6379/tcp80/tcp

制作鏡像:

[root@docker images]# docker build -t expose_port .Sending build context to Docker daemon? 8.645MBStep 1/3 : FROM redis:4-alpine ---> caaeda72bf8fStep 2/3 : LABEL maintainer="lixinkuan " ---> Using cache ---> 188775dd2e3eStep 3/3 : EXPOSE 6379/tcp 80/tcp --->Runninginb0f5bfbaafaeRemoving intermediate container b0f5bfbaafae ---> 165e707c2b23Successfully built 165e707c2b23Successfully tagged expose_port:latest

運(yùn)行容器時指定要暴露的端口:

[root@docker images]# docker run --name db1 -d --rm -p 25 expose_porte00f3e304103954c00651d44b00ae9961608900e0d5688eee4c08f140340f480[root@docker images]# docker container port db125/tcp ->0.0.0.0:32779

查看防火墻規(guī)則,只有暴露25端口的DNAT規(guī)則

[root@docker images]# iptables -t nat -nvLChain DOCKER (2 references) pkts bytes target? ? prot optinoutsourcedestination? ? ? ? ? ? 0? ? 0 RETURN? ? all? --? docker0 *? ? ? 0.0.0.0/0? ? ? ? ? ? 0.0.0.0/0? ? ? ? ? ? ? 0? ? 0 DNAT? ? ? tcp? --? !docker0 *? ? ? 0.0.0.0/0? ? ? ? ? ? 0.0.0.0/0? ? ? ? ? ? tcp dpt:32779 to:172.17.0.2:25

13. ENV

用于為鏡像定義所需的環(huán)境變量会通,并可被Dockerfile文件中位于其后的其它指令(如ENV、ADD娄周、COPY等)所調(diào)用

調(diào)用格式為$variable_name或${variable_name}

Syntax

ENV <key> <value>

ENV <key>=<value> ...

第一種格式中涕侈,<key>之后的所有內(nèi)容均會被視作其<value>的組成部分,因此煤辨,一次只能設(shè)置一個變量

第二種格式可用一次設(shè)置多個變量裳涛,每個變量為一個"<key>=<value>"的鍵值對,如果<value>中包含空格众辨,可以以反斜線()進(jìn)行轉(zhuǎn)義端三,也可通過對<value>加引號進(jìn)行標(biāo)識;另外鹃彻,反斜線也可用于續(xù)行

定義多個變量時郊闯,建議使用第二種方式,以便在同一層中完成所有功能

示例

編輯Dockerfile文件

FROMbusyboxLABEL maintainer="lixinkuan <lixinkuan@163.com>"ENV DOCROOT="/data/web/html/"COPY index.html${DOCROOT}VOLUME${DOCROOT}

提供index及所需掛載目錄:

[root@docker bbox]# mkdir -pv /data/web/htmlmkdir: created directory ‘/data’mkdir: created directory ‘/data/web’mkdir: created directory ‘/data/web/html’[root@docker bbox]# echo hello Docker > index.html[root@docker bbox]# cat index.htmlhello Docker

制作鏡像:

[root@docker bbox]# docker build -t bbox_file:latest ./Sending build context to Docker daemon? 3.072kBStep 1/5 : FROM busyboxlatest: Pulling from library/busybox07a152489297: Pull complete Digest: sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47Status: Downloaded newer image for busybox:latest ---> 8c811b4aec35Step 2/5 : LABEL maintainer="lixinkuan " --->Runningin87a1f2c22ad6Removing intermediate container 87a1f2c22ad6 ---> 56f723d6220cStep 3/5 : ENV DOCROOT="/data/web/html/" --->Runningin21fd1fcb0474Removing intermediate container 21fd1fcb0474 ---> c095f8dd8418Step 4/5 : COPY index.html ${DOCROOT} --->ee77cd16629aStep 5/5 : VOLUME ${DOCROOT} --->Runningin00474fde8b85Removing intermediate container 00474fde8b85 ---> d51ea735fdd3Successfully built d51ea735fdd3Successfully tagged bbox_file:latest

運(yùn)行容器并查看

[root@docker bbox]# docker run --name a1 -it --rm bbox_file:latest/# ls /data/web/htmlindex.html/# cat /data/web/html/index.htmlhello Docker

另啟終端查看掛載的卷:

[root@docker ~]# docker volume lsDRIVER? ? ? ? ? ? ? VOLUME NAMElocal1dcd37d2c4f2e6a71e0b96a385714ff01cad5d578e396c9b012922e9993aecbflocalb2df5fcd0e1aa58c403d2e8f0ec880feb7dcb1a80a688697e76122adec55e789[root@docker ~]# docker inspect -f {{.Mounts}} a1[{volume1dcd37d2c4f2e6a71e0b96a385714ff01cad5d578e396c9b012922e9993aecbf /var/lib/docker/volumes/1dcd37d2c4f2e6a71e0b96a385714ff01cad5d578e396c9b012922e9993aecbf/_data /data/web/htmllocaltrue }]

14. CMD與RUN

CMD

用于定義鏡像啟動為容器時默認(rèn)運(yùn)行的應(yīng)用程序蛛株。

類似于RUN指令团赁,CMD指令也可用于運(yùn)行任何命令或應(yīng)用程序,不過谨履,二者的運(yùn)行時間點不同

RUN指令運(yùn)行于映像文件構(gòu)建過程中欢摄,而CMD指令運(yùn)行于基于Dockerfile構(gòu)建出的新映像文件啟動一個容器時

CMD指令的首要目的在于為啟動的容器指定默認(rèn)要運(yùn)行的程序,且其運(yùn)行結(jié)束后笋粟,容器也將終止怀挠;不過,CMD指定的命令其可以被docker run的命令行選項所覆蓋

在Dockerfile中可以存在多個CMD指令害捕,但僅最后一個會生效

Syntax

CMD <command>

CMD [“<executable>”, “<param1>”, “<param2>”]

CMD ["<param1>","<param2>"]

前兩種語法格式的意義同RUN

第三種則用于為ENTRYPOINT指令提供默認(rèn)參數(shù)

RUN

指定docker build過程中運(yùn)行的程序唆香。必須是鏡像中存在的命令。

Syntax

RUN <command>

RUN ["<executable>", "<param1>", "<param2>"]

第一種格式中吨艇,<command>通常是一個shell命令躬它,且以“/bin/sh -c”來運(yùn)行它,這意味著此進(jìn)程在容器中的PID不為1东涡,不能接收Unix信號冯吓,因此倘待,當(dāng)使用docker stop <container>命令停止容器時,此進(jìn)程接收不到SIGTERM信號组贺;

第二種語法格式中的參數(shù)是一個JSON格式的數(shù)組凸舵,其中<executable>為要運(yùn)行的命令,后面的<paramN>為傳遞給命令的選項或參數(shù)失尖;然而啊奄,此種格式指定的命令不會以“/bin/sh -c”來發(fā)起,因此常見的shell操作如變量替換以及通配符(?,*等)替換將不會進(jìn)行掀潮;不過菇夸,如果要運(yùn)行的命令依賴于此shell特性的話,可以將其替換為類似下面的格式仪吧。

示例:RUN ["/bin/bash", "-c", "<executable>", "<param1>"]

示例1:基于centos基礎(chǔ)鏡像創(chuàng)建一個運(yùn)行nginx的鏡像

編輯Dockerfile文件:

FROM centosLABEL maintainer="lixinkuan <lixinkuan@163.com>"COPYbase.repo epel.repo /etc/yum.repos.d/RUN yum -y install nginx \? ? ? ? && yum clean all \? ? ? ? && rm -rf /var/cache/yum

提供base.repo epel.repo文件:

[root@docker nginx]# wget lixinkuan.top/base.repo--2018-06-3011:29:08--http://lixinkuan.top/base.repoResolving lixinkuan.top (lixinkuan.top)...47.94.102.99Connecting to lixinkuan.top (lixinkuan.top)|47.94.102.99|:80... connected.HTTP request sent, awaiting response...200OKLength:630Savingto:‘base.repo’100%[=================================================================================>]630--.-K/sin0s2018-06-3011:29:08 (87.9MB/s) - ‘base.repo’ saved [630/630][root@docker nginx]# wget lixinkuan.top/epel.repo--2018-06-3011:29:16--http://lixinkuan.top/epel.repoResolving lixinkuan.top (lixinkuan.top)...47.94.102.99Connecting to lixinkuan.top (lixinkuan.top)|47.94.102.99|:80... connected.HTTP request sent, awaiting response...200OKLength:214Savingto:‘epel.repo’100%[=================================================================================>]214--.-K/sin0s2018-06-3011:29:16(44.2MB/s) - ‘epel.repo’ saved [214/214][root@docker nginx]# lsbase.repo? Dockerfile? epel.repo

創(chuàng)建鏡像:

[root@docker nginx]# docker build -t nginx:v0.1 ./Sending build context to Docker daemon? 4.608kBStep 1/4 : FROM centoslatest: Pulling from library/centos7dc0dca2b151: Pull complete Digest: sha256:b67d21dfe609ddacf404589e04631d90a342921e81c40aeaf3391f6717fa5322Status: Downloaded newer image for centos:latest ---> 49f7960eb7e4Step 2/4 : LABEL maintainer="lixinkuan " --->Runningin6b16128ed7caRemoving intermediate container 6b16128ed7ca ---> b6ef19a3311fStep 3/4 : COPY base.repo epel.repo /etc/yum.repos.d/ ---> e571c2837442Step 4/4 : RUN yum -y install nginx? ? && yum clean all? ? && rm -rf /var/cache/yum --->Runningin445372de8e8dLoaded plugins: fastestmirror, ovl.....執(zhí)行安裝過程省略...Cleaning repos: base epel extras updatesCleaning up everythingMaybe you want: rm -rf /var/cache/yum, to also free up space taken by orphaned data from disabled or removed reposCleaning up list of fastest mirrorsRemoving intermediate container 445372de8e8d ---> 5cf6e8e3517eSuccessfully built 5cf6e8e3517eSuccessfully tagged nginx:v0.1

創(chuàng)建容器并查看:

[root@docker nginx]#dockerrun--nameweb-itnginx:v0.1[root@5e7adf4282c1 /]#rpm-qnginxnginx-1.12.2-2.el7.x86_64#nginx已安裝[root@5e7adf4282c1 /]#

示例2:以busybox制作一個掛載本地/data/web/html目錄并自動運(yùn)行httpd的鏡像

在工作目錄編輯Dockerfile文件

FROM busyboxLABEL maintainer="lixinkuan <lixinkuan@163.com>"ENV DOCROOT="/data/web/html/"COPY index.html${DOCROOT}VOLUME${DOCROOT}CMD /bin/httpd-f-h${DOCROOT}

提供index.html并創(chuàng)建要掛載的目錄

[root@docker bbox]# echo hello Docker > index.html[root@docker bbox]# cat index.htmlhello Docker

創(chuàng)建鏡像文件:

[root@docker bbox]# docker build -t web:v0.1 ./Sending build context to Docker daemon? 3.072kBStep 1/6 : FROM busybox ---> 8c811b4aec35Step 2/6 : LABEL maintainer="lixinkuan " ---> Using cache ---> 56f723d6220cStep 3/6 : ENV DOCROOT="/data/web/html/" ---> Using cache ---> c095f8dd8418Step 4/6 : COPY index.html ${DOCROOT} ---> Using cache --->ee77cd16629aStep 5/6 : VOLUME ${DOCROOT} ---> Using cache ---> d51ea735fdd3Step 6/6 : CMD /bin/httpd -f -h ${DOCROOT} --->Runninginf2fa2b284306Removing intermediate container f2fa2b284306 ---> b8613217ad3cSuccessfully built b8613217ad3cSuccessfully tagged web:v0.1

以新創(chuàng)建的鏡像文件運(yùn)行容器并查看

[root@docker bbox]# docker run --name web -d --rm web:v0.17b71084ebd922728ebf21d22a4e5ff3462443761c82bc22c640764c6d4925b2a[root@docker bbox]# docker container inspect -f {{.Config.Cmd}} web[/bin/sh-c /bin/httpd -f -h ${DOCROOT}][root@docker bbox]# docker exec -it web /bin/sh/# ps auxPID? USER? ? TIME? COMMAND1root0:00/bin/httpd -f -h /data/web/html/7root0:00/bin/sh13root0:00ps aux/# netstat -tnlActive Internet connections (only servers)Proto Recv-Q Send-Q Local Address? ? ? ? ? Foreign Address? ? ? ? State? ? ? tcp00:::80:::*LISTEN

示例3:docker run 時不運(yùn)行鏡像默認(rèn)進(jìn)程,運(yùn)行指定指令

查看當(dāng)前鏡像文件:

[root@docker bbox]#dockerimagesREPOSITORYTAGIMAGEIDCREATEDSIZEwebv0.1b8613217ad3c2hoursago1.15MB

以web:v0.1創(chuàng)建容器,不運(yùn)行默認(rèn)命令

[root@docker bbox]# docker run --name web -it --rm web:v0.1 /bin/sh/# netstat -tnlActive Internet connections (only servers)Proto Recv-Q Send-Q Local Address? ? ? ? ? Foreign Address? ? ? ? State? ? ? /# ps auxPID? USER? ? TIME? COMMAND1root0:00/bin/sh7root0:00ps aux

15. ENTRYPOINT

類似CMD指令的功能庄新,用于為容器指定默認(rèn)運(yùn)行程序,從而使得容器像是一個單獨的可執(zhí)行程序

與CMD不同的是薯鼠,由ENTRYPOINT啟動的程序不會被docker run命令行指定的參數(shù)所覆蓋择诈,而且,這些命令行參數(shù)會被當(dāng)作參數(shù)傳遞給ENTRYPOINT指定指定的程序

不過出皇,docker run命令的--entrypoint選項的參數(shù)可覆蓋ENTRYPOINT指令指定的程序

Syntax

ENTRYPOINT <command>

ENTRYPOINT ["<executable>", "<param1>", "<param2>"]

docker run命令傳入的命令參數(shù)會覆蓋CMD指令的內(nèi)容并且附加到ENTRYPOINT命令最后做為其參數(shù)使用

Dockerfile文件中也可以存在多個ENTRYPOINT指令羞芍,但僅有最后一個會生效

示例1:

編輯Dockerfile文件

FROM busyboxLABEL maintainer="lixinkuan <lixinkuan@163.com>"VOLUME/data/web/html/COPY index.html/data/web/html/EXPOSE80/tcpENTRYPOINT ["/bin/httpd","-f","-h","/data/web/html"]

創(chuàng)建鏡像

[root@docker bbox]# docker build -t web:v0.2 ./Sending build context to Docker daemon? 3.072kBStep 1/6 : FROM busybox ---> 8c811b4aec35Step 2/6 : LABEL maintainer="lixinkuan " ---> Using cache ---> 56f723d6220cStep 3/6 : VOLUME /data/web/html/ --->Runningin3095065d0ebbRemoving intermediate container 3095065d0ebb ---> 36dc68fabc6fStep 4/6 : COPY index.html /data/web/html/ ---> e47f81ec7728Step 5/6 : EXPOSE 80/tcp --->Runninginf86f957ec882Removing intermediate container f86f957ec882 ---> 01a005644fe6Step 6/6 : ENTRYPOINT ["/bin/httpd","-f","-h","/data/web/html"] --->Runningin7a5f8b4f4acfRemoving intermediate container 7a5f8b4f4acf ---> 43d514096d34Successfully built 43d514096d34Successfully tagged web:v0.2

創(chuàng)建容器運(yùn)行并查看:

[root@docker bbox]# docker exec -it web /bin/sh/# ps auxPID? USER? ? TIME? COMMAND1root0:00/bin/httpd -f -h /data/web/html7root0:00/bin/sh13root0:00ps aux/# netstat -tnlActive Internet connections (only servers)Proto Recv-Q Send-Q Local Address? ? ? ? ? Foreign Address? ? ? ? State? ? ? tcp00:::80:::*LISTEN? ? ? /#

運(yùn)行容器時指定執(zhí)行/bin/sh

[root@docker bbox]# docker run --name web -it --rm web:v0.2 /bin/sh

換另一tty查看

[root@docker bbox]# docker exec -it web /bin/sh/# ps auxPID? USER? ? TIME? COMMAND? ? 1 root? ? ? 0:00 /bin/httpd-f-h /data/web/html /bin/sh? ? 7 root? ? ? 0:00 /bin/sh? 13 root? ? ? 0:00 ps aux

并未執(zhí)行/bin/sh,而是執(zhí)行默認(rèn)程序,/bin/sh被當(dāng)作參數(shù)傳遞給/bin/httpd

示例:在docker run時使用entrypoint的時候更換默認(rèn)運(yùn)行的程序

--entrypoint string Overwrite the default ENTRYPOINT of the image

使用鏡像web:v0.2創(chuàng)建容器運(yùn)行時添加--entrypoint選項

[root@docker bbox]# docker run --name web -it --rm --entrypoint /bin/sh web:v0.2/# ps auxPID? USER? ? TIME? COMMAND1root0:00/bin/sh7root0:00ps aux/# netstat -tnlActive Internet connections (only servers)Proto Recv-Q Send-Q Local Address? ? ? ? ? Foreign Address? ? ? ? State? ? ? /#

示例

編輯Dockerfile文件

FROM busyboxLABEL maintainer="lixinkuan <lixinkuan@163.com>"ENV DOCROOT="/data/web/html/"MYPORT="80"COPY index.html ${DOCROOT} COPY entrypoint.sh /bin/COPY test.conf /etc/VOLUME ${DOCROOT}EXPOSE80/tcp#CMD /bin/httpd -f -h ${DOCROOT}#CMD ["/bin/sh","-c","/bin/httpd","-f","-h","${DOCROOT}"]ENTRYPOINT ["/bin/entrypoint.sh"]CMD["/bin/httpd","-f","-h","/data/web/html/"]

提供必須文件(腳本文件需加執(zhí)行權(quán)限)

[root@docker bbox]# cat entrypoint.sh #!/bin/shsed -i"s@^PORT=.*@PORT=${MYPORT}@g"/etc/test.confexec"$@"[root@docker bbox]# cat test.conf PORT=8080

制作鏡像:

[root@docker bbox]# docker build -t web:v0.3 ./Sending build context to Docker daemon? 5.12kBStep 1/10 : FROM busybox ---> 8c811b4aec35Step 2/10 : LABEL maintainer="lixinkuan " ---> Using cache ---> 56f723d6220cStep 3/10 : ENV DOCROOT="/data/web/html/" MYPORT="80" --->Runninginf237100ec645Removing intermediate container f237100ec645 ---> f754b5dcea84Step 4/10 : COPY index.html ${DOCROOT} ---> 3c31424c9b3dStep 5/10 : COPY entrypoint.sh /bin/ ---> 46ec2f5ede8cStep 6/10 : COPY test.conf /etc/ ---> 7db53e00338aStep 7/10 : VOLUME ${DOCROOT} --->Runningin5ae02469f585Removing intermediate container 5ae02469f585 ---> 0e1e3e966318Step 8/10 : EXPOSE 80/tcp --->Runninginae76bcf870caRemoving intermediate container ae76bcf870ca ---> dea89896460dStep 9/10 : ENTRYPOINT ["/bin/entrypoint.sh"] --->Runningin6862bf4a336eRemoving intermediate container 6862bf4a336e ---> ca568e1ff983Step 10/10 : CMD ["/bin/httpd","-f","-h","/data/web/html/"] --->Runningin2aa5dea11848Removing intermediate container 2aa5dea11848 ---> 26bb44795880Successfully built 26bb44795880Successfully tagged web:v0.3

運(yùn)行容器并查看配置文件是否被修改

[root@docker bbox]# docker run --name web -d --rm web:v0.36ec1f5a008e6a08047e8666f6ed3ad4673360805148789faf780baf335ee5637[root@docker bbox]# docker exec -it web /bin/sh/# netstat -tnlActive Internet connections (only servers)Proto Recv-Q Send-Q Local Address? ? ? ? ? Foreign Address? ? ? ? State? ? ? tcp00:::80:::*LISTEN? ? ? /# cat /etc/test.confPORT=80/# exit

示例:通過傳遞變量更改配置文件的方法:

[root@docker bbox]# docker run --name web1 -d --rm -e MYPORT=10080 web:v0.37e3b353e423839d598ee9423e881673066cf99626940b6590e78f34b7622834d[root@docker bbox]# docker exec -it web1 /bin/sh/# cat /etc/test.conf PORT=10080/#

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市郊艘,隨后出現(xiàn)的幾起案子荷科,更是在濱河造成了極大的恐慌,老刑警劉巖暇仲,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異副渴,居然都是意外死亡奈附,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門煮剧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來斥滤,“玉大人,你說我怎么就攤上這事勉盅∮悠模” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵草娜,是天一觀的道長挑胸。 經(jīng)常有香客問我,道長宰闰,這世上最難降的妖魔是什么茬贵? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任簿透,我火速辦了婚禮,結(jié)果婚禮上解藻,老公的妹妹穿的比我還像新娘老充。我一直安慰自己,他們只是感情好螟左,可當(dāng)我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布啡浊。 她就那樣靜靜地躺著,像睡著了一般胶背。 火紅的嫁衣襯著肌膚如雪巷嚣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天奄妨,我揣著相機(jī)與錄音涂籽,去河邊找鬼。 笑死砸抛,一個胖子當(dāng)著我的面吹牛评雌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播直焙,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼景东,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了奔誓?” 一聲冷哼從身側(cè)響起斤吐,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎厨喂,沒想到半個月后和措,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡蜕煌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年派阱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片斜纪。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡贫母,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出盒刚,到底是詐尸還是另有隱情腺劣,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布因块,位于F島的核電站橘原,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜靠柑,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一寨辩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧歼冰,春花似錦靡狞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至腮恩,卻和暖如春梢杭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背秸滴。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工武契, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人荡含。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓咒唆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親释液。 傳聞我的和親對象是個殘疾皇子全释,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,465評論 2 348

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