第05课:Docker使用入门(下)

第05课:Docker使用入门(下)

Docker 数据管理

还记得吗?在前一篇文章中,我们为了说明“镜像是静态的”这个概念,在容器里创建了一个文件“test.py”,然后把我们的容器提交成了一个新的镜像。然后,在那篇我们文章也提到了在容器里直接写入数据是很不好的习惯,那么,如果想在容器里面写入数据,该怎么做呢?这一小节我们就来解决这个问题。

Docker 数据管理主要有两种方式:数据卷数据卷容器。下面我们会分别展开介绍。

数据卷(Data Volume)

数据卷的使用其实和 Linux 挂载文件目录是很相似的。简单来说,数据卷就是一个可以供容器使用的特殊目录

  • 创建一个数据卷

在运行 Docker run 命令的时候使用 -v 参数为容器挂载一个数据卷:

sudo docker run -ti --name volume1 -v /myDir ubuntu:16.04 bash

可以发现我们的容器里面有一个 myDir 的目录,这个目录就是我们所说的数据卷:

enter image description here

  • 删除一个数据卷

数据卷是用来持久化数据的,所以数据卷的生命周期独立于容器。所以在容器结束后数据卷并不会被删除,如果你希望删除数据卷,可以在使用 docker rm 命令删除容器的时候加上 -v 参数。

值得注意的是,如果你删除挂载某个数据卷的所有容器的同时没有使用 -v 参数清理这些容器挂载的数据卷,你之后再想清理这些数据卷会很麻烦,所以在你确定某个数据卷没有必要存在的时候,在删除最后一个挂载这个数据卷的容器的时候,使用 -v 参数删除这个数据卷。

enter image description here

  • 挂载一个主机目录作为数据卷

当然,你也可以挂载一个主机目录到容器,同样是使用 -v 参数。

sudo docker run -ti --name volume2 -v /home/zsc/Music/:/myShare ubuntu:16.04 bash

以上指令会把宿主主机的目录 /home/zsc/Music 挂载到容器的 myShare 目录下,然后你可以发现我们容器内的 myShare 目录就会包含宿主主机对应目录下的文件:

enter image description here

Docker 挂载数据卷的默认权限是读写,你可以通过 :ro 指令为只读

sudo docker run -ti --name volume2 -v /home/zsc/Music/:/myShare:ro ubuntu:16.04 bash

直接挂载宿主主机目录作为数据卷到容器内的方式在测试的时候很有用,你可以在本地目录放置一些程序,用来测试容器工作是否正确。当然,Docker 也可以挂载宿主主机的一个文件到容器,但是这会出现很多问题,所以不推荐这样做。如果你要挂载某个文件,最简单的办法就是挂载它的父目录。

数据卷容器(Data Volume Container)

所谓数据卷容器,其实就是一个普通的容器,只不过这个容器专门作为数据卷供其它容器挂载

首先,在运行 docker run 指令的时候使用 -v 参数创建一个数据卷容器(这和我们之前创建数据卷的指令是一样的):

sudo docker run -ti  -d -v /dataVolume --name v0 ubuntu:16.04

然后,创建一个新的容器挂载刚才创建的数据卷容器中的数据卷:使用 --volumes-from 参数

 sudo docker run -ti --volumes-from v0 --name v1 ubuntu:16.04 bash

然后,我们的新容器里就可以看到数据卷容器的数据卷内容:

enter image description here

注意:

1、数据卷容器被挂载的时候不必保持运行!

2、如果删除了容器 v0 和 v1,数据卷并不会被删除。如果想要删除数据卷,应该像本文1.1小节介绍的那样在执行 docker rm 命令的时候使用 -v 参数。

Docker 网络

准备工作

Ubuntu 的官方 Docker 镜像默认没有安装 ping,ifconfig 等网络工具,但是本文为了讲解 Docker 容器的网络使用需要这些工具的辅助。为了跟随本教程的内容,需要创建一个具备一定网络功能的镜像(目前我们依旧使用从容器提交镜像的方法创建镜像,关于如何使用 dockerfile 创建镜像的方法会在下一篇文章介绍)。

首先从之前的 Ubuntu:16.04 创建一个容器:

sudo docker run -ti --name Exercise ubuntu:16.04 bash

进入之后依次执行下述命令:

apt-get update
apt-get install vim
apt-get install net-tools
apt install iputils-ping 
apt install apache2
apt install apache2-utils
apt install openssh-server
apt install openssh-client

之后使用 vim 修改:

vim /etc/ssh/sshd_config

把“PermitRootLogin”的内容改为 yes,保存。

输入:

passwd

输入你的 root 密码。(密码需要记好哦!

完成之后退出容器。使用 docker ps -a 找到你刚才运行的容器,找到之后从这个容器提交新镜像:

zsc@Berry:~$ sudo docker commit -m "My network exercise" Exercise net:v1.0

说明:

-m 是添加一个对镜像的简短说明,和 git 类似;

其后一个参数是刚刚容器的名字或者 ID;

最后是新镜像的名字:标签对。

Bingo! 我们已经准备好我们的新镜像喽,后面的教程我们将使用这个 net:v1.0 镜像运行容器!

端口暴露

我们可以使用 -p 参数执行端口映射,格式如下:

-p hostPort:containerPort 映射所有 IP 地址上的指定端口到容器内部

-p ip:hostPort:containerPort 映射指定 IP 地址上的指定端口到容器内部

-p ip::containerPort 映射指定 IP 地址上的任意端口到容器内部

现在,我们来举个例子看看端口映射到底是什么:

sudo docker run -ti --name web -p 80:80 net:v1.0 bash

这条命令启动了一个容器,映射宿主主机所有 IP 的80端口到容器的80端口。

然后,在容器里面启动 Apache 服务(之前的准备工作中,我们已经安装好了 ApacheWeb 服务器,它提供了一个默认网页),容器里面运行如下指令:

apache2ctl start

然后查看容器的 IP 地址是“172.17.0.2”(你的 IP 可能有所不同):

enter image description here

此时,打开你的宿主主机(即安装 Docker 的计算机)上的浏览器,输入 IP 地址就可以访问 Apache 服务器的默认主页了:

enter image description here

然后,使用 ifconfig 命令查看宿主主机的 IP 地址,我的宿主主机有2个 IP,一个是无线网 IP: 10.192.19.12,一个是有线网 IP:223.3.48.163,如果你有另一台在同一局域网的设备,比如你的手机,你可以访问这两个 IP,发现都可以访问 Apache 服务器主页:

enter image description here

通过这个例子,你应该对端口暴露有一个比较明白的理解了。当然,端口暴露不仅仅可以用来把容器作为 Web 服务器使用,还可以通过网络让不同容器之间相互通信,Docker 默认使用 TCP 协议在容器之间进行网络通信,如果你需要 UDP,可以使用如下格式指定:

sudo docker run -ti --name web -p 80:80/udp net:v1.0 bash

容器互联

容器互联可以不用端口映射就可以让容器之间进行交互。容器互联会在源容器和接收容器之间创建一条安全隧道,接收容器可以看到源容器的信息。

首先,创建一个源容器:

sudo docker run -ti --name source net:v1.0 bash

然后运行另一个容器,使用--link 参数连接第一个容器:

sudo docker run -ti --name receiver --link source:sender net:v1.0 bash

这里的 --link source:sender 的意思是把名字为 source 的容器链接到别名 sender,然后你就可以在第二个容器里以 sender 这个名字和第一个容器通信,比如 ping sender:

enter image description here

这是因为,系统把这个别名加入到了 /etc/hosts 里面:

enter image description here

ssh 登录容器

首先,运行一个容器:

sudo docker run -ti --name ssh -p 6667:22 net:v1.0 bash

然后在容器里面启动 ssh 服务:

service ssh start

查看我们的容器的 IP 地址:

ifconfig

enter image description here

然后再新的终端里面运行:

ssh root@172.17.0.3

然后就顺利进入容器了:

enter image description here

Docker 网络——再进一步

本小节主要讲一点 Docker 网络的高级用法。

当 Docker 启动的时候,会在宿主主机上面创建一个名字为 docker0 的虚拟网桥,相当于一个软件交换机,并且,Docker 会随机分配一个未被占用的私有网段给 docker0 接口(具体原理在之后的“底层原理初探”讲解):

enter image description here

你可以使用 Docker 组建自己的虚拟局域网。在此之前,首先看看 Docker 默认为我们创建的三个网络:bridge,none,host:

enter image description here

其中,bridge 是默认的网络模式docker0 是默认的网络,当我们在运行容器的时候,如果没有显式指定网络,那么我们的容器会被默认添加到 docker0 网络中,docker0 的模式正是 bridge。在我的电脑上,docker0 的网址是172.17.0.1,所以我们添加到 docker0 网络的容器的网址都是172.17.0.x。

none 模式翻译过来就是“无网络模式”,加到这个网络模式中容器,无法进行网络通信,我一般不使用。

host 模式将容器网络与宿主主机的网络直接相连通,这听起来不错,但是却破坏了容器的网络隔离,一般我也很少使用。

下面,我们主要说明一下 bridge 模式的使用。虽然 Docker 为我们创建了一个 docker0 的默认网络,但是有时候我们希望定义自己的网络,使用如下指令可以创建一个名为 mynet 的网络:

sudo docker network create --driver bridge mynet

命令解释:

  • -driver后面的一项是网络模式,这里我们选 bridge;

最后一项 mynet 是我们网络的名字。

下面,使用 ifconfig 发现我们多了一个网络:

enter image description here

现在,我们运行一个容器,并使用 --net 参数把这个容器添加到我们的 mynet 网络:

sudo docker run -ti --name netcontainer --net mynet net:v1.0 bash

使用这种方式,我们可以把容器添加到自定义网络。

删除网络指令:

sudo docker network rm mynet

Docker 可以通过 docker0 或者你自定义的网络桥接,让容器通过宿主主机的网络访问外部互联网,但是访问外部互联网还需要 DNS 配置,那么容器的 DNS 是怎么配置的呢?

其实,容器通过默认挂载宿主主机的3个相关配置文件来使用宿主主机的 DNS 配置,在容器里面使用 mount 命令可以看到相关信息:

enter image description here

这样,当宿主主机 DNS 信息发生变化的时候,容器的 DNS 配置会通过 /etc/resolv.conf 文件立刻得到更新。

如果你希望自己配置 DNS 信息,可以在使用 docker run 命令的时候加上 --hostname=HOSTNAME 参数设定容器的主机名,使用 --dns=IP_ADDRESS 添加 DNS 服务器到容器的 /etc/resolv.conf 文件中。

好了,关于 Docker 网络我们目前就介绍这么多。更多的使用方法需要读者在使用过程中根据自己的需要慢慢探索,故不在我们这个入门课程作过多介绍。

接下来做什么?

本文主要介绍了数据卷和 Docker 网络的使用,接下来我们会讲解如何使用 dockerfile 定制自己的镜像,以及简单介绍 Docker 的底层原理。

上一篇
下一篇
目录