Docker 项目
在本节中,我们将发布一个 springcloud/spring-cloud-contract
Docker 镜像,其中包含一个项目,该项目用于生成测试并在 EXPLICIT
模式下针对正在运行的应用执行这些测试。
EXPLICIT 模式意味着从契约生成的测试发送的是实际请求,而不是模拟请求。 |
我们还发布了一个 spring-cloud/spring-cloud-contract-stub-runner
Docker 镜像,该镜像启动 Stub Runner 的独立版本。
Maven、JAR 和二进制存储简介
由于非 JVM 项目可以使用此 Docker 镜像,因此最好解释一下 Spring Cloud Contract 打包默认设置背后的基本术语。
以下部分定义摘自Maven 词汇表
-
Project
(项目):Maven 以项目为单位进行思考。项目就是您构建的一切。这些项目遵循一个明确定义的“项目对象模型”。项目可以依赖其他项目——在这种情况下,后者被称为“依赖项”。一个项目可能包含多个子项目。然而,这些子项目仍然被平等地视为项目。 -
Artifact
(构件):构件是由项目产生或使用的东西。Maven 为项目生成的构件示例包括 JAR 文件以及源代码和二进制分发。每个构件都通过一个 group ID 和一个在组内唯一的 artifact ID 来唯一标识。 -
JAR
:JAR 代表 Java ARchive。其格式基于 ZIP 文件格式。Spring Cloud Contract 将契约和生成的存根打包在一个 JAR 文件中。 -
GroupId
:GroupId 是项目的全局唯一标识符。虽然这通常只是项目名称(例如,commons-collections
),但使用完全限定的包名有助于将其与名称相似的其他项目(例如,org.apache.maven
)区分开来。通常,发布到 Artifact Manager 时,GroupId
会用斜杠分隔,并构成 URL 的一部分。例如,对于 group IDcom.example
和 artifact IDapplication
,结果将是/com/example/application/
。 -
Classifier
(分类器):Maven 依赖表示法如下所示:groupId:artifactId:version:classifier
。分类器是传递给依赖项的附加后缀——例如,stubs
或sources
。同一个依赖项(例如,com.example:application
)可以生成多个构件,这些构件通过分类器彼此区分。 -
Artifact manager
(构件管理器):当您生成二进制文件、源代码或包时,您希望其他人可以下载、引用或重用它们。在 JVM 世界中,这些构件通常是 JAR。对于 Ruby,这些构件是 gem。对于 Docker,这些构件是 Docker 镜像。您可以将这些构件存储在管理器中。这类管理器的示例包括 Artifactory 和 Nexus。
在生产者端生成测试
镜像会在 /contracts
文件夹下搜索契约。运行测试的输出可在 /spring-cloud-contract/build
文件夹中找到(对调试很有用)。
您可以挂载您的契约并传递环境变量。然后,镜像会进行以下操作:
-
生成契约测试
-
针对提供的 URL 运行测试
-
生成 WireMock 存根
-
将存根发布到构件管理器(可选 - 默认开启)
环境变量
Docker 镜像需要一些环境变量来指向您正在运行的应用、构件管理器实例等。以下列表描述了这些环境变量
名称 |
描述 |
默认值 |
ADDITIONAL_FLAGS |
(仅限 Docker 镜像)要传递给 Gradle 构建的附加标志 |
|
DEBUG |
(仅限 Docker 镜像)适用于 Docker 镜像 - 为 Gradle 构建开启调试模式 |
false |
EXTERNAL_CONTRACTS_ARTIFACT_ID |
包含契约的项目的 Artifact ID |
|
EXTERNAL_CONTRACTS_CLASSIFIER |
包含契约的项目的分类器 |
|
EXTERNAL_CONTRACTS_GROUP_ID |
包含契约的项目的 Group ID |
com.example |
EXTERNAL_CONTRACTS_PATH |
给定项目内部(包含契约的项目)的契约路径。默认为用斜杠分隔的 |
|
EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_PASSWORD |
(可选)如果 |
|
EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_URL |
您的构件管理器的 URL。默认使用 |
|
EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_USERNAME |
(可选)如果 |
|
EXTERNAL_CONTRACTS_VERSION |
包含契约的项目的版本。默认为选择最新版本。 |
+ |
EXTERNAL_CONTRACTS_WORK_OFFLINE |
如果设置为 |
false |
FAIL_ON_NO_CONTRACTS |
如果不存在契约,构建是否应该失败? |
false |
MESSAGING_TYPE |
消息传递类型。可以是 [rabbit] 或 [kafka]。 |
|
PRODUCER_STUBS_CLASSIFIER |
用于生成的生产者存根的归档分类器 |
stubs |
PROJECT_GROUP |
您项目的 group ID |
com.example |
PROJECT_NAME |
您项目的 artifact id |
example |
PROJECT_VERSION |
您项目的版本 |
0.0.1-SNAPSHOT |
PUBLISH_ARTIFACTS |
如果设置为 |
true |
PUBLISH_ARTIFACTS_OFFLINE |
如果设置为 |
false |
PUBLISH_STUBS_TO_SCM |
如果设置为 |
false |
REPO_ALLOW_INSECURE_PROTOCOL |
(可选)如果 <true>,则允许通过不安全的 HTTP 将构件发布到构件管理器 |
false |
REPO_WITH_BINARIES_PASSWORD |
(可选)构件管理器受保护时的密码 |
password |
REPO_WITH_BINARIES_URL |
您的构件管理器的 URL(在本地运行时,默认为 Artifactory 的默认 URL) |
|
REPO_WITH_BINARIES_USERNAME |
(可选)构件管理器受保护时的用户名 |
admin |
STANDALONE_PROTOCOL |
对于独立版本,应该添加哪些附加协议 |
运行测试时使用以下环境变量
名称 |
描述 |
默认值 |
APPLICATION_BASE_URL |
应用正在运行的 URL。 |
|
APPLICATION_PASSWORD |
访问应用的可选密码。 |
|
APPLICATION_USERNAME |
访问应用的可选用户名。 |
|
MESSAGING_TRIGGER_CONNECT_TIMEOUT |
连接到应用以触发消息的超时时间。 |
5000 |
MESSAGING_TRIGGER_READ_TIMEOUT |
读取应用响应以触发消息的超时时间。 |
5000 |
MESSAGING_TYPE |
消息传递类型。可以是 [rabbit] 或 [kafka]。 |
|
MESSAGING_TYPE |
处理基于消息的契约时定义消息传递类型。 |
|
SPRING_KAFKA_BOOTSTRAP_SERVERS |
对于 Kafka - 代理地址。 |
|
SPRING_RABBITMQ_ADDRESSES |
对于 RabbitMQ - 代理地址。 |
自定义 Gradle 构建
您可以通过在运行容器时将自定义构建文件挂载为卷,来提供要在容器中运行的自定义 gradle.build
。
$ docker run -v <absolute-path-of-your-custom-file>:/spring-cloud-contract/build.gradle springcloud/spring-cloud-contract:<version>
HTTP 使用示例
在本节中,我们将探索一个简单的 MVC 应用。要开始,请克隆以下 git 仓库并切换到结果目录,运行以下命令:
$ git clone https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs
$ cd bookstore
契约位于 /contracts
文件夹中。
由于我们要运行测试,可以运行以下命令:
$ npm test
然而,为了学习目的,我们将其分解为以下几个部分:
# Stop docker infra (nodejs, artifactory)
$ ./stop_infra.sh
# Start docker infra (nodejs, artifactory)
$ ./setup_infra.sh
# Kill & Run app
$ pkill -f "node app"
$ nohup node app &
# Prepare environment variables
$ SC_CONTRACT_DOCKER_VERSION="..."
$ APP_IP="192.168.0.100"
$ APP_PORT="3000"
$ ARTIFACTORY_PORT="8081"
$ APPLICATION_BASE_URL="http://${APP_IP}:${APP_PORT}"
$ ARTIFACTORY_URL="http://${APP_IP}:${ARTIFACTORY_PORT}/artifactory/libs-release-local"
$ CURRENT_DIR="$( pwd )"
$ CURRENT_FOLDER_NAME=${PWD##*/}
$ PROJECT_VERSION="0.0.1.RELEASE"
# Run contract tests
$ docker run --rm -e "APPLICATION_BASE_URL=${APPLICATION_BASE_URL}" -e "PUBLISH_ARTIFACTS=true" -e "PROJECT_NAME=${CURRENT_FOLDER_NAME}" -e "REPO_WITH_BINARIES_URL=${ARTIFACTORY_URL}" -e "PROJECT_VERSION=${PROJECT_VERSION}" -v "${CURRENT_DIR}/contracts/:/contracts:ro" -v "${CURRENT_DIR}/node_modules/spring-cloud-contract/output:/spring-cloud-contract-output/" springcloud/spring-cloud-contract:"${SC_CONTRACT_DOCKER_VERSION}"
# Kill app
$ pkill -f "node app"
通过 bash 脚本,发生以下情况:
-
基础设施(MongoDb 和 Artifactory)已设置。在实际场景中,您将使用模拟数据库运行 NodeJS 应用。在此示例中,我们希望展示如何快速利用 Spring Cloud Contract 的优势。
-
由于这些限制,契约也表示有状态的情况。
-
第一个请求是
POST
请求,它会导致数据插入到数据库中。 -
第二个请求是
GET
请求,它返回一个包含先前插入的一个元素的列表。
-
-
NodeJS 应用已启动(在端口
3000
上)。 -
通过 Docker 生成契约测试,并针对正在运行的应用执行测试。
-
契约来自
/contracts
文件夹。 -
测试输出位于
node_modules/spring-cloud-contract/output
下。
-
-
存根已上传到 Artifactory。您可以在 localhost:8081/artifactory/libs-release-local/com/example/bookstore/0.0.1.RELEASE/ 中找到它们。存根位于 localhost:8081/artifactory/libs-release-local/com/example/bookstore/0.0.1.RELEASE/bookstore-0.0.1.RELEASE-stubs.jar。
消息传递使用示例
如果您想通过 Docker 镜像使用 Spring Cloud Contract 进行消息传递(例如在多语言应用中),则需要满足以下先决条件:
-
在生成测试之前,消息中间件(例如 RabbitMQ 或 Kafka)必须正在运行
-
您的契约需要调用一个方法
triggerMessage(…)
,该方法带有一个String
参数,其值等于契约的label
。 -
您的应用需要有一个 HTTP 端点,通过该端点我们可以触发消息
-
该端点不应在生产环境中可用(可以通过环境变量启用)
-
消息传递契约示例
契约需要调用 triggerMessage(…)
方法。该方法已在 Docker 镜像中所有测试的基础类中提供,并将向生产者端的 HTTP 端点发送请求。下面您可以看到此类契约的示例。
- Groovy
-
import org.springframework.cloud.contract.spec.Contract Contract.make { description 'Send a pong message in response to a ping message' label 'ping_pong' input { // You have to provide the `triggerMessage` method with the `label` // as a String parameter of the method triggeredBy('triggerMessage("ping_pong")') } outputMessage { sentTo('output') body([ message: 'pong' ]) } metadata( [amqp: [ outputMessage: [ connectToBroker: [ declareQueueWithName: "queue" ], messageProperties: [ receivedRoutingKey: '#' ] ] ] ]) }
- YAML
-
description: 'Send a pong message in response to a ping message' label: 'ping_pong' input: # You have to provide the `triggerMessage` method with the `label` # as a String parameter of the method triggeredBy: 'triggerMessage("ping_pong")' outputMessage: sentTo: 'output' body: message: 'pong' metadata: amqp: outputMessage: connectToBroker: declareQueueWithName: "queue" messageProperties: receivedRoutingKey: '#'
触发消息的 HTTP 端点
为什么需要开发这样的端点?Spring Cloud Contract 必须生成各种语言的代码(就像在 Java 中那样),才能触发向代理发送消息的生产代码。如果未生成此类代码,那么无论如何我们都需要能够触发消息,实现方式是提供一个 HTTP 端点,用户可以使用他们选择的语言准备该端点。
该端点必须具有以下配置:
-
URL:
/springcloudcontract/{label}
,其中label
可以是任意文本 -
方法:
POST
-
基于
label
将生成一条消息,该消息将根据契约定义发送到给定目的地
下面是此类端点的示例。如果您有兴趣使用您的语言提供示例,请随时在 Github 上的 Spring Cloud Contract 仓库中提交一个 issue。
#!/usr/bin/env python
from flask import Flask
from flask import jsonify
import pika
import os
app = Flask(__name__)
# Production code that sends a message to RabbitMQ
def send_message(cmd):
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
channel.basic_publish(
exchange='output',
routing_key='#',
body=cmd,
properties=pika.BasicProperties(
delivery_mode=2, # make message persistent
))
connection.close()
return " [x] Sent via Rabbit: %s" % cmd
# This should be ran in tests (shouldn't be publicly available)
if 'CONTRACT_TEST' in os.environ:
@app.route('/springcloudcontract/<label>', methods=['POST'])
def springcloudcontract(label):
if label == "ping_pong":
return send_message('{"message":"pong"}')
else:
raise ValueError('No such label expected.')
在生产者端运行消息测试
现在,让我们从契约生成测试以测试生产者端。我们将运行 bash 代码来启动带有附加契约的 Docker 镜像,同时也会为消息传递代码添加变量以使其工作。在这种情况下,我们假设契约存储在 Git 仓库中。
#!/bin/bash
set -x
CURRENT_DIR="$( pwd )"
export SC_CONTRACT_DOCKER_VERSION="${SC_CONTRACT_DOCKER_VERSION:-4.0.1-SNAPSHOT}"
export APP_IP="$( ./whats_my_ip.sh )"
export APP_PORT="${APP_PORT:-8000}"
export APPLICATION_BASE_URL="http://${APP_IP}:${APP_PORT}"
export PROJECT_GROUP="${PROJECT_GROUP:-group}"
export PROJECT_NAME="${PROJECT_NAME:-application}"
export PROJECT_VERSION="${PROJECT_VERSION:-0.0.1-SNAPSHOT}"
export PRODUCER_STUBS_CLASSIFIER="${PRODUCER_STUBS_CLASSIFIER:-stubs}"
export FAIL_ON_NO_CONTRACTS="${FAIL_ON_NO_CONTRACTS:-false}"
# In our Python app we want to enable the HTTP endpoint
export CONTRACT_TEST="true"
# In the Verifier docker container we want to add support for RabbitMQ
export MESSAGING_TYPE="rabbit"
# Let's start the infrastructure (e.g. via Docker Compose)
yes | docker-compose kill || echo "Nothing running"
docker-compose up -d
echo "SC Contract Version [${SC_CONTRACT_DOCKER_VERSION}]"
echo "Application URL [${APPLICATION_BASE_URL}]"
echo "Project Version [${PROJECT_VERSION}]"
# Let's run python app
gunicorn -w 4 --bind 0.0.0.0 main:app &
APP_PID=$!
# Generate and run tests
docker run --rm \
--name verifier \
# For the image to find the RabbitMQ running in another container
-e "SPRING_RABBITMQ_ADDRESSES=${APP_IP}:5672" \
# We need to tell the container what messaging middleware we will use
-e "MESSAGING_TYPE=${MESSAGING_TYPE}" \
-e "PUBLISH_STUBS_TO_SCM=false" \
-e "PUBLISH_ARTIFACTS=false" \
-e "APPLICATION_BASE_URL=${APPLICATION_BASE_URL}" \
-e "PROJECT_NAME=${PROJECT_NAME}" \
-e "PROJECT_GROUP=${PROJECT_GROUP}" \
-e "PROJECT_VERSION=${PROJECT_VERSION}" \
-e "EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_URL=git://https://github.com/marcingrzejszczak/cdct_python_contracts.git" \
-e "EXTERNAL_CONTRACTS_ARTIFACT_ID=${PROJECT_NAME}" \
-e "EXTERNAL_CONTRACTS_GROUP_ID=${PROJECT_GROUP}" \
-e "EXTERNAL_CONTRACTS_VERSION=${PROJECT_VERSION}" \
-v "${CURRENT_DIR}/build/spring-cloud-contract/output:/spring-cloud-contract-output/" \
springcloud/spring-cloud-contract:"${SC_CONTRACT_DOCKER_VERSION}"
kill $APP_PID
yes | docker-compose kill
将发生以下情况:
-
将从 Git 中获取的契约生成测试
-
在契约中,我们在元数据中提供了一个名为
declareQueueWithName
的条目,它将在发送触发消息的请求之前,在 RabbitMQ 中创建具有给定名称的队列 -
通过调用
triggerMessage("ping_pong")
方法,将向 Python 应用的/springcloudcontract/ping_pong
端点发送 POST 请求 -
Python 应用将通过 RabbitMQ 生成并发送一个
'{\"message\":\"pong\"}'
JSON 到名为output
的交换器 -
生成的测试将轮询发送到
output
交换器的消息 -
一旦收到消息,将断言其内容
测试通过后,我们知道消息已从 Python 应用正确发送到 RabbitMQ。
在消费者端运行存根
本节介绍如何在消费者端使用 Docker 来获取和运行存根。
我们发布了一个 spring-cloud/spring-cloud-contract-stub-runner
Docker 镜像,该镜像启动 Stub Runner 的独立版本。
安全
由于 Spring Cloud Contract Stub Runner Docker 镜像使用 Stub Runner 的独立版本,因此需要考虑相同的安全事项。您可以在文档的这一部分阅读更多内容。
环境变量
您可以运行 Docker 镜像并传递 JUnit 和 Spring 的通用属性中的任何属性作为环境变量。惯例是所有字母都应大写。点号 (.
) 应替换为下划线 (_
) 字符。例如,stubrunner.repositoryRoot
属性应表示为 STUBRUNNER_REPOSITORY_ROOT
环境变量。
除了这些变量,您还可以设置以下变量:
-
MESSAGING_TYPE
- 您正在使用的消息传递系统类型(目前支持rabbit
,kafka
) -
ADDITIONAL_OPTS
- 您希望传递给应用的任何附加属性
使用示例
我们想使用在 [docker-server-side] 步骤中创建的存根。假设我们想在端口 9876
上运行存根。您可以通过克隆仓库并切换到以下命令指示的目录来查看 NodeJS 代码:
$ git clone https://github.com/spring-cloud-samples/spring-cloud-contract-nodejs
$ cd bookstore
现在我们可以通过运行以下命令来使用存根运行 Stub Runner Boot 应用:
# Provide the Spring Cloud Contract Docker version
$ SC_CONTRACT_DOCKER_VERSION="..."
# The IP at which the app is running and Docker container can reach it
$ APP_IP="192.168.0.100"
# Spring Cloud Contract Stub Runner properties
$ STUBRUNNER_PORT="8083"
# Stub coordinates 'groupId:artifactId:version:classifier:port'
$ STUBRUNNER_IDS="com.example:bookstore:0.0.1.RELEASE:stubs:9876"
$ STUBRUNNER_REPOSITORY_ROOT="http://${APP_IP}:8081/artifactory/libs-release-local"
# Run the docker with Stub Runner Boot
$ docker run --rm \
-e "STUBRUNNER_IDS=${STUBRUNNER_IDS}" \
-e "STUBRUNNER_REPOSITORY_ROOT=${STUBRUNNER_REPOSITORY_ROOT}" \
-e "STUBRUNNER_STUBS_MODE=REMOTE" \
-p "${STUBRUNNER_PORT}:${STUBRUNNER_PORT}" \
-p "9876:9876" \
springcloud/spring-cloud-contract-stub-runner:"${SC_CONTRACT_DOCKER_VERSION}"
当执行上述命令时:
-
独立的 Stub Runner 应用启动。
-
它下载坐标为
com.example:bookstore:0.0.1.RELEASE:stubs
的存根,并在端口9876
上运行。 -
它从运行在
192.168.0.100:8081/artifactory/libs-release-local
的 Artifactory 下载。 -
一段时间后,Stub Runner 在端口
8083
上运行。 -
存根在端口
9876
上运行。
在服务器端,我们构建了一个有状态的存根。我们可以使用 curl 来断言存根是否设置正确。为此,请运行以下命令:
# let's run the first request (no response is returned)
$ curl -H "Content-Type:application/json" -X POST --data '{ "title" : "Title", "genre" : "Genre", "description" : "Description", "author" : "Author", "publisher" : "Publisher", "pages" : 100, "image_url" : "https://d213dhlpdb53mu.cloudfront.net/assets/pivotal-square-logo-41418bd391196c3022f3cd9f3959b3f6d7764c47873d858583384e759c7db435.svg", "buy_url" : "https://pivotal.io" }' http://localhost:9876/api/books
# Now time for the second request
$ curl -X GET http://localhost:9876/api/books
# You will receive contents of the JSON
如果您想使用您在本地主机上构建的存根,应该设置 -e STUBRUNNER_STUBS_MODE=LOCAL 环境变量,并挂载您本地 m2 的卷 (-v "${HOME}/.m2/:/home/scc/.m2:rw" )。 |
消息传递使用示例
为了使消息传递工作,只需传递带有 kafka
或 rabbit
值的 MESSAGING_TYPE
环境变量即可。这将设置 Stub Runner Boot Docker 镜像,使其具备连接到代理所需的依赖项。
为了设置连接属性,您可以查阅 Spring Cloud Stream 属性页面来设置适当的环境变量。
-
-
您可以搜索
spring.rabbitmq.xxx
或spring.kafka.xxx
属性
-
您最常设置的属性是正在运行的中间件的位置。如果设置它的属性名为 spring.rabbitmq.addresses
或 spring.kafka.bootstrap-servers
,则您应该将环境变量命名为 SPRING_RABBITMQ_ADDRESSES
和 SPRING_KAFKA_BOOTSTRAP_SERVERS
。
针对现有中间件运行契约测试
针对现有中间件运行契约测试有充分的理由。一些测试框架可能会给出假阳性结果——您的构建中的测试通过了,但在生产环境中通信失败。
在 Spring Cloud Contract Docker 镜像中,我们提供了连接到现有中间件的选项。如前几小节所示,我们开箱即用地支持 Kafka 和 RabbitMQ。然而,通过 Apache Camel 组件,我们也可以支持其他中间件。让我们看看下面的使用示例。
Spring Cloud Contract Docker 与运行中的中间件
为了连接到任意中间件,我们将利用契约部分的 standalone
元数据条目。
description: 'Send a pong message in response to a ping message'
label: 'standalone_ping_pong' (1)
input:
triggeredBy: 'triggerMessage("ping_pong")' (2)
outputMessage:
sentTo: 'rabbitmq:output' (3)
body: (4)
message: 'pong'
metadata:
standalone: (5)
setup: (6)
options: rabbitmq:output?queue=output&routingKey=(7)
outputMessage: (8)
additionalOptions: routingKey=#&queue=output (9)
1 | 通过 Stub Runner 触发消息的标签 |
2 | 与之前的消息传递示例一样,我们需要触发运行应用中的 HTTP 端点,使其根据提供的协议发送消息 |
3 | Apache Camel 要求格式为 protocol:destination |
4 | 输出消息体 |
5 | Standalone 元数据条目 |
6 | Setup 部分将包含关于在实际调用运行应用的 HTTP 端点之前,如何准备运行契约测试的信息 |
7 | 在设置阶段要调用的 Apache Camel URI。在这种情况下,我们将尝试在 output 交换器轮询消息,由于设置了 queue=output 和 routingKey= ,将创建名为 output 的队列并绑定到 output 交换器,路由键为
|
8 | 要附加到第 (3) 点的 protocol:destination 的附加选项(更偏向技术细节)——它们将组合成以下格式 rabbitmq:output?routingKey=#&queue=output 。 |
为了使契约测试通过,像在多语言环境中的消息传递一样,我们需要一个正在运行的应用和正在运行的中间件。这次我们将为 Spring Cloud Contract Docker 镜像设置不同的环境变量。
#!/bin/bash
set -x
# Setup
# Run the middleware
docker-compose up -d rabbitmq (1)
# Run the python application
gunicorn -w 4 --bind 0.0.0.0 main:app & (2)
APP_PID=$!
docker run --rm \
--name verifier \
-e "STANDALONE_PROTOCOL=rabbitmq" \ (3)
-e "CAMEL_COMPONENT_RABBITMQ_ADDRESSES=172.18.0.1:5672" \ (4)
-e "PUBLISH_STUBS_TO_SCM=false" \
-e "PUBLISH_ARTIFACTS=false" \
-e "APPLICATION_BASE_URL=172.18.0.1" \
-e "PROJECT_NAME=application" \
-e "PROJECT_GROUP=group" \
-e "EXTERNAL_CONTRACTS_ARTIFACT_ID=application" \
-e "EXTERNAL_CONTRACTS_GROUP_ID=group" \
-e "EXTERNAL_CONTRACTS_VERSION=0.0.1-SNAPSHOT" \
-v "${CURRENT_DIR}/build/spring-cloud-contract/output:/spring-cloud-contract-output/" \
springcloud/spring-cloud-contract:"${SC_CONTRACT_DOCKER_VERSION}"
# Teardown
kill $APP_PID
yes | docker-compose kill
1 | 我们首先需要中间件正在运行 |
2 | 应用需要启动并运行 |
3 | 通过 STANDALONE_PROTOCOL 环境变量,我们将获取一个 Apache Camel 组件。我们将获取的制品是 org.apache.camel.springboot:camel-${STANDALONE_PROTOCOL}-starter 。换句话说,STANDALONE_PROTOCOL 与 Camel 的组件匹配。 |
4 | 我们通过 Camel 的 Spring Boot Starter 机制设置地址(也可以设置凭据)。例如 Apache Camel 的 RabbitMQ Spring Boot 自动配置 |
Stub Runner Docker 与运行中的中间件
为了针对运行中的中间件触发桩消息,我们可以按以下方式运行 Stub Runner Docker 镜像。
用法示例
$ docker run \
-e "CAMEL_COMPONENT_RABBITMQ_ADDRESSES=172.18.0.1:5672" \ (1)
-e "STUBRUNNER_IDS=group:application:0.0.1-SNAPSHOT" \ (2)
-e "STUBRUNNER_REPOSITORY_ROOT=git://https://github.com/marcingrzejszczak/cdct_python_contracts.git" \ (3)
-e ADDITIONAL_OPTS="--thin.properties.dependencies.rabbitmq=org.apache.camel.springboot:camel-rabbitmq-starter:3.4.0" \ (4)
-e "STUBRUNNER_STUBS_MODE=REMOTE" \ (5)
-v "${HOME}/.m2/:/home/scc/.m2:rw" \ (6)
-p 8750:8750 \ (7)
springcloud/spring-cloud-contract-stub-runner:3.0.4-SNAPSHOT (8)
1 | 我们通过 Apache Camel 的 Spring Boot 自动配置 注入 RabbitMQ 的地址 |
2 | 我们告诉 Stub Runner 要下载哪些桩 |
3 | 我们为我们的桩提供了一个外部位置 (Git 仓库) |
4 | 通过 ADDITIONAL_OPTS=--thin.properties.dependencies.XXX=GROUP:ARTIFACT:VERSION 属性,我们告诉 Stub Runner 在运行时获取哪些附加依赖。在本例中,我们想获取 camel-rabbitmq-starter ,所以 XXX 是一个随机字符串,我们想获取版本 3.4.0 的制品 org.apache.camel.springboot:camel-rabbitmq-starter 。 |
5 | 由于我们正在使用 Git,需要设置远程获取桩的选项 |
6 | 为了加快 Stub Runner 的启动速度,我们将本地 Maven 仓库 .m2 作为卷挂载。如果你的仓库没有填充内容,可以考虑通过 :rw 设置写权限,而不是只读的 :ro 。 |
7 | 我们暴露 Stub Runner 运行的端口 8750 。 |
8 | Stub Runner Docker 镜像的坐标。 |
过一会儿,你会在控制台中注意到以下文本,这意味着 Stub Runner 已准备好接受请求。
o.a.c.impl.engine.AbstractCamelContext : Apache Camel 3.4.3 (camel-1) started in 0.007 seconds
o.s.c.c.s.server.StubRunnerBoot : Started StubRunnerBoot in 14.483 seconds (JVM running for 18.666)
o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
o.s.web.servlet.DispatcherServlet : Completed initialization in 2 ms
要获取触发器列表,你可以向 localhost:8750/triggers
端点发送 HTTP GET 请求。要触发桩消息,你可以向 localhost:8750/triggers/standalone_ping_pong
发送 HTTP POST 请求。在控制台中你会看到
o.s.c.c.v.m.camel.CamelStubMessages : Will send a message to URI [rabbitmq:output?routingKey=#&queue=output]
如果你查看 RabbitMQ 管理控制台,你会看到 output
队列中有 1 条可用消息。