Docker-Linux-02

五轴咱、Docker 端口映射

# Find IP address of container with ID <container_id> 通過(guò)容器 id 獲取 ip $ sudo docker inspect <container_id> | grep IPAddress | cut -d ’"’ -f 4

無(wú)論如何汛蝙,這些 ip 是基于本地系統(tǒng)的并且容器的端口非本地主機(jī)是訪問(wèn)不到的。此外朴肺,除了端口只能本地訪問(wèn)外窖剑,對(duì)于容器的另外一個(gè)問(wèn)題是這些 ip 在容器每次啟動(dòng)的時(shí)候都會(huì)改變。
Docker 解決了容器的這兩個(gè)問(wèn)題戈稿,并且給容器內(nèi)部服務(wù)的訪問(wèn)提供了一個(gè)簡(jiǎn)單而可靠的方法西土。Docker 通過(guò)端口綁定主機(jī)系統(tǒng)的接口,允許非本地客戶端訪問(wèn)容器內(nèi)部運(yùn)行的服務(wù)器瘪。為了簡(jiǎn)便的使得容器間通信翠储,Docker 提供了這種連接機(jī)制绘雁。

5.1 自動(dòng)映射端口

-P使用時(shí)需要指定--expose選項(xiàng)橡疼,指定需要對(duì)外提供服務(wù)的端口

$ sudo docker run -t -P --expose 22 --name server ubuntu:14.04

使用docker run -P自動(dòng)綁定所有對(duì)外提供服務(wù)的容器端口,映射的端口將會(huì)從沒(méi)有使用的端口池中 (49000..49900) 自動(dòng)選擇庐舟,你可以通過(guò)docker ps欣除、docker inspect <container_id>或者docker port <container_id> <port>確定具體的綁定信息。

5.2 綁定端口到指定接口

基本語(yǔ)法

$ sudo docker run -p [([<host_interface>:[host_port]])|(<host_port>):]<container_port>[/udp] <image> <cmd>

默認(rèn)不指定綁定 ip 則監(jiān)聽所有網(wǎng)絡(luò)接口挪略。
綁定 TCP 端口

# Bind TCP port 8080 of the container to TCP port 80 on 127.0.0.1 of the host machine. $ sudo docker run -p 127.0.0.1:80:8080 <image> <cmd> # Bind TCP port 8080 of the container to a dynamically allocated TCP port on 127.0.0.1 of the host machine. $ sudo docker run -p 127.0.0.1::8080 <image> <cmd> # Bind TCP port 8080 of the container to TCP port 80 on all available interfaces of the host machine. $ sudo docker run -p 80:8080 <image> <cmd> # Bind TCP port 8080 of the container to a dynamically allocated TCP port on all available interfaces $ sudo docker run -p 8080 <image> <cmd>

綁定 UDP 端口

#Bind UDP port 5353 of the container to UDP port 53 on 127.0.0.1 of the host machine. $ sudo docker run -p 127.0.0.1:53:5353/udp <image> <cmd>

六历帚、Docker 網(wǎng)絡(luò)配置

非常詳細(xì)的 Docker 學(xué)習(xí)筆記

Dokcer 通過(guò)使用 Linux 橋接提供容器之間的通信,docker0 橋接接口的目的就是方便 Docker 管理杠娱。當(dāng) Docker daemon 啟動(dòng)時(shí)需要做以下操作:
creates the docker0 bridge if not present
如果 docker0 不存在則創(chuàng)建

searches for an IP address range which doesn’t overlap with an existing route
搜索一個(gè)與當(dāng)前路由不沖突的 ip 段

picks an IP in the selected range
在確定的范圍中選擇 ip

assigns this IP to the docker0 bridge
綁定 ip 到 docker0

6.1 Docker 四種網(wǎng)絡(luò)模式

四種網(wǎng)絡(luò)模式摘自 Docker 網(wǎng)絡(luò)詳解及 pipework 源碼解讀與實(shí)踐
docker run 創(chuàng)建 Docker 容器時(shí)挽牢,可以用 --net 選項(xiàng)指定容器的網(wǎng)絡(luò)模式,Docker 有以下 4 種網(wǎng)絡(luò)模式:

host 模式摊求,使用 --net=host 指定禽拔。
container 模式,使用 --net=container:NAMEorID 指定室叉。
none 模式睹栖,使用 --net=none 指定。
bridge 模式茧痕,使用 --net=bridge 指定野来,默認(rèn)設(shè)置。

host 模式

如果啟動(dòng)容器的時(shí)候使用 host 模式踪旷,那么這個(gè)容器將不會(huì)獲得一個(gè)獨(dú)立的 Network Namespace曼氛,而是和宿主機(jī)共用一個(gè) Network Namespace豁辉。容器將不會(huì)虛擬出自己的網(wǎng)卡,配置自己的 IP 等舀患,而是使用宿主機(jī)的 IP 和端口秋忙。
例如,我們?cè)?10.10.101.105/24 的機(jī)器上用 host 模式啟動(dòng)一個(gè)含有 web 應(yīng)用的 Docker 容器构舟,監(jiān)聽 tcp 80 端口灰追。當(dāng)我們?cè)谌萜髦袌?zhí)行任何類似 ifconfig 命令查看網(wǎng)絡(luò)環(huán)境時(shí),看到的都是宿主機(jī)上的信息狗超。而外界訪問(wèn)容器中的應(yīng)用弹澎,則直接使用 10.10.101.105:80 即可,不用任何 NAT 轉(zhuǎn)換努咐,就如直接跑在宿主機(jī)中一樣苦蒿。但是,容器的其他方面渗稍,如文件系統(tǒng)佩迟、進(jìn)程列表等還是和宿主機(jī)隔離的。

container 模式

這個(gè)模式指定新創(chuàng)建的容器和已經(jīng)存在的一個(gè)容器共享一個(gè) Network Namespace竿屹,而不是和宿主機(jī)共享报强。新創(chuàng)建的容器不會(huì)創(chuàng)建自己的網(wǎng)卡,配置自己的 IP拱燃,而是和一個(gè)指定的容器共享 IP秉溉、端口范圍等。同樣碗誉,兩個(gè)容器除了網(wǎng)絡(luò)方面召嘶,其他的如文件系統(tǒng)、進(jìn)程列表等還是隔離的哮缺。兩個(gè)容器的進(jìn)程可以通過(guò) lo 網(wǎng)卡設(shè)備通信弄跌。

none模式

這個(gè)模式和前兩個(gè)不同。在這種模式下尝苇,Docker 容器擁有自己的 Network Namespace铛只,但是殉农,并不為 Docker容器進(jìn)行任何網(wǎng)絡(luò)配置压语。也就是說(shuō),這個(gè) Docker 容器沒(méi)有網(wǎng)卡引颈、IP诵冒、路由等信息凯肋。需要我們自己為 Docker 容器添加網(wǎng)卡、配置 IP 等汽馋。

bridge模式

圖片(4)

圖:The Container World | Part 2 Networking
bridge 模式是 Docker 默認(rèn)的網(wǎng)絡(luò)設(shè)置侮东,此模式會(huì)為每一個(gè)容器分配 Network Namespace圈盔、設(shè)置 IP 等,并將一個(gè)主機(jī)上的 Docker 容器連接到一個(gè)虛擬網(wǎng)橋上悄雅。當(dāng) Docker server 啟動(dòng)時(shí)驱敲,會(huì)在主機(jī)上創(chuàng)建一個(gè)名為 docker0 的虛擬網(wǎng)橋,此主機(jī)上啟動(dòng)的 Docker 容器會(huì)連接到這個(gè)虛擬網(wǎng)橋上宽闲。虛擬網(wǎng)橋的工作方式和物理交換機(jī)類似众眨,這樣主機(jī)上的所有容器就通過(guò)交換機(jī)連在了一個(gè)二層網(wǎng)絡(luò)中。接下來(lái)就要為容器分配 IP 了容诬,Docker 會(huì)從 RFC1918 所定義的私有 IP 網(wǎng)段中娩梨,選擇一個(gè)和宿主機(jī)不同的IP地址和子網(wǎng)分配給 docker0,連接到 docker0 的容器就從這個(gè)子網(wǎng)中選擇一個(gè)未占用的 IP 使用览徒。如一般 Docker 會(huì)使用 172.17.0.0/16 這個(gè)網(wǎng)段狈定,并將 172.17.42.1/16 分配給 docker0 網(wǎng)橋(在主機(jī)上使用 ifconfig 命令是可以看到 docker0 的,可以認(rèn)為它是網(wǎng)橋的管理接口习蓬,在宿主機(jī)上作為一塊虛擬網(wǎng)卡使用)

6.2 列出當(dāng)前主機(jī)網(wǎng)橋

$ sudo brctl show # brctl 工具依賴 bridge-utils 軟件包 bridge name bridge id STP enabled interfacesdocker0 8000.000000000000 no

6.3 查看當(dāng)前 docker0 ip

$ sudo ifconfig docker0docker0 Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xxinet addr:172.17.42.1 Bcast:0.0.0.0 Mask:255.255.0.0

在容器運(yùn)行時(shí)纽什,每個(gè)容器都會(huì)分配一個(gè)特定的虛擬機(jī)口并橋接到 docker0。每個(gè)容器都會(huì)配置同 docker0 ip 相同網(wǎng)段的專用 ip 地址躲叼,docker0 的 IP 地址被用于所有容器的默認(rèn)網(wǎng)關(guān)芦缰。

6.4 運(yùn)行一個(gè)容器

$ sudo docker run -t -i -d ubuntu /bin/bash52f811c5d3d69edddefc75aff5a4525fc8ba8bcfa1818132f9dc7d4f7c7e78b4 
$ sudo brctl showbridge name bridge id STP enabled interfacesdocker0 8000.fef213db5a66 no vethQCDY1N

以上, docker0 扮演著 52f811c5d3d6 container 這個(gè)容器的虛擬接口 vethQCDY1N interface 橋接的角色。
使用特定范圍的 IP
Docker 會(huì)嘗試尋找沒(méi)有被主機(jī)使用的 ip 段押赊,盡管它適用于大多數(shù)情況下饺藤,但是它不是萬(wàn)能的包斑,有時(shí)候我們還是需要對(duì) ip 進(jìn)一步規(guī)劃流礁。Docker 允許你管理 docker0 橋接或者通過(guò)-b選項(xiàng)自定義橋接網(wǎng)卡,需要安裝bridge-utils軟件包罗丰。
基本步驟如下:

ensure Docker is stopped
確保 docker 的進(jìn)程是停止的

create your own bridge (bridge0 for example)
創(chuàng)建自定義網(wǎng)橋

assign a specific IP to this bridge
給網(wǎng)橋分配特定的 ip

start Docker with the -b=bridge0 parameter
以 -b 的方式指定網(wǎng)橋

# Stopping Docker and removing docker0 
$ sudo service docker stop
 $ sudo ip link set dev docker0 down 
$ sudo brctl delbr docker0 
# Create our own bridge 
$ sudo brctl addbr bridge0 
$ sudo ip addr add 192.168.5.1/24 dev bridge0 $ sudo ip link set dev bridge0 up 
# Confirming that our bridge is up and running 
$ ip addr show bridge04: bridge0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state UP group default link/ether 66:38:d0:0d:76:18 brd ff:ff:ff:ff:ff:ff inet 192.168.5.1/24 scope global bridge0 valid_lft forever preferred_lft forever # Tell Docker about it and restart (on Ubuntu) 
$ echo 'DOCKER_OPTS="-b=bridge0"' >> /etc/default/docker $ sudo service docker start

參考文檔: Network Configuration

6.5 不同主機(jī)間容器通信

不同容器之間的通信可以借助于 pipework 這個(gè)工具:

$ git clone https://github.com/jpetazzo/pipework.git
$ sudo cp -rp pipework/pipework /usr/local/bin/

安裝相應(yīng)依賴軟件
$ sudo apt-get install iputils-arping bridge-utils -y

橋接網(wǎng)絡(luò)

橋接網(wǎng)絡(luò)可以參考 日常問(wèn)題處理 Tips 關(guān)于橋接的配置說(shuō)明神帅,這里不再贅述。

 brctl   show bridgename 
bridge id STP enabled interfacesbr0 

8000.000c291412cd no eth0docker0 
8000.56847afe9799 no vetheb48029

可以刪除 docker0萌抵,直接把 docker 的橋接指定為 br0找御。也可以保留使用默認(rèn)的配置,這樣單主機(jī)容器之間的通信可以通過(guò) docker0绍填,而跨主機(jī)不同容器之間通過(guò) pipework 新建 docker 容器的網(wǎng)卡橋接到 br0霎桅,這樣跨主機(jī)容器之間就可以通信了。
ubuntu

$ sudo service docker stop
$ sudo ip link set dev docker0 down
$ sudo brctl delbr docker0
$ echo 'DOCKER_OPTS="-b=br0"' >> /etc/default/docker
$ sudo service docker start

CentOS 7/RHEL 7

$ sudo systemctl stop docker
$ sudo ip link set dev docker0 down
$ sudo brctl delbr docker0
$ cat /etc/sysconfig/docker | grep 'OPTIONS='OPTIONS=--selinux-enabled -b=br0 -H fd://
$ sudo systemctl start docker

pipework


非常詳細(xì)的 Docker 學(xué)習(xí)筆記

不同容器之間的通信可以借助于 pipework 這個(gè)工具給 docker 容器新建虛擬網(wǎng)卡并綁定 IP 橋接到 br0

$ git clone https://github.com/jpetazzo/pipework.git
$ sudo cp -rp pipework/pipework /usr/local/bin/
$ pipework Syntax:pipework <hostinterface> [-i containerinterface] <guest> <ipaddr>/<subnet>[@default_gateway] [macaddr][@vlan]pipework <hostinterface> [-i containerinterface] <guest> dhcp [macaddr][@vlan]pipework --wait [-i containerinterface]

如果刪除了默認(rèn)的 docker0 橋接讨永,把 docker 默認(rèn)橋接指定到了 br0滔驶,則最好在創(chuàng)建容器的時(shí)候加上--net=none,防止自動(dòng)分配的 IP 在局域網(wǎng)中有沖突卿闹。

$ sudo docker run --rm -ti --net=none ubuntu:14.04 /bin/bashroot@a46657528059:/#$ # Ctrl-P + Ctrl-Q 回到宿主機(jī) shell揭糕,容器 detach 狀態(tài)
$ sudo docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESa46657528059 ubuntu:14.04 "/bin/bash" 4 minutes ago Up 4 minutes hungry_lalande
$ sudo pipework br0 -i eth0 a46657528059 192.168.115.10/24@192.168.115.2 

默認(rèn)不指定網(wǎng)卡設(shè)備名萝快,則默認(rèn)添加為 eth1# 另外 pipework 不能添加靜態(tài)路由,如果有需求則可以在 run 的時(shí)候加上 --privileged=true 權(quán)限在容器中手動(dòng)添加著角,# 但這種安全性有缺陷揪漩,可以通過(guò) ip netns 操作

$ sudo docker attach a46657528059root@a46657528059:/# ifconfig eth0eth0 Link encap:Ethernet HWaddr 86:b6:6b:e8:2e:4d inet addr:192.168.115.10 Bcast:0.0.0.0 Mask:255.255.255.0 inet6 addr: fe80::84b6:6bff:fee8:2e4d/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:8 errors:0 dropped:0 overruns:0 frame:0 TX packets:9 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:648 (648.0 B) TX bytes:690 (690.0 B)root@a46657528059:/# route -nKernel IP routing tableDestination Gateway Genmask Flags Metric Ref Use Iface0.0.0.0 192.168.115.2 0.0.0.0 UG 0 0 0 eth0192.168.115.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0

使用ip netns添加靜態(tài)路由,避免創(chuàng)建容器使用--privileged=true選項(xiàng)造成一些不必要的安全問(wèn)題:
$ docker inspect --format="{{ .State.Pid }}" a46657528059 # 獲取指定容器 pid6350$ sudo ln -s /proc/6350/ns/net /var/run/netns/6350$ sudo ip netns exec 6350 ip route add 192.168.0.0/16 dev eth0 via 192.168.115.2$ sudo ip netns exec 6350 ip route # 添加成功192.168.0.0/16 via 192.168.115.2 dev eth0 ... ...

在其它宿主機(jī)進(jìn)行相應(yīng)的配置吏口,新建容器并使用 pipework 添加虛擬網(wǎng)卡橋接到 br0奄容,測(cè)試通信情況即可。
另外产徊,pipework 可以創(chuàng)建容器的 vlan 網(wǎng)絡(luò)嫩海,這里不作過(guò)多的介紹了,官方文檔已經(jīng)寫的很清楚了囚痴,可以查看以下兩篇文章:
Pipework 官方文檔
Docker 網(wǎng)絡(luò)詳解及 pipework 源碼解讀與實(shí)踐

七叁怪、Dockerfile

Docker 可以通過(guò) Dockerfile 的內(nèi)容來(lái)自動(dòng)構(gòu)建鏡像。Dockerfile 是一個(gè)包含創(chuàng)建鏡像所有命令的文本文件深滚,通過(guò)docker build命令可以根據(jù) Dockerfile 的內(nèi)容構(gòu)建鏡像奕谭,在介紹如何構(gòu)建之前先介紹下 Dockerfile 的基本語(yǔ)法結(jié)構(gòu)。

Dockerfile 有以下指令選項(xiàng):

FROM
MAINTAINER
RUN
CMD
EXPOSE
ENV
ADD
COPY
ENTRYPOINT
VOLUME
USER
WORKDIR
ONBUILD

7.1 FROM

用法:
FROM <image>

或者
FROM <image>

FROM指定構(gòu)建鏡像的基礎(chǔ)源鏡像痴荐,如果本地沒(méi)有指定的鏡像血柳,則會(huì)自動(dòng)從 Docker 的公共庫(kù) pull 鏡像下來(lái)。
FROM必須是 Dockerfile 中非注釋行的第一個(gè)指令生兆,即一個(gè) Dockerfile 從FROM語(yǔ)句開始难捌。
FROM可以在一個(gè) Dockerfile 中出現(xiàn)多次,如果有需求在一個(gè) Dockerfile 中創(chuàng)建多個(gè)鏡像鸦难。
如果FROM語(yǔ)句沒(méi)有指定鏡像標(biāo)簽根吁,則默認(rèn)使用latest標(biāo)簽。

7.2 MAINTAINER

用法:
MAINTAINER <name>

指定創(chuàng)建鏡像的用戶
RUN 有兩種使用方式
RUN
RUN "executable", "param1", "param2"

每條RUN指令將在當(dāng)前鏡像基礎(chǔ)上執(zhí)行指定命令合蔽,并提交為新的鏡像击敌,后續(xù)的RUN都在之前RUN提交后的鏡像為基礎(chǔ),鏡像是分層的拴事,可以通過(guò)一個(gè)鏡像的任何一個(gè)歷史提交點(diǎn)來(lái)創(chuàng)建沃斤,類似源碼的版本控制
exec 方式會(huì)被解析為一個(gè) JSON 數(shù)組刃宵,所以必須使用雙引號(hào)而不是單引號(hào)衡瓶。exec 方式不會(huì)調(diào)用一個(gè)命令 shell,所以也就不會(huì)繼承相應(yīng)的變量牲证,如:
RUN [ "echo", "$HOME" ]

這種方式是不會(huì)達(dá)到輸出 HOME 變量的哮针,正確的方式應(yīng)該是這樣的
RUN [ "sh", "-c", "echo", "$HOME" ]

RUN產(chǎn)生的緩存在下一次構(gòu)建的時(shí)候是不會(huì)失效的,會(huì)被重用,可以使用--no-cache選項(xiàng)诚撵,即docker build --no-cache缭裆,如此便不會(huì)緩存。

7.3 CMD

CMD有三種使用方式:

CMD ["executable","param1","param2"](http://opskumu.github.io/exec%20form,%20this%20is%20the%20preferred%20form,%20%E4%BC%98%E5%85%88%E9%80%89%E6%8B%A9)
CMD ["param1","param2"](http://opskumu.github.io/as%20default%20parameters%20to%20%60ENTRYPOINT%60)
CMD command param1 param2 (shell form)

CMD指定在 Dockerfile 中只能使用一次寿烟,如果有多個(gè)澈驼,則只有最后一個(gè)會(huì)生效。

CMD的目的是為了在啟動(dòng)容器時(shí)提供一個(gè)默認(rèn)的命令執(zhí)行選項(xiàng)筛武。如果用戶啟動(dòng)容器時(shí)指定了運(yùn)行的命令缝其,則會(huì)覆蓋掉CMD指定的命令。

CMD會(huì)在啟動(dòng)容器的時(shí)候執(zhí)行徘六,build 時(shí)不執(zhí)行内边,而RUN只是在構(gòu)建鏡像的時(shí)候執(zhí)行,后續(xù)鏡像構(gòu)建完成之后待锈,啟動(dòng)容器就與RUN無(wú)關(guān)了漠其,這個(gè)初學(xué)者容易弄混這個(gè)概念,這里簡(jiǎn)單注解一下竿音。

7.4 EXPOSE

EXPOSE <port> [<port>...]

告訴 Docker 服務(wù)端容器對(duì)外映射的本地端口和屎,需要在 docker run 的時(shí)候使用-p或者-P選項(xiàng)生效。

7.5 ENV

ENV <key> <value> 
# 只能設(shè)置一個(gè)變量ENV <key>=<value> ... 
# 允許一次設(shè)置多個(gè)變量

指定一個(gè)環(huán)節(jié)變量春瞬,會(huì)被后續(xù)RUN指令使用柴信,并在容器運(yùn)行時(shí)保留。
例子:

ENV myName="John Doe" myDog=Rex\ The\ Dog \ myCat=fluffy

#等同于
ENV myName John DoeENV myDog Rex The DogENV myCat fluffy

7.6 ADD

ADD <src>... <dest>

ADD復(fù)制本地主機(jī)文件宽气、目錄或者遠(yuǎn)程文件 URLS 從 并且添加到容器指定路徑中 随常。
支持通過(guò) Go 的正則模糊匹配,具體規(guī)則可參見 Go filepath.Match

ADD hom* /mydir/ 
# adds all files starting with "hom"ADD hom?.txt /mydir/ # ? is replaced with any single character

路徑必須是絕對(duì)路徑萄涯,如果 不存在绪氛,會(huì)自動(dòng)創(chuàng)建對(duì)應(yīng)目錄
路徑必須是 Dockerfile 所在路徑的相對(duì)路徑
如果是一個(gè)目錄,只會(huì)復(fù)制目錄下的內(nèi)容窃判,而目錄本身則不會(huì)被復(fù)制

7.7 COPY

COPY <src>... <dest>

COPY復(fù)制新文件或者目錄從 并且添加到容器指定路徑中 钞楼。用法同ADD,唯一的不同是不能指定遠(yuǎn)程文件 URLS袄琳。

7.8 ENTRYPOINT

ENTRYPOINT "executable", "param1", "param2"
ENTRYPOINT command param1 param2 (shell form)

配置容器啟動(dòng)后執(zhí)行的命令,并且不可被 docker run 提供的參數(shù)覆蓋燃乍,而CMD是可以被覆蓋的唆樊。如果需要覆蓋,則可以使用docker run --entrypoint選項(xiàng)刻蟹。
每個(gè) Dockerfile 中只能有一個(gè)ENTRYPOINT逗旁,當(dāng)指定多個(gè)時(shí),只有最后一個(gè)生效。
Exec form ENTRYPOINT 例子
通過(guò)ENTRYPOINT使用 exec form 方式設(shè)置穩(wěn)定的默認(rèn)命令和選項(xiàng)片效,而使用CMD添加默認(rèn)之外經(jīng)常被改動(dòng)的選項(xiàng)红伦。

FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]

通過(guò) Dockerfile 使用ENTRYPOINT展示前臺(tái)運(yùn)行 Apache 服務(wù)

FROM debian:stable
RUN apt-get update && apt-get install -y --force-yes apache2
EXPOSE 80 443
VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]

Shell form ENTRYPOINT 例子
這種方式會(huì)在/bin/sh -c中執(zhí)行,會(huì)忽略任何CMD或者docker run命令行選項(xiàng)淀衣,為了確保docker stop能夠停止長(zhǎng)時(shí)間運(yùn)行ENTRYPOINT的容器昙读,確保執(zhí)行的時(shí)候使用exec選項(xiàng)。

FROM ubuntu
ENTRYPOINT exec top -b

如果在ENTRYPOINT忘記使用exec選項(xiàng)膨桥,則可以使用CMD補(bǔ)上:

FROM ubuntu
ENTRYPOINT top -b
CMD --ignored-param1 # --ignored-param2 ... --ignored-param3 ... 依此類推

7.9 VOLUME

VOLUME ["/data"]

創(chuàng)建一個(gè)可以從本地主機(jī)或其他容器掛載的掛載點(diǎn)蛮浑,后續(xù)具體介紹。

7.10 USER

USER daemon

指定運(yùn)行容器時(shí)的用戶名或 UID只嚣,后續(xù)的RUN沮稚、CMD、ENTRYPOINT也會(huì)使用指定用戶册舞。

7.11 WORKDIR

WORKDIR /path/to/workdir

為后續(xù)的RUN蕴掏、CMD、ENTRYPOINT指令配置工作目錄调鲸∏羲疲可以使用多個(gè)WORKDIR指令,后續(xù)命令如果參數(shù)是相對(duì)路徑线得,則會(huì)基于之前命令指定的路徑饶唤。

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

最終路徑是/a/b/c。
WORKDIR指令可以在ENV設(shè)置變量之后調(diào)用環(huán)境變量:

ENV DIRPATH /path
WORKDIR $DIRPATH/$DIRNAME

最終路徑則為 /path/$DIRNAME贯钩。

7.12 ONBUILD

ONBUILD [INSTRUCTION]

配置當(dāng)所創(chuàng)建的鏡像作為其它新創(chuàng)建鏡像的基礎(chǔ)鏡像時(shí)募狂,所執(zhí)行的操作指令。
例如角雷,Dockerfile 使用如下的內(nèi)容創(chuàng)建了鏡像 image-A:

[...]
ONBUILD 
ADD . /app/src
ONBUILD 
RUN /usr/local/bin/python-build --dir /app/src[...]

#如果基于 image-A 創(chuàng)建新的鏡像時(shí)祸穷,新的 Dockerfile 中使用 FROM image-A 指定基礎(chǔ)鏡像時(shí),會(huì)自動(dòng)執(zhí)行 ONBUILD 指令內(nèi)容勺三,等價(jià)于在后面添加了兩條指令雷滚。

#  Automatically run the following
#  ADD . /app/src
#  RUN /usr/local/bin/python-build --dir /app/src

使用ONBUILD指令的鏡像,推薦在標(biāo)簽中注明吗坚,例如 ruby:1.9-onbuild祈远。

7.13 Dockerfile Examples

# Nginx
## VERSION 0.0.1
FROM ubuntu
MAINTAINER Victor Vieux <victor@docker.com>
RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server  

# Firefox over VNC
## VERSION 0.3
FROM ubuntu
# Install vnc, xvfb in order to create a 'fake' display and firefoxRUN apt-get update && apt-get install -y x11vnc xvfb firefox
RUN mkdir ~/.vnc
# Setup a password
RUN x11vnc -storepasswd 1234 ~/.vnc/passwd
# Autostart firefox (might not be the best way, but it does the trick)
RUN bash -c 'echo "firefox" >> /.bashrc'
EXPOSE 5900
CMD ["x11vnc", "-forever", "-usepw", "-create"]

# Multiple images example
## VERSION 0.1
FROM ubuntu
RUN echo foo > bar
# Will output something like ===> 907ad6c2736f

FROM ubuntu
RUN echo moo > oink
# Will output something like ===> 695d7793cbe4
# You?ll now have two images, 907ad6c2736f with /bar, and 695d7793cbe4 with /oink.

7.14 docker build

$ docker build --help
Usage: docker build [OPTIONS] PATH | URL | -Build a new image from the source code at PATH --force-rm=false Always remove intermediate containers, even after unsuccessful builds 
# 移除過(guò)渡容器,即使構(gòu)建失敗 
# --no-cache=false   Do not use cache when building the image 
# 不實(shí)用 
# cache -q, --quiet=false Suppress the verbose output generated by the containers 
#--rm=true Remove intermediate containers after a successful build 
# 構(gòu)建成功后移除過(guò)渡層容器 -t, --tag="" Repository name (and optionally a tag) to be applied to the resulting image in case of success

參考文檔:Dockerfile Reference

7.15 dockerfile 最佳實(shí)踐

使用.dockerignore文件

為了在docker build過(guò)程中更快上傳和更加高效商源,應(yīng)該使用一個(gè).dockerignore文件用來(lái)排除構(gòu)建鏡像時(shí)不需要的文件或目錄车份。例如,除非.Git在構(gòu)建過(guò)程中需要用到,否則你應(yīng)該將它添加到.dockerignore文件中牡彻,這樣可以節(jié)省很多時(shí)間扫沼。
避免安裝不必要的軟件包

為了降低復(fù)雜性、依賴性、文件大小以及構(gòu)建時(shí)間缎除,應(yīng)該避免安裝額外的或不必要的包严就。例如,不需要在一個(gè)數(shù)據(jù)庫(kù)鏡像中安裝一個(gè)文本編輯器器罐。
每個(gè)容器都跑一個(gè)進(jìn)程

在大多數(shù)情況下梢为,一個(gè)容器應(yīng)該只單獨(dú)跑一個(gè)程序。解耦應(yīng)用到多個(gè)容器使其更容易橫向擴(kuò)展和重用技矮。如果一個(gè)服務(wù)依賴另外一個(gè)服務(wù)抖誉,可以參考 Linking Containers Together
最小化層

我們知道每執(zhí)行一個(gè)指令衰倦,都會(huì)有一次鏡像的提交袒炉,鏡像是分層的結(jié)構(gòu),對(duì)于Dockerfile樊零,應(yīng)該找到可讀性和最小化層之間的平衡我磁。
多行參數(shù)排序

如果可能,通過(guò)字母順序來(lái)排序驻襟,這樣可以避免安裝包的重復(fù)并且更容易更新列表夺艰,另外可讀性也會(huì)更強(qiáng),添加一個(gè)空行使用\換行:
RUN apt-get update && apt-get install -y \ bzr \ cvs \ git \ mercurial \ subversion

創(chuàng)建緩存

鏡像構(gòu)建過(guò)程中會(huì)按照Dockerfile的順序依次執(zhí)行沉衣,每執(zhí)行一次指令 Docker 會(huì)尋找是否有存在的鏡像緩存可復(fù)用郁副,如果沒(méi)有則創(chuàng)建新的鏡像。如果不想使用緩存豌习,則可以在docker build時(shí)添加--no-cache=true選項(xiàng)存谎。
從基礎(chǔ)鏡像開始就已經(jīng)在緩存中了,下一個(gè)指令會(huì)對(duì)比所有的子鏡像尋找是否執(zhí)行相同的指令肥隆,如果沒(méi)有則緩存失效既荚。在大多數(shù)情況下只對(duì)比Dockerfile指令和子鏡像就足夠了。ADD和COPY指令除外栋艳,執(zhí)行ADD和COPY時(shí)存放到鏡像的文件也是需要檢查的恰聘,完成一個(gè)文件的校驗(yàn)之后再利用這個(gè)校驗(yàn)在緩存中查找,如果檢測(cè)的文件改變則緩存失效吸占。RUN apt-get -y update命令只檢查命令是否匹配晴叨,如果匹配就不會(huì)再執(zhí)行更新了。
為了有效地利用緩存旬昭,你需要保持你的 Dockerfile 一致篙螟,并且盡量在末尾修改。

Dockerfile 指令
FROM: 只要可能就使用官方鏡像庫(kù)作為基礎(chǔ)鏡像
RUN: 為保持可讀性问拘、方便理解、可維護(hù)性,把長(zhǎng)或者復(fù)雜的RUN語(yǔ)句使用\分隔符分成多行不建議RUN apt-get update獨(dú)立成行骤坐,否則如果后續(xù)包有更新绪杏,那么也不會(huì)再執(zhí)行更新
避免使用RUN apt-get upgrade或者dist-upgrade,很多必要的包在一個(gè)非privileged權(quán)限的容器里是無(wú)法升級(jí)的纽绍。如果知道某個(gè)包更新蕾久,使用apt-get install -y xxx
標(biāo)準(zhǔn)寫法RUN apt-get update && apt-get install -y package-bar package-foo

例子:

RUN apt-get update && apt-get install -y \ aufs-tools \ automake \ btrfs-tools \ build-essential \ curl \ dpkg-sig \ git \ iptables \ libapparmor-dev \ libcap-dev \ libsqlite3-dev \ lxc=1.0* \ mercurial \ parallel \ reprepro \ ruby1.9.1 \ ruby1.9.1-dev \ s3cmd=1.1.0*

CMD: 推薦使用CMD [“executable”, “param1”, “param2”…]這種格式,CMD [“param”, “param”]則配合ENTRYPOINT使用
EXPOSE: Dockerfile 指定要公開的端口拌夏,使用docker run時(shí)指定映射到宿主機(jī)的端口即可
ENV: 為了使新的軟件更容易運(yùn)行僧著,可以使用ENV更新PATH變量。如ENV PATH /usr/local/nginx/bin:$PATH確保CMD ["nginx"]即可運(yùn)行

ENV也可以這樣定義變量:
ENV PG_MAJOR 9.3ENV PG_VERSION 9.3.4RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH

ADDorCOPY:ADD比COPY多一些特性「tar 文件自動(dòng)解包和支持遠(yuǎn)程 URL」障簿,不推薦添加遠(yuǎn)程 URL

如不推薦這種方式:
ADD http://example.com/big.tar.xz /usr/src/things/RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/thingsRUN make -C /usr/src/things all

推薦使用 curl 或者 wget 替換盹愚,使用如下方式:
RUN mkdir -p /usr/src/things \ && curl -SL http://example.com/big.tar.gz \ | tar -xJC /usr/src/things \ && make -C /usr/src/things all

如果不需要添加 tar 文件,推薦使用COPY站故。
參考文檔:
Best practices for writing Dockerfiles
Dockerfile最佳實(shí)踐(一)
Dockerfile最佳實(shí)踐(二)

八西篓、容器數(shù)據(jù)管理

docker管理數(shù)據(jù)的方式有兩種:
數(shù)據(jù)卷
數(shù)據(jù)卷容器

8.1 數(shù)據(jù)卷

數(shù)據(jù)卷是一個(gè)或多個(gè)容器專門指定繞過(guò)Union File System的目錄,為持續(xù)性或共享數(shù)據(jù)提供一些有用的功能:
數(shù)據(jù)卷可以在容器間共享和重用
數(shù)據(jù)卷數(shù)據(jù)改變是直接修改的
數(shù)據(jù)卷數(shù)據(jù)改變不會(huì)被包括在容器中
數(shù)據(jù)卷是持續(xù)性的赁豆,直到?jīng)]有容器使用它們

添加一個(gè)數(shù)據(jù)卷
你可以使用-v選項(xiàng)添加一個(gè)數(shù)據(jù)卷,或者可以使用多次-v選項(xiàng)為一個(gè) docker 容器運(yùn)行掛載多個(gè)數(shù)據(jù)卷。

$ sudo docker run --name data -v /data -t -i ubuntu:14.04 /bin/bash

 # 創(chuàng)建數(shù)據(jù)卷綁定到到新建容器,新建容器中會(huì)創(chuàng)建 /data 數(shù)據(jù)卷 bash-4.1
# ls -ld /data/drwxr-xr-x 2 root root 4096 Jul 23 06:59 /data/bash-4.1
# df -ThFilesystem Type Size Used Avail Use% Mounted on... ... ext4 91G 4.6G 82G 6% /data

創(chuàng)建的數(shù)據(jù)卷可以通過(guò)docker inspect獲取宿主機(jī)對(duì)應(yīng)路徑

$ sudo docker inspect data
"Volumes": { "/data": "/var/lib/docker/vfs/dir/151de401d268226f96d824fdf444e77a4500aed74c495de5980c807a2ffb7ea9" }, 
# 可以看到創(chuàng)建的數(shù)據(jù)卷宿主機(jī)路徑 

或者直接指定獲取
$ sudo docker inspect --format="{{ .Volumes }}" 
datamap[/data: /var/lib/docker/vfs/dir/151de401d268226f96d824fdf444e77a4500aed74c495de5980c807a2ffb7ea9]

掛載宿主機(jī)目錄為一個(gè)數(shù)據(jù)卷
-v選項(xiàng)除了可以創(chuàng)建卷,也可以掛載當(dāng)前主機(jī)的一個(gè)目錄到容器中。

$ sudo docker run --name web -v /source/:/web -t -i ubuntu:14.04 /bin/bash
bash-4.1
# ls -ld 
#/web/drwxr-xr-x 2 root root 4096 Jul 23 06:59 /web/bash-4.1# df -Th... ... ext4 91G 4.6G 82G 6% /webbash-4.1# exit

默認(rèn)掛載卷是可讀寫的退渗,可以在掛載時(shí)指定只讀
$ sudo docker run --rm --name test -v /source/:/test:ro -t -i ubuntu:14.04 /bin/bash

8.2 創(chuàng)建和掛載一個(gè)數(shù)據(jù)卷容器
如果你有一些持久性的數(shù)據(jù)并且想在容器間共享钞啸,或者想用在非持久性的容器上,最好的方法是創(chuàng)建一個(gè)數(shù)據(jù)卷容器,然后從此容器上掛載數(shù)據(jù)。
創(chuàng)建數(shù)據(jù)卷容器
$ sudo docker run -t -i -d -v /test --name test ubuntu:14.04 echo hello

使用--volumes-from選項(xiàng)在另一個(gè)容器中掛載 /test 卷。不管 test 容器是否運(yùn)行,其它容器都可以掛載該容器數(shù)據(jù)卷,當(dāng)然如果只是單獨(dú)的數(shù)據(jù)卷是沒(méi)必要運(yùn)行容器的馍刮。
$ sudo docker run -t -i -d --volumes-from test --name test1 ubuntu:14.04 /bin/bash

添加另一個(gè)容器
$ sudo docker run -t -i -d --volumes-from test --name test2 ubuntu:14.04 /bin/bash

也可以繼承其它掛載有 /test 卷的容器
$ sudo docker run -t -i -d --volumes-from test1 --name test3 ubuntu:14.04 /bin/bash

非常詳細(xì)的 Docker 學(xué)習(xí)筆記

8.3 備份姊扔、恢復(fù)或遷移數(shù)據(jù)卷
備份
$ sudo docker run --rm --volumes-from test -v $(pwd):/backup ubuntu:14.04 tar cvf /backup/test.tar /testtar: Removing leading `/' from member names/test//test/b/test/d/test/c/test/a

啟動(dòng)一個(gè)新的容器并且從test容器中掛載卷梗掰,然后掛載當(dāng)前目錄到容器中為 backup埂陆,并備份 test 卷中所有的數(shù)據(jù)為 test.tar,執(zhí)行完成之后刪除容器--rm蓬抄,此時(shí)備份就在當(dāng)前的目錄下丰嘉,名為test.tar。
$ ls # 宿主機(jī)當(dāng)前目錄下產(chǎn)生了 test 卷的備份文件 test.tar test.tar

恢復(fù)
你可以恢復(fù)給同一個(gè)容器或者另外的容器嚷缭,新建容器并解壓備份文件到新的容器數(shù)據(jù)卷
$ sudo docker run -t -i -d -v /test --name test4 ubuntu:14.04 /bin/bash $ sudo docker run --rm --volumes-from test4 -v $(pwd):/backup ubuntu:14.04 tar xvf /backup/test.tar -C / # 恢復(fù)之前的文件到新建卷中饮亏,執(zhí)行完后自動(dòng)刪除容器 test/ test/b test/d test/c test/a

8.4 刪除 Volumes
Volume 只有在下列情況下才能被刪除:
docker rm -v刪除容器時(shí)添加了-v選項(xiàng)
docker run --rm運(yùn)行容器時(shí)添加了--rm選項(xiàng)

否則,會(huì)在/var/lib/docker/vfs/dir目錄中遺留很多不明目錄峭状。
參考文檔:
Managing Data in Containers
深入理解Docker Volume(一)
深入理解Docker Volume(二)

九克滴、鏈接容器
docker 允許把多個(gè)容器連接在一起,相互交互信息优床。docker 鏈接會(huì)創(chuàng)建一種容器父子級(jí)別的關(guān)系劝赔,其中父容器可以看到其子容器提供的信息。
9.1 容器命名
在創(chuàng)建容器時(shí)胆敞,如果不指定容器的名字着帽,則默認(rèn)會(huì)自動(dòng)創(chuàng)建一個(gè)名字杂伟,這里推薦給容器命名:
1、給容器命名方便記憶仍翰,如命名運(yùn)行 web 應(yīng)用的容器為 web
2赫粥、為 docker 容器提供一個(gè)參考,允許方便其他容器調(diào)用予借,如把容器 web 鏈接到容器 db

可以通過(guò)--name選項(xiàng)給容器自定義命名:
$ sudo docker run -d -t -i --name test ubuntu:14.04 bash $ sudo docker inspect --format="{{ .Nmae }}" test/test

注:容器名稱必須唯一越平,即你只能命名一個(gè)叫test的容器。如果你想復(fù)用容器名灵迫,則必須在創(chuàng)建新的容器前通過(guò)docker rm刪除舊的容器或者創(chuàng)建容器時(shí)添加--rm選項(xiàng)秦叛。

9.2 鏈接容器
鏈接允許容器間安全通信,使用--link選項(xiàng)創(chuàng)建鏈接瀑粥。
$ sudo docker run -d --name db training/postgres

基于 training/postgres 鏡像創(chuàng)建一個(gè)名為 db 的容器挣跋,然后下面創(chuàng)建一個(gè)叫做 web 的容器,并且將它與 db 相互連接在一起
$ sudo docker run -d -P --name web --link db:db training/webapp python app.py

--link <name or id>:alias選項(xiàng)指定鏈接到的容器狞换。
查看 web 容器的鏈接關(guān)系:
$ sudo docker inspect -f "{{ .HostConfig.Links }}" web[/db:/web/db]

可以看到 web 容器被鏈接到 db 容器為/web/db避咆,這允許 web 容器訪問(wèn) db 容器的信息。
容器之間的鏈接實(shí)際做了什么修噪?一個(gè)鏈接允許一個(gè)源容器提供信息訪問(wèn)給一個(gè)接收容器查库。在本例中,web 容器作為一個(gè)接收者割按,允許訪問(wèn)源容器 db 的相關(guān)服務(wù)信息膨报。Docker 創(chuàng)建了一個(gè)安全隧道而不需要對(duì)外公開任何端口給外部容器,因此不需要在創(chuàng)建容器的時(shí)候添加-p或-P指定對(duì)外公開的端口适荣,這也是鏈接容器的最大好處现柠,本例為 PostgreSQL 數(shù)據(jù)庫(kù)。
Docker 主要通過(guò)以下兩個(gè)方式提供連接信息給接收容器:
環(huán)境變量
更新/etc/hosts文件

環(huán)境變量
當(dāng)兩個(gè)容器鏈接弛矛,Docker 會(huì)在目標(biāo)容器上設(shè)置一些環(huán)境變量够吩,以獲取源容器的相關(guān)信息。
首先丈氓,Docker 會(huì)在每個(gè)通過(guò)--link選項(xiàng)指定別名的目標(biāo)容器上設(shè)置一個(gè)<alias>NAME環(huán)境變量周循。如果一個(gè)名為 web 的容器通過(guò)--link db:webdb被鏈接到一個(gè)名為 db 的數(shù)據(jù)庫(kù)容器,那么 web 容器上會(huì)設(shè)置一個(gè)環(huán)境變量為WEBDB_NAME=/web/webdb.
以之前的為例万俗,Docker 還會(huì)設(shè)置端口變量:
$ sudo docker run --rm --name web2 --link db:db training/webapp env. . .DB_NAME=/web2/dbDB_PORT=tcp://172.17.0.5:5432 DB_PORT_5432_TCP=tcp://172.17.0.5:5432 # <name>PORT<port>
<protocol> 協(xié)議可以是 TCP 或 UDPDB_PORT_5432_TCP_PROTO=tcpDB_PORT_5432_TCP_PORT=5432DB_PORT_5432_TCP_ADDR=172.17.0.5. . .

注:這些環(huán)境變量只設(shè)置給容器中的第一個(gè)進(jìn)程湾笛,類似一些守護(hù)進(jìn)程 (如 sshd ) 當(dāng)他們派生 shells 時(shí)會(huì)清除這些變量

更新/etc/hosts文件
除了環(huán)境變量,Docker 會(huì)在目標(biāo)容器上添加相關(guān)主機(jī)條目到/etc/hosts中闰歪,上例中就是 web 容器嚎研。
$ sudo docker run -t -i --rm --link db:db training/webapp /bin/bashroot@aed84ee21bde:/opt/webapp# cat /etc/hosts172.17.0.7 aed84ee21bde. . .172.17.0.5 db

/etc/host文件在源容器被重啟之后會(huì)自動(dòng)更新 IP 地址,而環(huán)境變量中的 IP 地址則不會(huì)自動(dòng)更新的库倘。

十临扮、構(gòu)建私有庫(kù)
Docker 官方提供了 docker registry 的構(gòu)建方法 docker-registry
10.1 快速構(gòu)建
快速構(gòu)建 docker registry 通過(guò)以下兩步:
安裝 docker
運(yùn)行 registry:docker run -p 5000:5000 registry

這種方法通過(guò) Docker hub 使用官方鏡像 official image from the Docker hub
10.2 不使用容器構(gòu)建 registry
安裝必要的軟件
$ sudo apt-get install build-essential python-dev libevent-dev python-pip liblzma-dev

配置 docker-registry
sudo pip install docker-registry

或者 使用 github clone 手動(dòng)安裝
$ git clone https://github.com/dotcloud/docker-registry.git$ cd docker-registry/$ cp config/config_sample.yml config/config.yml$ mkdir /data/registry -p$ pip install .

運(yùn)行
docker-registry

高級(jí)啟動(dòng)方式 [不推薦]
使用gunicorn控制:
gunicorn -c contrib/gunicorn_config.py docker_registry.wsgi:application

或者對(duì)外監(jiān)聽開放
gunicorn --access-logfile - --error-logfile - -k gevent -b 0.0.0.0:5000 -w 4 --max-requests 100 docker_registry.wsgi:application

10.3 提交指定容器到私有庫(kù)
$ docker tag ubuntu:12.04 私有庫(kù)IP:5000/ubuntu:12.04$ docker push 私有庫(kù)IP:5000/ubuntu

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末论矾,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子杆勇,更是在濱河造成了極大的恐慌贪壳,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚜退,死亡現(xiàn)場(chǎng)離奇詭異闰靴,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)关霸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門传黄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人队寇,你說(shuō)我怎么就攤上這事≌滦眨” “怎么了佳遣?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)凡伊。 經(jīng)常有香客問(wèn)我零渐,道長(zhǎng),這世上最難降的妖魔是什么系忙? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任诵盼,我火速辦了婚禮,結(jié)果婚禮上银还,老公的妹妹穿的比我還像新娘风宁。我一直安慰自己,他們只是感情好蛹疯,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布戒财。 她就那樣靜靜地躺著,像睡著了一般捺弦。 火紅的嫁衣襯著肌膚如雪饮寞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天列吼,我揣著相機(jī)與錄音幽崩,去河邊找鬼。 笑死寞钥,一個(gè)胖子當(dāng)著我的面吹牛慌申,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播凑耻,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼太示,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼柠贤!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起类缤,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤臼勉,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后餐弱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宴霸,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年膏蚓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瓢谢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡驮瞧,死狀恐怖氓扛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情论笔,我是刑警寧澤采郎,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站狂魔,受9級(jí)特大地震影響蒜埋,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜最楷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一整份、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧籽孙,春花似錦烈评、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至胎挎,卻和暖如春沟启,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背犹菇。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工德迹, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人揭芍。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓胳搞,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子肌毅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

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

  • 轉(zhuǎn)載自 http://blog.opskumu.com/docker.html 一筷转、Docker 簡(jiǎn)介 Docke...
    極客圈閱讀 10,501評(píng)論 0 120
  • Docker — 云時(shí)代的程序分發(fā)方式 要說(shuō)最近一年云計(jì)算業(yè)界有什么大事件?Google Compute Engi...
    ahohoho閱讀 15,534評(píng)論 15 147
  • 一悬而、Docker 簡(jiǎn)介 Docker 兩個(gè)主要部件:Docker: 開源的容器虛擬化平臺(tái)Docker Hub: 用...
    R_X閱讀 4,388評(píng)論 0 27
  • 映射的種類 有五種映射存在: 用于普通模式: 輸入命令時(shí)呜舒。 用于可視模式: 可視區(qū)域高亮并輸入命令時(shí)。 用于操作符...
    __XY__閱讀 878評(píng)論 0 0
  • 健康到腥,是一種幸福,更是一種責(zé)任蔚袍,有健康的身體才能擔(dān)當(dāng)好家庭和社會(huì)的角色乡范,才能活出生命的精彩! 關(guān)注健康页响,關(guān)愛(ài)...
    純陽(yáng)草閱讀 227評(píng)論 0 0