Docker容器连接
端口映射并不是唯一把docker连接到另一个容器的方法。docker有一个连接系统允许将多个容器连接在一起,共享连接信息。docker连接会创建一个父子关系,其中父容器可以看到子容器的信息。
执行此连接需要依靠你的docker的名字,这里我们可以看到当我们创建每一个容器的时候,它都会自动被命名。也可以自己命名容器。这种命名提供了两个有用的功能:
1.给容器特定的名字使你更容易记住他们,例如:命名web应用程序为web容器。
2.它为docker提供一个参考,允许其他容器引用,举例连接web容器到db容器。
你可以使用--name标识来命名容器,举例:
$ sudo docker run -d -P --name web training/webapp python app.py
我们可以看到我们启动了的容器,就是我们使用--name标识命名为web的容器。我们可以使用docker ps命令来查看容器名称。
$ sudo docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
aed84ee21bde training/webapp:latest python app.py 12 hours ago Up 2 seconds 0.0.0.0:49154->5000/tcp web
我们也可以使用docker inspect来返回容器名字。
$ sudo docker inspect -f "{{ .Name }}" aed84ee21bde
注:容器的名称必须是唯一的。这意味着你只能调用一个web容器。如果你想使用重复的名称来命名容器,你需要使用docker rm命令删除以前的容器。在容器停止后删除。
连接允许容器之间可见并且安全地进行通信。使用--link创建连接。我们创建一个新容器,这个容器是数据库。
$ sudo docker run -d --name db training/postgres
这里我们使用training/postgres容器创建一个新的容器。容器是PostgreSQL数据库。
现在我们创建一个web容器来连接db容器。
$ sudo docker run -d -P --name web --link db:db training/webapp python app.py
这将使我们的web容器和db容器连接起来。--link的形式
--link name:alias
name是我们连接容器的名字,alias是link的别名。让我们看如何使用alias。
让我们使用docker ps来查看容器连接.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
349169744e49 training/postgres:latest su postgres -c '/usr About a minute ago Up About a minute 5432/tcp db
aed84ee21bde training/webapp:latest python app.py 16 hours ago Up 2 minutes 0.0.0.0:49154->5000/tcp db/web,web
我们可以看到我们命名的容器,db和web,我们还在名字列中可以看到web容器也显示db/web。这告诉我们web容器和db容器是父/子关系。
我们连接容器做什么?我们发现连接的两个容器是父子关系。这里的父容器是db可以访问子容器web。为此docker在容器之间打开一个安全连接隧道不需要暴露任何端口在容器外部。你会注意到当你启动db容器的时候我们没有使用-P或者-p标识。我们连接容器的时候我们不需要通过网络给PostgreSQL数据库开放端口。
Docker在父容器中开放子容器连接信息有两种方法:
更新/etc/hosts文件。
让我们先看看docker的环境变量。我们运行env命令来查看列表容器的环境变量。
$ sudo docker run --rm --name web2 --link db:db training/webapp env
. . .
DB_NAME=/web2/db
DB_PORT=tcp://172.17.0.5:5432
DB_PORT_5000_TCP=tcp://172.17.0.5:5432
DB_PORT_5000_TCP_PROTO=tcp
DB_PORT_5000_TCP_PORT=5432
DB_PORT_5000_TCP_ADDR=172.17.0.5
. . .
注:这些环境变量只设置顶一个进程的容器。同样,一些守护进程(例如sshd)进行shell连接时就会去除。
我们可以看到docker为我们的数据库容器创建了一系列环境变量。每个前缀变量是DB_填充我们指定的别名。如果我们的别名是db1,前缀别名就是DB1_。您可以使用这些环境变量来配置您的应用程序连接到你的数据库db容器。该连接时安全、私有的,只能在web容器和db容器之间通信。
docker除了环境变量,可以添加信息到父主机的/etc/hosts
root@aed84ee21bde:/opt/webapp# cat /etc/hosts
172.17.0.7 aed84ee21bde
. . .
172.17.0.5 db
这里我们可以看到两个主机项。第一项是web容器用容器ID作为主机名字。第二项是使用别名引用IP地址连接数据库容器。现在我们试试ping这个主机:
root@aed84ee21bde:/opt/webapp# apt-get install -yqq inetutils-ping
root@aed84ee21bde:/opt/webapp# ping db
PING db (172.17.0.5): 48 data bytes
56 bytes from 172.17.0.5: icmp_seq=0 ttl=64 time=0.267 ms
56 bytes from 172.17.0.5: icmp_seq=1 ttl=64 time=0.250 ms
56 bytes from 172.17.0.5: icmp_seq=2 ttl=64 time=0.256 ms
注:我们不得不安装ping,因为容器内没有它。
我们使用ping命令来pingdb容器,使用它解析到127.17.0.5主机。我们可以利用这个主机项配置应用程序来使用我们的db容器。
注:你可以使用一个父容器连接多个子容器。例如,我们可以有多个web容器连接到我们的db数据库容器。
Docker管理容器数据
Docker管理数据的两种主要的方法:
数据卷容器
数据卷是指在存在于一个或多个容器中的特定目录,此目录能够绕过Union File System提供一些用于持续存储或共享数据的特性。
数据卷可在容器之间共享或重用
数据卷中的更改可以直接生效
数据卷中的更改不会包含在镜像的更新中
数据卷的生命周期一直持续到没有容器使用它为止
添加一个数据卷
你可以在docker run命令中使用-v标识来给容器内添加一个数据卷,你也可以在一次docker run命令中多次使用-v标识挂载多个数据卷。现在我们在web容器应用中创建单个数据卷。
$ sudo docker run -d -P --name web -v /webapp training/webapp python app.py
这会在容器内部创建一个新的卷/webapp
注:类似的,你可以在Dockerfile中使用VOLUME指令来给创建的镜像添加一个或多个数据卷。
挂载一个主机目录作为卷
使用-v,除了可以创建一个数据卷,还可以挂载本地主机目录到容器中:
$ sudo docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py
这将会把本地目录/src/webapp挂载到容器的/opt/webapp目录。这在做测试时是非常有用的,例如我们可以挂载宿主机的源代码到容器内部,这样我们就可以看到改变源代码时的应用时如何工作的。宿主机上的目录必须是绝对路径,如果目录不存在docker会自动创建它。
注:出于可移植和分享的考虑,这种方法不能够直接在Dockerfile中实现。作为宿主机目录——其性质——是依赖于特定宿主机的,并不能够保证在所有的宿主机上都存在这样的特定目录。
docker默认情况下是对数据卷有读写权限,但是我们通过这样的方式让数据卷只读:
$ sudo docker run -d -P --name web -v /src/webapp:/opt/webapp:ro training/webapp python app.py
这里我们同样挂载了/src/webapp目录,只是添加了ro选项来限制它只读。
将宿主机上的特定文件挂载为数据卷
除了能挂载目录外,-v标识还可以将宿主机的一个特定文件挂载为数据卷:
$ sudo docker run --rm -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash
上述命令会在容器中运行一个bash shell,当你退出此容器时在主机上也能够看到容器中bash的命令历史。
注:很多文件编辑工具如vi和sed --in-place会导致inode change。Docker v1.1.0之后的版本,会产生一个错误:“sed cannot rename ./sedKdJ9Dy: Device or resource busy”。这种情况下如果想要更改挂载的文件,最好是直接挂载它的父目录。
创建、挂载数据卷容器
如果你想要容器之间数据共享,或者从非持久化容器中使用一些持久化数据,最好创建一个指定名称的数据卷容器,然后用它来挂载数据。
让我们创建一个指定名称的数据卷容器:
$ sudo docker run -d -v /dbdata --name dbdata training/postgres echo Data-only container for postgres
你可以在另外一个容器使用--volumes-from标识,通过刚刚创建的数据卷容器来挂载对应的数据卷。
$ sudo docker run -d --volumes-from dbdata --name db1 training/postgres
可以将对应的数据卷挂载到更多的容器中:
$ sudo docker run -d --volumes-from dbdata --name db2 training/postgres
当然,您也可以对一个容器使用多个--volumes-from标识,来将多个数据卷桥接到这个容器中。
数据卷容器是可以进行链式扩展的,之前的dbdata数据卷依次挂载到了dbdata 、db1和db2容器,我们还可以使用这样的方式来将数据卷挂载到新的容器db3:
$ sudo docker run -d --name db3 --volumes-from db1 training/postgres
即使你删除所有de 挂载了数据卷dbdata的容器(包括最初的dbdata容器和后续的db1和db2),数据卷本身也不会被删除。要删在磁盘上删除这个数据卷,只能针对最后一个挂载了数据卷的容器显式地调用docker rm -v命令。这种方式可使你在容器之间方便的更新和迁移数据。
备份、恢复或者迁移数据卷
数据卷还可以用来备份、恢复或迁移数据。为此我们使用--volumes-from参数来创建一个挂载数据卷的容器,像这样:
$ sudo docker run --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
这里我们启动了一个挂载dbdata卷的新容器,并且挂载了一个本地目录作为/backup卷。最后,我们通过使用tar命令将dbdata卷的内容备份到容器中的/backup目录下的backup.tar文件中。当命令完成或者容器停止,我们会留下我们的dbdata卷的备份。
然后,你可以在同一容器或在另外的容器中恢复此数据。创建一个新的容器
$ sudo docker run -v /dbdata --name dbdata2 ubuntu /bin/bash
然后在新的容器中的数据卷里un-tar此备份文件。
$ sudo docker run --volumes-from dbdata2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar
你可以对熟悉的目录应用此技术,来测试自动备份、迁移和恢复。