docker 网关
随着您作为开发人员的发展而进步,您迟早会了解像Docker这样的容器系统所提供的好处:您可以在代码中指定您的环境,而无需向系统工程师发送所有Slack消息,也不会造成麻烦站立一致配置的服务器。 同样,您可能已经了解了微服务的吸引力,因为微服务是解决其自身债务缠身的整体应用程序问题的解决方案。
本文提供了一些有关如何在微服务的开发流程中利用Docker的见解。
Docker支持隔离微服务
微服务本身的开发应该相当简单。 从环境的角度来看,开发一个应用程序与开发更传统的应用程序应该没有什么不同。 也许您的微服务需要支持一个或两个API端点-您需要它连接到MySQL或Redis等几个数据模型,然后您才能快速开始竞赛。 这是Docker 101的东西。 您可以利用受支持的现有Docker项目,例如Laradock或NoDock (分别用于PHP和Node.js),它们为开发人员提供了集成的Docker环境,该环境支持通过docker-compose联网在一起的一系列常用技术。
快速提醒
我想给使用Docker的任何人的第一个提示是,它的发展速度非常快:即使是最近的课程也可能涉及已经不推荐使用的命令或实用程序( 例如 docker-machine
)。 准备稍微咬一下牙,挠头并浏览一些不熟悉的错误消息。 但是,一旦您越过了保镖,就值得拥有Docker俱乐部的会员资格。
Docker独立版
当然,在开始之前,请确保您的计算机上已安装Docker工具箱。 请访问Docker.com以下载适用于您的主机操作系统的客户端(CE社区版适用于我们的目的)。
如果您需要运行特定技术(例如脚本语言或操作系统),则很有可能有人已经为其创建了Docker映像。 在重用他人慷慨共享的代码时, DockerHub是您的朋友。 切记: 不要重新发明轮子! 请注意,出于某种原因,该站点被标记为搜索容器 ,而实际上是在搜索图像 。 请记住:容器是模板-可以从单个图像模板创建多个容器实例。
简而言之,您的交互应围绕克隆容器(使用clone
命令),然后运行其实例(使用run
命令)进行。 例如,这是获取PostGres的工作副本所需要做的一切:
docker pull postgres
docker run --name some-postgres -e POSTGRES_PASSWORD=mysecretpassword -d postgres
如果您查看任何容器的相应Git存储库,则其Dockerfile
包含从映像构建容器实例所需的步骤, 例如 PostGres容器。
通常,Dockerfile中的第一条指令使用FROM
命令:这扩展了命名容器,因此您可以从一开始就看到,极大地激励了作者重用现有映像。
Docker撰写
在许多情况下,您会发现将单独的Docker容器连接在一起非常有用。 如果您的应用程序需要特定版本PHP和特定版本的PostGres,则没问题:找到每个的Docker映像,并在docker-compose.yml
文件中引用它们。
对于许多用例, docker-compose
将是将容器捆绑在一起的最重要的单个工具。 对于每个微服务,您将能够引用新的和现有的Docker映像,并通过docker-compose.yml
文件定义它们之间的关系。
例如,这是我们如何定义一种环境以在NGINX Web服务器上支持PHP 7和PostGres。 假设此处的存储库根目录具有composer.json
和一个名为public/
公共Web文件的文件夹。
# PHP + PostGres microservice docker-compose.yml
version: '2'
services:
nginx:
image: nginx:1.13-alpine
ports:
- 3000:80
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
web:
# This build command is what
# builds the neighboring Dockerfile
build: .
ports:
- 9000:9000
volumes:
- .:/var/www
- /var/www/vendor
depends_on:
- postgres
environment:
DATABASE_URL: postgres://todoapp@postgres/todos
postgres:
image: postgres:9.6.2-alpine
environment:
POSTGRES_USER: todoapp
POSTGRES_DB: todos
其中大多数是端口映射和卷映射。 PHP在哪里? 它在build: .
过程中有些模糊build: .
命令。 更详细地说,该命令运行docker build .
,因此预计该Dockerfile
docker-compose.yml
文件旁边将有一个Dockerfile
。 PHP Dockerfile
可能看起来像这样:
FROM php:7.1-fpm-alpine
RUN apk update && apk add build-base
RUN apk add postgresql postgresql-dev \
&& docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql \
&& docker-php-ext-install pdo pdo_pgsql pgsql
RUN apk add zlib-dev git zip \
&& docker-php-ext-install zip
RUN curl -sS https://getcomposer.org/installer | php \
&& mv composer.phar /usr/local/bin/ \
&& ln -s /usr/local/bin/composer.phar /usr/local/bin/composer
# References the virtual path
COPY . /var/www
WORKDIR /var/www
RUN composer install --prefer-source --no-interaction
ENV PATH="~/.composer/vendor/bin:./vendor/bin:${PATH}"
根据您的需求,您可能完全不用Dockerfile
就能摆脱Dockerfile
。 可以docker-compose.yml
而不是build
命令来引用image
,但是由于PHP是使用的服务器端语言,因此很有可能需要进行一些自定义。 在Dockerfile
最容易发生这种情况,因此通过build
属性引用它可能是最好的方法。
您需要的最后一件事是NGINX配置文件。 这样的事情就足够了:
server {
listen 80;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/public/;
location / {
try_files $uri /index.php$is_args$args;
}
location ~ ^/.+\.php(/|$) {
fastcgi_pass web:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
如果您注意在docker-compose.yml
中完成的映射,其中存储库根目录对应于容器内的/var/www/
,则可以看到,如所写,它期望nginx.conf
文件位于存储库的根。
很容易被nginx.conf
文件中的虚拟路径混淆,因此您必须将其与docker-compose.yml
进行比较。 具体来说,它已映射.
(存储库根目录)到虚拟机上的/var/www
。 因此,NGINX从这一点开始接手,并将其Web根目录定义为/var/www/public/
-这是您存储库中的public/
文件夹。
要下载这些图像并将其构建到容器中,您可以运行docker-compose up
。 下载和构建图像可能需要一些时间,但是如果一切顺利,您应该可以在http://localhost:3000
上运行新PHP应用程序。
种子数据
在开发微服务时,您将要编写测试。 当使用像Docker这样的技术可以轻松,一致地启动相关服务时,您应该认识到一个很好的机会来创建彻底的集成和功能测试,这些测试基于精选的种子数据集合进行。
当您可以访问真实的数据库并获得真实的响应时,为什么仅依靠单元测试和模拟服务呢? 尽管设置起来比较费力,但是集成测试的优点是它们更彻底-有时会出现无法覆盖的惊喜和细微差别。
在这种情况下,要进行测试运行,首先要重新启动容器,然后将整理的种子数据加载到容器中。 这确实比执行简单的单元测试要花费更长的时间,但是它不应该像浏览器自动化或其他最终用户测试那样慢。
执行种子操作的最简单方法之一是使用docker-compose
的exec
函数,该函数在命名容器中执行命令。 例如,如果我们PHP应用程序是Laravel应用程序,则可以利用其工匠命令行工具来迁移和播种数据库。
docker-compose exec web php artisan migrate
无论使用哪种语言,都应该有一种可行的方法来支持数据库迁移,并为集成测试提供一些可行的种子数据来为数据库提供种子。
注册免费的Codeship帐户
用于API网关的Docker
当您退后一步并开始从事API网关本身的开发时,或者如果您需要处理与多种数据源进行交互的更复杂的服务时,最终可能会费尽心思生态系统中所有相互关联的应用程序的有效版本。
您的API Gateway应用程序的Docker映像可能与我们针对单个微服务所讨论的映像完全不同。 它需要某种环境来通过服务器端代码(也许是Go或Elixir)处理请求和响应,并且通常将其附加到身份验证/授权服务,以便可以在将请求代理到微服务之前对其进行验证。
这可能就足够了:您可以像在任何微服务应用程序内部一样地测试API网关内部的任何权限逻辑或错误处理。 如果您为身份验证服务添加了种子,则可以测试是否为每个路由强制实施了适当的权限。 您还可以验证传入请求已代理到特定服务,并且可以根据需要模拟响应。
但是,这并不代表端到端测试。 如果我们想确保特定的请求产生特定的响应,我们将不得不做得更好。 这就是我们回到Docker和Docker Compose的地方。
如果我们将docker-compose.yml
用作关于微服务的“记录文档”,您可以轻松地想象它可能会列出大量服务( 例如 ,每个微服务一个)。 如果每个服务都是作为Docker映像构建的,那么您可以将这些映像作为公共(或私有)存储库发布在Docker Hub上 ,以便其他开发人员可以轻松地克隆和构建应用程序所需的容器。
专用测试图
解决种子数据和运行集成测试问题的一种解决方案是为该任务创建专用的Docker映像。 该Docker映像可能会充分利用depends_on
docker-compose.yml
文件中的depends_on
关键字。 用于编写测试的语言可能是最适合手头任务的一种语言:测试。 只要您可以轻松地用种子数据填充数据模型,并编写使用HTTP请求到达API网关的测试,就可以使用。
完全有可能将这些测试与API网关放在相同的映像和代码库中,但是对于许多用例,将它们分开可能更有意义。 最重要的是,对测试或种子数据的任何更改都不需要升级和部署API网关本身。 其次,API网关的语言可能不适用于编写测试或使用种子数据填充模型。 因此,拥有一个专门的任务图像应该有助于隔离变更并提供最佳的工作工具。
这种安排有时可能需要更多的人力,但是它确实促进了代码和服务以及环境本身的测试驱动开发和良好的测试覆盖率。 如果我们将每个微服务视为应用程序“主体”中的某种处置“单元”,那么将集成测试和随之而来的种子数据与微服务分开是很有意义的。
在某种程度上,这在网关与其微服务之间提供了牢固的契约。 如果您更新服务或将其完全替换,则集成测试将为您提供确保更改兼容的可靠保证。
结论
这只是刮擦了网络,填充和测试互连微服务可能遇到的复杂性的表面。 本文概述的方法已经暗示了在某些情况下可能会出现的一些缺点,因此您可能已经了解了诸如Kubernetes之类的其他技术对您有何用处。 希望它为您提供了一些有关如何为自己的应用程序环境解决其中一些问题的想法。
翻译自: https://www.javacodegeeks.com/2018/01/using-docker-api-gateway-microservice-development.html
docker 网关