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 词汇表

  • 项目: Maven 以项目为单位进行思考。项目是您构建的所有内容。这些项目遵循定义良好的“项目对象模型”。项目可以依赖其他项目——在这种情况下,后者称为“依赖项”。一个项目可以由多个子项目组成。然而,这些子项目仍然被同等对待为项目。

  • 工件: 工件是项目生成或使用的东西。Maven 为项目生成的工件示例包括 JAR 文件以及源代码和二进制发行版。每个工件都由一个组 ID 和一个在该组中唯一的工件 ID 唯一标识。

  • JAR: JAR 代表 Java ARchive。其格式基于 ZIP 文件格式。Spring Cloud Contract 将契约和生成的存根打包在 JAR 文件中。

  • GroupId: Group ID 是项目的全局唯一标识符。虽然这通常只是项目名称(例如,commons-collections),但使用完全限定的包名有助于将其与其他同名项目区分开来(例如,org.apache.maven)。通常,当发布到工件管理器时,GroupId 会用斜杠分隔并构成 URL 的一部分。例如,对于 group ID com.example 和 artifact ID application,结果将是 /com/example/application/

  • Classifier: Maven 依赖表示法如下:groupId:artifactId:version:classifier。分类器是传递给依赖项的附加后缀,例如,stubssources。同一个依赖项(例如,com.example:application)可以生成多个仅在分类器上不同的工件。

  • 工件管理器: 当您生成二进制文件、源代码或包时,您希望它们可供其他人下载、引用或重用。在 JVM 世界中,这些工件通常是 JAR。对于 Ruby,这些工件是 gem。对于 Docker,这些工件是 Docker 镜像。您可以将这些工件存储在管理器中。此类管理器的示例包括 ArtifactoryNexus

在生产者端生成测试

镜像在 /contracts 文件夹下搜索契约。运行测试的输出可在 /spring-cloud-contract/build 文件夹中找到(用于调试目的)。

您可以挂载您的契约并传递环境变量。然后镜像将

  • 生成契约测试

  • 针对提供的 URL 运行测试

  • 生成 WireMock 存根

  • 将存根发布到工件管理器(可选——默认启用)

环境变量

Docker 镜像需要一些环境变量来指向您运行中的应用程序、工件管理器实例等。以下列表描述了环境变量

表 1. Docker 环境变量

名称

描述

默认值

ADDITIONAL_FLAGS

(仅限 Docker 镜像)要传递给 Gradle 构建的附加标志

DEBUG

(仅限 Docker 镜像)适用于 Docker 镜像 - 为 Gradle 构建开启调试模式

EXTERNAL_CONTRACTS_ARTIFACT_ID

包含契约的项目的工件 ID

EXTERNAL_CONTRACTS_CLASSIFIER

包含契约的项目的分类器

EXTERNAL_CONTRACTS_GROUP_ID

包含契约的项目的组 ID

com.example

EXTERNAL_CONTRACTS_PATH

给定项目内部契约的路径,位于包含契约的项目中。默认为斜杠分隔的 EXTERNAL_CONTRACTS_GROUP_ID/EXTERNAL_CONTRACTS_ARTIFACT_ID 连接。例如,对于组 ID cat-server-side.dog 和工件 ID fish,契约路径将为 cat/dog/fish

EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_PASSWORD

(可选)如果 EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_URL 需要身份验证,则为密码。它默认为 `REPO_WITH_BINARIES_PASSWORD`,如果未设置,则默认为 `password`

EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_URL

您的工件管理器的 URL。它默认为 REPO_WITH_BINARIES_URL 环境变量的值,如果未设置,则默认为 localhost:8081/artifactory/libs-release-local

EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_USERNAME

(可选)如果 EXTERNAL_CONTRACTS_REPO_WITH_BINARIES_URL 需要身份验证,则为用户名。它默认为 REPO_WITH_BINARIES_USERNAME。如果未设置,则默认为 `admin`

EXTERNAL_CONTRACTS_VERSION

包含契约的项目的版本。默认为选择最新版本

+

EXTERNAL_CONTRACTS_WORK_OFFLINE

如果设置为 true,则从容器的 .m2 中检索包含契约的工件。将您的本地 .m2 挂载为容器 /root/.m2 路径上的可用卷

FAIL_ON_NO_CONTRACTS

如果不存在契约,构建是否应该失败?

MESSAGING_TYPE

消息类型。可以是 [rabbit] 或 [kafka]。

PRODUCER_STUBS_CLASSIFIER

用于生成生产者存根的存档分类器

stubs

PROJECT_GROUP

您的项目的组 ID

com.example

PROJECT_NAME

您的项目的工件 ID

example

PROJECT_VERSION

您的项目的版本

0.0.1-SNAPSHOT

PUBLISH_ARTIFACTS

如果设置为 true,则将工件发布到二进制存储

true

PUBLISH_ARTIFACTS_OFFLINE

如果设置为 true,则将工件发布到本地 m2

PUBLISH_STUBS_TO_SCM

如果设置为 true,将运行任务将存根发布到 SCM

REPO_ALLOW_INSECURE_PROTOCOL

(可选)如果为 <true>,则允许通过不安全的 HTTP 将工件发布到工件管理器

REPO_WITH_BINARIES_PASSWORD

(可选)当工件管理器受保护时的密码

password

REPO_WITH_BINARIES_URL

您的工件管理器的 URL(默认为本地运行时 Artifactory 的默认 URL)

localhost:8081/artifactory/libs-release-local

REPO_WITH_BINARIES_USERNAME

(可选)当工件管理器受保护时的用户名

admin

STANDALONE_PROTOCOL

对于独立版本,应添加哪个附加协议

以下环境变量在运行测试时使用

表 2. Docker 环境变量 - 运行时读取

名称

描述

默认值

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 脚本,发生以下情况

通过消息传递使用示例

如果您想通过 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 仓库 中提交问题。

Python
#!/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 的通用属性。约定是所有字母都应为大写。点 (.) 应替换为下划线 (_) 字符。例如,spring.cloud.contract.stubrunner.repositoryRoot 属性应表示为 SPRING_COUD_CONTRACT_STUBRUNNER_REPOSITORY_ROOT 环境变量。

除了这些变量,您还可以设置以下变量

  • MESSAGING_TYPE - 您正在使用的消息系统类型(目前支持 rabbitkafka

  • 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
$ SPRING_CLOUD_CONTRACT_STUBRUNNER_PORT="8083"
# Stub coordinates 'groupId:artifactId:version:classifier:port'
$ SPRING_CLOUD_CONTRACT_STUBRUNNER_IDS="com.example:bookstore:0.0.1.RELEASE:stubs:9876"
$ SPRING_CLOUD_CONTRACT_STUBRUNNER_REPOSITORY_ROOT="http://${APP_IP}:8081/artifactory/libs-release-local"
# Run the docker with Stub Runner Boot
$ docker run  --rm \
    -e "SPRING_CLOUD_CONTRACT_STUBRUNNER_IDS=${STUBRUNNER_IDS}" \
    -e "SPRING_CLOUD_CONTRACT_STUBRUNNER_REPOSITORY_ROOT=${STUBRUNNER_REPOSITORY_ROOT}" \
    -e "SPRING_CLOUD_CONTRACT_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" }' https://:9876/api/books
# Now time for the second request
$ curl -X GET https://:9876/api/books
# You will receive contents of the JSON
如果您想使用在本地主机上构建的存根,您应该设置 -e STUBRUNNER_STUBS_MODE=LOCAL 环境变量并挂载本地 m2 的卷 (-v "${HOME}/.m2/:/home/scc/.m2:rw")。

消息传递使用示例

为了使消息传递工作,只需传递 MESSAGING_TYPE 环境变量,其值为 kafkarabbit。这将导致使用连接到代理所需的依赖项设置 Stub Runner Boot Docker 镜像。

为了设置连接属性,您可以查看 Spring Cloud Stream 属性页面以设置正确的环境变量。

您会设置的最常见的属性是运行中间件的位置。如果设置该属性的名称是 spring.rabbitmq.addressesspring.kafka.bootstrap-servers,那么您应该分别将环境变量命名为 SPRING_RABBITMQ_ADDRESSESSPRING_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 protocol:destination,由 Apache Camel 请求
4 输出消息体
5 独立元数据条目
6 设置部分将包含在实际调用运行中应用程序的 HTTP 端点之前如何准备运行契约测试的信息
7 将在设置阶段调用的 Apache Camel URI。在这种情况下,我们将尝试轮询 output 交换机中的消息,并且由于存在 queue=outputroutingKey=,因此将设置一个名为 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 "SPRING_CLOUD_CONTRACT_STUBRUNNER_IDS=group:application:0.0.1-SNAPSHOT" \ (2)
    -e "SPRING_CLOUD_CONTRACT_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 "SPRING_CLOUD_CONTRACT_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.0org.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 条消息。

© . This site is unofficial and not affiliated with VMware.