之前有个web程序的例子已经介绍过了端口, 这里说下网络
每个Docker
引擎默认都会包含三个默认的网络, 我们可以这样查看:
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
5fa52100eeb6 bridge bridge local
e3b7da4f14e9 host host local
6ddc3eda6788 none null local
NAME
为bridge
的网络比较特殊, 新运行的容器默认都是在这个网络中, 除非指定是用别的网络$ docker run -itd --name=networktest ubuntu
408cf6d9f25b9757c5d5fdfcd8c9a7133c7b888095c02b7b85d46f8df404b847
$ docker network inspect bridge
我们会得到类似于下面的描述
[
{
"Name": "bridge",
"Id": "5fa52100eeb64d58d5ec97b2f2267c78d700265d310030b0bc61e203367172d2",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Containers": {
"408cf6d9f25b9757c5d5fdfcd8c9a7133c7b888095c02b7b85d46f8df404b847": {
"Name": "networktest",
"EndpointID": "87625c710a97b0e40dd79119d5002edd4c44f162ff1c2d4b85d9c87b0f43968e",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
我们可以这样检查容器的信息, 其中就有网络信息
花括号之间没有空格!!
# 查看网络信息
$ docker inspect --format='{ {json .NetworkSettings.Networks}}' networktest
{"bridge":{"IPAMConfig":null,"Links":null,"Aliases":null,"NetworkID":"5fa52100eeb64d58d5ec97b2f2267c78d700265d310030b0bc61e203367172d2","EndpointID":"87625c710a97b0e40dd79119d5002edd4c44f162ff1c2d4b85d9c87b0f43968e","Gateway":"172.17.0.1","IPAddress":"172.17.0.2","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"02:42:ac:11:00:02"}}
# 直接查看IP地址
$ docker inspect --format='{ {range .NetworkSettings.Networks}}{ {.IPAddress}}{ {end}}' networktest
172.17.0.2
$ docker network disconnect bridge networktest
把networktest
这个容器从bridge
网络中断开, 再次查看IP地址就没没有ip了
当然也可以重新连接
$ docker network connect bridge networktest
我们可以这样创建一个bridge
网络
$ docker network create -d bridge my-bridge
-d
: driver value, 可以不写, 默认就是bridge
; 最后面跟自己的driver名字在运行容器的时候可以通过传递参数--network=my-bridge
来指定使用那个网络, 不传默认使用bridge
花括号之间没有空格!!
$ docker run -d --network=my-bridge --name db training/postgres
$ docker run -d --name web training/webapp python app.py
# db 使用的网络是 my-bridge
$ docker inspect --format='{ {range .NetworkSettings.Networks}}{ {.IPAddress}}{ {end}}' db
172.18.0.2
# web 使用的网络是 bridge
shisong$ docker inspect --format='{ {range .NetworkSettings.Networks}}{ {.IPAddress}}{ {end}}' web
172.17.0.2
我们可以打开容器db
的终端, ping
一下看看网是否通
$ docker exec -it db bash
root@822d3512fe8d:/# ping 172.17.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.114 ms
64 bytes from 172.18.0.2: icmp_seq=2 ttl=64 time=0.070 ms
^C
--- 172.18.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1006ms
如果我们把web
容器也连接到my-bridge
网络中, 则网络就通了
$ docker network connect my-bridge web
# 查看新的IP地址, 刚才的网络没断开, 所以会看到有两个网络, 两个IP地址(新的是172.18.0.3)
$ docker inspect web
$ docker exec -it db bash
root@822d3512fe8d:/# ping 172.18.0.3
PING 172.18.0.3 (172.18.0.3) 56(84) bytes of data.
64 bytes from 172.18.0.3: icmp_seq=1 ttl=64 time=0.298 ms
64 bytes from 172.18.0.3: icmp_seq=2 ttl=64 time=0.112 ms
^C
--- 172.18.0.3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
数据卷(data volume
)类似于linux系统中的挂载点
我们在使用docker create
或docker run
时可以通过-v
flag来添加数据卷, 甚至可以多次使用-v
来添加多个数据卷
$ docker run -d -P --name web -v /webapp training/webapp python app.py
上面是挂载了一个数据卷到容器的/webapp
目录(必须是绝对路径), /webapp
不存在则创建, 存在则覆盖(但不会删除原有的, 卸载时恢复原有的)
通过docker inspect web
命令来查看添加数据卷的信息, 会有一段如下:
...
"Mounts":[
{
"Name":"e30f9d5c1c8ffe1d02c8f1d758c5b0663c73ba46e8469e1e6ee14a9e5ee1784a",
"Source":"/var/lib/docker/volumes/e30f9d5c1c8ffe1d02c8f1d758c5b0663c73ba46e8469e1e6ee14a9e5ee1784a/_data",
"Destination":"/webapp",
"Driver":"local",
"Mode":"",
"RW":true,
"Propagation":""
}
]
...
其中的Source
就是我们挂载的数据卷,Destination
是我们挂载到容器中的位置,RW
是否可读写, 默认就是可读写
我们可以挂载本地目录, 也可以指定是只读还是可读写模式, -v
后面的格式为[local_path:]container-dir[:ro]
, 除了上面的那种形式, 还可以像下面这样:
$ docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py
$ docker run -d -P --name web -v /src/webapp:/opt/webapp:ro training/webapp python app.py
不过在OS X
和windows
中, Docker Engine
只有/Users (OS X)
或C:\Users (Windows)
的访问权限, 所以只能这样使用了:
# os x
$ docker run -v /Users/<path>:/<container path> ...
# windows
$ docker run -v /c/Users/<path>:/<container path> ...
另外, 还可以挂载某个名字的数据卷, Docker
会创建一个给定名字的数据卷, 如:
$ docker run -d -P --name web -v foo:/opt/webapp:ro training/webapp python app.py
通过docker inspect web
得到的描述如下:
...
"Mounts": [
{
"Name": "foo",
"Source": "/var/lib/docker/volumes/foo/_data",
"Destination": "/opt/webapp",
"Driver": "local",
"Mode": "ro",
"RW": false,
"Propagation": "rprivate"
}
]
...
我们可以挂载某个文件到容器中:
$ docker run --rm -it -v ~/.bash_history:/root/.bash_history ubuntu /bin/bash
--rm
: 容器退出时自动删除容器上面就挂载了bash_history
到容器中, 在容器里查看到原来本地机上的历史命令, 当退出容器的时候, 本地机会有刚才在容器里使用过的命令的历史.
不过需要注意的是, 若是挂在了文件, 在容器里使用vi
等编辑该挂在文件时, 会引起错误. 因此挂载这个文件的父目录是更好的选择.
挂载数据卷, 可以是匿名的也可以是命名的, 可以挂载本地目录也可以挂载本地文件, 还能挂载另一个容器中的数据卷. 我们可以通过参数--volumes-from
指定数据卷来自于哪个容器, 可以多次使用--volumes-from
来挂载多个数据卷
# 先创建一个叫 dbstore 的容器, 这个容器添加了数据卷
$ docker create -v /dbdata --name dbstore training/postgres /bin/true
# 创建容器 db1, 指明数据卷来自于 dbstore
$ docker run -d --volumes-from dbstore --name db1 training/postgres
# 创建容器 db2, 指明数据卷来自于 db1
$ docker run -d --volumes-from db1 --name db2 training/postgres
上面例子中, 删除挂载数据卷的容器, 并不会删除挂载的数据卷, 除非在删除最后一个引用该数据卷的容器时指定-v
标记
# 删除容器不会删除数据卷
$ docker rm db1
# 添加 -v 由于不是最后一个引用数据卷的容器, 所以数据卷仍没被删除
$ docker rm -v dbstore
# 删除最后一个引用数据卷的容器时,添加 -v , 数据卷被删除
$ docker rm -v db2
如果删除了最后一个引用数据卷的容器时没有加-v
, 将会出现dangling
状态(悬挂,没人用了)的volume
.
volume
有匿名和命名之分, 我们可以在创建容器时通过参数--rm
指定, 当容器删除时, 对应的所有匿名volume
也随着删除
$ docker run --rm -v /foo -v awesome:/bar --name test ubuntu
我们通过-v
指定了一个匿名volume
, 挂载到容器的/foo
下, 还指定了一个命名为awesome
的volume
挂在到了/bar
下, 容器运行完自动删除镜像(--rm
)时, 匿名数据卷会被删除,而awesome
并没有被删除.
另外我们可以通过 docker volume
命令来查看管理所有的数据卷
# 查看所有 volume
$ docker volume ls
# 查看 dangling 的 volume
$ docker volume ls -f dangling=true
# 删除 volume
$ docker volume rm <volume name>
volume
的其他用法我们可以使用数据卷进行数据的备份、存储以及迁移等工作
$ docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
从dbstore
挂载了一个数据卷, 并且把本地目录挂在到了/backup
下, 最后传递了一个tar
命令, 把dbdata volume
备份到/backup
目录下的backup.tar
文件里. 命令执行完, 容器停止并被自动移除了, 但是dbdata volume
的数据被备份了.
然后我们可以创建一个新容器, 添加了一个匿名的volume
在容器的/dbdata
目录下:
$ docker run -v /dbdata --name dbstore2 ubuntu /bin/bash
下面我们可以把刚才的备份文件解压到dbstore2
的volume
中, 从而达到转移的目的
$ docker run --rm --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1"