作为初级开发人员的你,是不是参加过这样的面试,在面试中面试官希望你准确地回答Docker的工作原理?现今的面试官们希望应聘者能够深入了解8项、10项、甚至更多的技术。其实这有点疯狂。在大学或其他学校里,他们很可能根本不会教你任何关于Docker的知识。然而,如果你真的能够深入了解Docker,那么你就可以从一大群应聘者中脱颖而出。
当你开始使用Docker时,首先会遇到的问题之一是你无法连接到Docker容器。这篇文章将详细解释这个问题为什么会发生,同时我也会解释端口绑定(port binding)是如何工作的。
即使你是一个经验丰富的开发人员,你也应该了解什么是端口绑定。否则,你在面试时会显得很傻。如果你还没有了解,那么现在就给自己拿杯咖啡。我一定会让你把你想知道的关于这个话题的一切内容都记在你的脑子里,只需要花费你六分钟!
让我们从一个Nginx Docker容器开始吧!
如果你对Docker有一点点了解的话,你就无需担心了。因为我会尽量详细地解释关于Docker的一切。首先,我需要确保你理解Docker容器和Docker镜像之间的区别。
你可以把Docker镜像看作一个文件,它包含了运行一个特定程序的所有依赖项和配置。为什么要这样做?因为Docker想要解决的首个问题就是系统/程序安装的噩梦。
我们都经历过在Windows、Mac或Linux系统上安装程序的情况。然而令人沮丧的是,系统每次都会提示你缺少另一个程序。就像下面系统提示你要不要安装的那样,我猜你每次遇到这个问题都会选择安装,对吧?
你也要安装这个程序吗?…
最终你会发现,你不但需要安装很多不同的程序,而且经常还需要配置系统变量等等。在最坏的情况下,这些会把你的系统弄得一团糟。
你一定不希望你组织里的每个人都经历这种麻烦,对吗?
Docker镜像可以帮助你解决这个麻烦,因为一个Docker镜像里包含了安装程序所需的所有内容。而Docker容器则是Docker镜像的运行实例。
Docker为你解决了安装的噩梦。而Docker容器包含了它运行时所需要的一切,不多也不少。你可以在Windows、Linux或Mac上运行一个Docker容器。基本上,只要你将Docker安装好,你就可以在任何地方运行它。
关于Docker的优势已经讲得够多了。接下来,我们要做的是让一个Docker容器开始运行起来。
让我们从一个Nginx Docker容器开始。Nginx是一个运行在端口80上的web服务器。下面,我将使用Nginx Docker镜像以分离模式(后台运行)启动一个Docker容器,命令如下:
docker container run -d nginx
这个命令将会生成一个新的Docker容器,你会看到这个新的Docker容器的UUID。如果你不知道UUID是什么,那么请认真阅读我写的这篇文章中的所有内容。使用Docker容器的ps命令(docker ps),你将看到这个Docker容器处于活跃状态:
现在,如果你试图使用curl命令或使用一个浏览器直接连接到这个Docker容器,你会遇到连接失败的错误(见下面)。因为你不能直接连接到一个Docker容器,原因是什么呢?Docker的文档只是解释说端口80易受攻击…这个解释有点不明不白。但是别担心,我会在下一节详细给出解释!
为什么我不能直接连接到一个Docker容器?
事实上,Docker容器可以在不作任何配置的情况下连接到外部世界。这一点太好了,因为这样我们就不必改变我们以前编程过的任何东西。
但是默认地,外部世界无法直接连接到一个Docker容器。
说到这里,我想你应该明白了,这一点和我们预想的不同。那么你应该如何连接到你的Docker容器呢?好吧,有多种选择。让我们探索一下。
1. 公开Docker的所有端口
docker container run -P -d nginx
这里的-P命令打开容器公开的每个端口。Docker会标识在Dockerfile中公开的每个端口,以及使用带有--expose 参数的Docker container build命令公开的每个端口。每个公开的端口都直接绑定在主机的一个“随机”端口上。
听起来不错,但是我们现在该怎么找到这些端口呢?别担心,我们会找到你心爱的端口的,甚至有多种方法可以帮助找到它们。接下来我将向你展示两种不同的方法:
Docker container port
netstat
我们的第一个选择是使用上面的Docker命令(docker container port)。你只需要键入上面的命令和容器UUID。你就会看到Docker容器的端口80绑定到了IP地址为0.0.0.0的主机端口32768上(如果你自己尝试执行该命令,则会看到一个不同的端口)。
docker container port *insert container_uuid*80/tcp -> 0.0.0.0:32768
我们的另一个选择是使用netstat命令。要查找所有打开的端口,你可以执行以下命令。注意,Docker公开的端口混杂在其他端口中间,本例中第三行的那个端口就是我们要找的。
netstat -ntlp
2. 公开一个特定端口
端口绑定示例:将Docker容器的80端口绑定到主机的8080端口上。
公开所有Docker端口通常不是一个好主意,默认情况是根本不公开任何端口,这是为了安全起见。你不想公开一切,因为这样做根本没有任何好处,对吧?
如果你只想公开一个端口,请执行以下命令:
docker container run -p 8080:80 -d nginx
这个命令使得Nginx容器的80端口通过主机端口8080对外公开。现在,我们就可以通过多种方式连接到容器。例如,使用curl命令或通过一个浏览器。这是不是太棒了!
恭喜你,现在你终于明白了Docker端口绑定最重要的部分了!下面我将向你展示curl命令执行的结果:
curl -I 0.0.0.0:8080HTTP/1.1 200 OKServer: nginx/1.17.9Date: Sun, 08 Mar 2020 11:38:47 GMTContent-Type: text/htmlContent-Length: 612Last-Modified: Tue, 03 Mar 2020 14:32:47 GMTConnection: keep-aliveETag: "5e5e6a8f-264"Accept-Ranges: bytes
如果你在浏览器中访问这个地址:0.0.0.0:8080,那么你的浏览器会向你展示如下的内容:还有一件事
默认情况下,Docker会将容器端口公开到IP地址0.0.0.0(这个地址和系统上的任何IP都匹配)上。你也可以告诉Docker要绑定哪个IP,这个IP可以是127.0.0.1,也可以是其他IP地址。
如果你想将Docker容器的80端口绑定到主机系统端口8000和IP地址127.0.0.1(也称为本地主机)上,你只需运行以下命令:
docker run -d -p 127.0.0.1:8000:80 nginx
结束语
对于使用Docker容器来说,Docker的端口绑定是一个很重要的概念。一开始可能因为需要配置传入连接(incoming connection)的问题,会让人困惑。但是Docker在提供所有需要的文档方面做得很出色。
不过,作为开发者,有些Docker的概念比其他概念更难理解。希望读完这篇文章后,你对Docker端口绑定已经很清楚了。