docker 多层 镜像
背景
尽管目前有很多非常好的Docker教程,但我发现很多教程要么在提供的场景中过于简单,要么在某些情况下太过复杂了。 因此,我决定编写自己的教程,描述使用Docker配置的多层架构。
先决条件
本教程假定您已成功安装Git和Docker。 我在Mac上运行Boot2Docker,这使Docker可以像在Mac上本地安装一样运行(在PC上,Boot2Docker并不那么简单)。 我假设对Docker有一定的基本了解(很好的信息来源是https://docs.docker.com/articles/basics/ )。
情境
我为本教程开发的场景如下所示:
如您所见,它涉及多个层次:
MongoDB :这是我们的持久层,其中将填充一些代表客户的演示数据。
API服务器 :此层代表Restful API服务。 它公开了打包为JSON的mongo数据(就本教程而言,它实际上并未使用通常会出现的任何业务逻辑)。 该层是使用Spring Web Services和Spring Data用Java开发的。
WebClient :这是一个非常简单的层,演示了用Google的Polymer UI框架编写的Web应用程序。 所有业务逻辑都驻留在Javascript中,然后使用CORS隧道从服务层访问API数据。
我不会在每个层的实现上花费很多时间,因为它与本Docker教程的目的无关。 我将简要介绍一些代码逻辑,只是为了设置上下文。 让我们开始看看持久层是如何配置的。
MongoDB配置
注意:该层的项目代码位于: https : //github.com/dajevu/docker-mongo 。
Dockerhub包含mongo的正式映像,我们将以此为起点( https://registry.hub.docker.com/u/dockerfile/mongodb/ )。 万一我们需要基于此映像中安装的内容,我决定通过简单地复制其Dockerfile(映像可以是二进制文件,也可以通过文本Dockerfile声明性地)来克隆映像。 这是Dockerfile:
第5行标识用于mongo安装的基本映像-这是官方的dockerfile / ubuntu映像。 由于未指定任何版本,因此我们正在获取最新版本。
注意 :Dockerfiles中的注释以#开头。
第8行开始安装mongo数据库以及一些其他工具,例如s curl,git等。Ubuntu的apt-get是Ubuntu的标准软件包管理工具。
第16和18行为mongo数据库文件所在的位置设置了一些挂载点(以及git挂载点,以备日后使用)。 在第21行,我们将工作目录设置为该数据安装点位置(从第16行开始)。
最后,我们确定Mongo需要暴露的一些端口(第27和28行)。
假设您已从我的git存储库( https://github.com/dajevu/docker-mongo )中获取了代码,则可以通过运行脚本runDockerMongo.sh
来启动启动此Docker映像(在Windows Boot2Docker中,您需要在运行Docker的VM容器中获取代码)。 该脚本仅包含以下内容:
docker run -t -d -p 27017:27017 --name mongodb jeffdavisco/mongodb mongod --rest --httpinterface --smallfiles
运行时,它将使用目录中存在的Dockerfile启动容器。 您可以使用docker ps
命令确认它正在运行:
从上面可以看到,在这种情况下,它使用4fb383781949
容器ID启动了Mongo。 获得容器ID后,您可以使用以下方法查看容器的服务器日志:
docker logs --tail="all" 4fb383781949 #container Id
如果您看不到docker ps的任何结果,则意味着该容器已启动但随后立即退出。 尝试发出命令docker ps -a-
这将标识失败服务的容器ID,然后您可以使用docker logs
来确定出了什么问题。 在使用docker rm
启动新容器之前,您需要删除该容器。
Mongo容器运行后,我们现在可以用一些演示数据填充它,这些数据将用于API服务层。 项目文件中存在一个名为northwind-mongo-master
目录,该目录包含一个名为mongo-import-remote.sh
的脚本。 让我们看一下该文件的内容:
该脚本仅运行目录中存在的每个.csv文件,并使用mongoimport
实用程序加载集合。 但是,有一点皱纹。 由于mongoimport
正在连接到远程mongo数据库,因此需要远程主机的IP地址,并且此远程主机是刚启动的mongo容器。 如何确定要使用的IP地址? 如果您使用的是Boot2Docker,则可以简单地运行boot2docker ip
–这将为您提供所使用的Docker主机的IP地址。 如果直接在运行Docker的主机中运行,则可以通过localhost作为您的IP地址进行连接(因为该端口在启动容器时公开给Docker主机)。
为了加载测试数据,请更新该脚本,使其具有适合您的环境的IP地址。 然后,您可以运行脚本( mongo-import-remote.sh
),它将使用示例数据填充mongo数据库。 如果您使用的是MongoHub,则可以连接到远程mongo主机,并查看以下可用集合:
幸运的是,我们不必在剩余的容器上经历这些障碍。
API服务层配置
API服务是一个非常简单的基于Restful的Web服务,它仅以JSON格式公开了一些mongo数据(当然,您可以通过其Restful API直接访问mongo,但是在大多数实际情况下,您永远不会公开曝光)。 用Java Spring编写的Web应用程序使用Spring数据库访问远程mongo数据库。
该层的项目文件位于: https : //github.com/dajevu/docker-maven-tomcat 。 虽然我不会介绍所有Spring配置/设置(毕竟,这不是Spring演示),但让我们简要看一下将具有公开Web服务的主要服务类:
使用Spring Web服务的Spring注释,我们在第5行中对该控制器进行注释,以便Spring可以使用基本URL /customer
公开后续服务。 然后,我们定义一种方法,该方法用于公开Mongo集合中的所有客户数据。 CustomerDAO
类包含与Mongo接口的逻辑。
让我们看一下用于运行此Web服务的Dockerfile(使用Jetty作为Web服务器):
如您所见,在第2行中,我们将API服务的基本映像标识为Java 7映像。 类似于mongo Dockerfile,我们在第8-15行中要做的下一步是安装各种必需的依赖项,例如git,maven和mongo客户端。
然后,与我们的mongo Dockerfile不同,我们使用git安装我们的Java Web应用程序。 这是在第21至26行中完成的。我们为源文件创建一个位置,然后使用git clone安装它们。 最后,在第28行,我们的shell脚本名为run.sh
让我们看一下脚本的内容:
#!/bin/bash
echo `env`
mvn jetty:run
如您所见,这非常少。 我们首先从此容器中回显环境变量,以便出于故障排除的目的,在检查docker日志时可以看到它们。 然后,我们只需使用mvn jetty:run
启动Web应用程序。 由于已经通过git clone
下载了应用程序的源代码,因此maven将自动编译webapp,然后启动jetty Web服务器。
现在,您可能想知道,Web服务如何知道如何连接到Mongo数据库? 当我们将Mongo数据库端口公开给docker主机时,如何在Java应用程序中定义连接,以使其指向正确的位置。 这是通过使用在两个容器之间指定依赖项/链接时自动创建的环境变量来完成的。 为了了解它是如何实现的,让我们看一下用于启动容器的启动脚本runDockerMaven.sh
:
docker run -d --name tomcat-maven -p 8080:8080
\ —link mongodb:mongodb jeffdavisco/tomcat-maven:latest
\ /local/git/docker-maven-tomcat/run.sh
如您所见, -link
选项用于通知docker该容器与另一个容器(在本例中为Mongo实例)具有依赖性。 如果存在,-link选项将创建一组环境变量,这些变量在启动容器时填充。 让我们使用docker logs命令检查这些环境变量的外观(记住,在启动此容器之前,必须先运行mongo容器):
MONGODB_PORT_28017_TCP_PROTO=tcp
HOSTNAME=f81d981f5e9e
MONGODB_NAME=/tomcat-maven/mongodb
MONGODB_PORT_27017_TCP=tcp://172.17.0.2:27017
MONGODB_PORT_28017_TCP_PORT=28017
MONGODB_PORT=tcp://172.17.0.2:27017
MONGODB_PORT_27017_TCP_PORT=27017
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/local/git/docker-maven-tomcat
MONGODB_PORT_27017_TCP_PROTO=tcp
JAVA_HOME=/usr/lib/jvm/java-7-oracle MONGODB_PORT_28017_TCP_ADDR=172.17.0.2 MONGODB_PORT_28017_TCP=tcp://172.17.0.2:28017
MONGODB_PORT_27017_TCP_ADDR=172.17.0.2
以MONGODB
开头的环境变量表示通过链接创建的环境变量。 怎么知道以MONGODB
为前缀? 这是因为,当我们启动mongo容器时,我们指定了可选的—name
参数,该参数为该容器提供了名称别名。
现在,如何将其整合到API服务中? 当定义用于访问mongo的Spring Data属性时,我们指定使用环境变量来标识主机。 这是在spring-data.xml
文件中完成的(位于项目代码中的src / main / resources下)。
threads-allowed-to-block-for-connection-multiplier="4"
connect-timeout="1000"
max-wait-time="1500"
auto-connect-retry="true"
socket-keep-alive="true"
socket-timeout="1500"
slave-ok="true"
write-number="1"
write-timeout="0"
write-fsync="true" />
因此,当我们启动容器时,所需runDockerMaven.sh
就是使用runDockerMaven.sh
启动它。 通过使用以下命令通过浏览器访问服务来确认该服务正在运行:
在您的环境中,如果您使用的是Boot2Docker,请运行boot2docker ip
以标识公开该服务的IP地址。 如果直接在Docker主机上运行,则应该能够指定localhost。 这应该带回一些JSON客户数据,例如:
现在,让我们看一下最后一个容器,该容器用于通过网页公开数据。
Web应用程序层
Web应用程序层由轻量级Python Web服务器组成,该服务器仅提供静态HTML页面以及相应的Javascript。 该页面使用Google的Polymer UI框架在浏览器中显示客户结果。 为了允许Polymer直接与API服务进行通信,在API服务器上配置了CORS以允许入站请求(我想使Web应用程序层尽可能轻便)。
注意:可以在以下位置找到该层的源代码/项目文件: https : //github.com/dajevu/docker-python
这是Javascript中进行远程调用的相关代码:
显然, url
属性中存在的VMHOST
值不是有效的域名。 相反,当启动Docker容器时,它将用API服务器的实际IP替换该值。 在深入了解这一点之前,让我们首先检查用于Python服务器的Dockerfile:
这个Dockerfile与我们一直在使用的其他文件非常相似。 像mongo容器一样,该容器基于ubuntu官方图片。 然后,我们在第11-14行中指定要加载Python和相关库。 在23-24行中,我们为git源代码准备了一个目录。 接下来,我们在第27行使用git clone提取代码,然后将工作目录设置到该位置(第28行)。 (实际上,第31行的CMD命令会被忽略,因为我们在启动脚本中指定了要运行的命令(即,它覆盖了Dockerfile中的命令)。
让我们看一下现在用于启动容器的启动脚本:
docker run -d -e VMHOST=192.168.59.103 --name python -p 8000:8000 \
--link tomcat-maven:tomcat jeffdavisco/polymer-python:latest \
/local/git/docker-python/run.sh
上面需要注意的几件事。 注意如何使用环境标志-e VMHOST=192.168.59.103
传递Boot2Docker实例的IP地址。 与配置API服务层时需要执行的操作类似,您必须针对您的环境进行修改(如果使用Boot2Docker,请运行boot2docker ip
以找到您的boot2docker ip
主机的IP地址,或者如果在Linux上本地运行,则可以使用本地主机)。 注意,我们正在做的另一件事是暴露端口8000,这是我们的Python Web服务器将在其下运行的位置。 最后,我们指示Docker容器运行run.sh
shell脚本。 接下来我们来看。
run.sh
脚本包含以下内容:
#!/bin/bash
# replace placeholder with actual docker host
sed -i "s/VMHOST/$VMHOST/g" post-service/post-service.html
python -m SimpleHTTPServer 8000
sed命令用于将VMHOST占位符令牌替换为启动时传递给$VMHOST
容器的环境变量( $VMHOST
)。 html文件更新后,我们将使用命令python -m SimpleHTTPServer 8000
启动python服务器。 运行启动脚本后,如果一切顺利,则应该能够在浏览器中访问: http://:8000
(其中dockeriphost
等于您的boot2docker ip地址,如果在Linux上则为本地docker主机)。 您应该看到类似以下内容:
您现在已经完成了本教程! 您有一个运行mongo的docker容器; 另一个正在运行API服务; 以及最后一个运行的简单Web服务。 我希望您喜欢本教程,并且希望对它进行后续介绍,以简短地描述如何使用fig可以更轻松地管理这些容器(在http://www.fig.sh/上了解更多信息 )。
翻译自: https://www.javacodegeeks.com/2015/02/multi-tier-architecture-tutorial-using-docker.html
docker 多层 镜像