通过 TCP/IP 连接传输 HL7v2 消息

本教程介绍了如何使用最小底层协议 (MLLP) 通过 TCP/IP 连接传输 HL7v2 消息。如需要求证明者将 MLLP 映像进行签名,请参考使用已签名的 MLLP 映像通过 TCP/IP 连接传输 HL7v2 消息中的步骤。

本教程介绍了如何在以下环境中运行在 GitHub 中托管的开源 MLLP 适配器

目标

完成本教程后,您将了解如何执行以下任务:

费用

在本文档中,您将使用 Google Cloud 的以下收费组件:

  • Cloud Healthcare API
  • Google Kubernetes Engine
  • Compute Engine
  • Cloud VPN
  • Pub/Sub

您可使用价格计算器根据您的预计使用情况来估算费用。 Google Cloud 新用户可能有资格申请免费试用

须知事项

在开始学习本教程之前,请查看 MLLP 和 Google Cloud MLLP 适配器,熟悉有关最小底层协议 (MLLP) 的概念性文档。该概念性文档简要介绍了 MLLP,医疗保健系统如何通过 MLLP 连接向 Cloud Healthcare API 发送和接收消息,以及 MLLP 安全的基础知识。

在设置 MLLP 适配器之前,您必须选择或创建一个 Google Cloud 项目,并通过完成以下步骤来启用所需的 API:

  1. 登录您的 Google Cloud 账号。如果您是 Google Cloud 新手,请创建一个账号来评估我们的产品在实际场景中的表现。新客户还可获享 $300 赠金,用于运行、测试和部署工作负载。
  2. 在 Google Cloud Console 中的项目选择器页面上,选择或创建一个 Google Cloud 项目

    转到“项目选择器”

  3. 确保您的 Google Cloud 项目已启用结算功能

  4. 启用 Cloud Healthcare API, Google Kubernetes Engine, Container Registry, and Pub/Sub API。

    启用 API

  5. 在 Google Cloud Console 中的项目选择器页面上,选择或创建一个 Google Cloud 项目

    转到“项目选择器”

  6. 确保您的 Google Cloud 项目已启用结算功能

  7. 启用 Cloud Healthcare API, Google Kubernetes Engine, Container Registry, and Pub/Sub API。

    启用 API

  8. 稍作等待,让 Kubernetes Engine API 和相关服务完成启用过程。 此过程可能耗时几分钟。

选择 shell

要完成本教程,您可以使用 Cloud Shell 或本地 shell。

Cloud Shell 是一种 shell 环境,用于管理托管在 Google Cloud 上的资源。Cloud Shell 预装了 gcloud CLIkubectl 工具。gcloud CLI 提供了 Google Cloud 的主要命令行界面。kubectl 提供了用于针对 GKE 集群运行命令的命令行界面。

如果您更喜欢使用本地 shell,则必须安装 gcloud CLI。

如需打开 Cloud Shell 或配置本地 shell,请完成以下步骤:

Cloud Shell

如需启动 Cloud Shell,请完成以下步骤:

  1. 进入 Google Cloud 控制台。

    Google Cloud 控制台

  2. 在控制台的右上角,点击激活 Google Cloud Shell 按钮:

控制台底部的框中随即打开一个 Cloud Shell 会话。您可以使用此 shell 运行 gcloudkubectl 命令。

本地 Shell

如需安装 gcloud CLI 和 kubectl 工具,请完成以下步骤:

  1. 安装并初始化 Google Cloud CLI
  2. 如果只是在本地测试适配器,则无需完成任何其他步骤,可以继续创建数据集。如果要将适配器部署到 GKE,请通过运行以下命令安装 kubectl 命令行工具:

    gcloud components install kubectl

创建数据集

如果尚未创建 Cloud Healthcare API 数据集,请按照以下步骤创建数据集:

控制台

  1. 在 Google Cloud 控制台中,转到数据集页面。

    进入“数据集”

  2. 点击创建数据集
  3. 名称字段中,输入数据集的标识符。数据集 ID 必须符合以下条件:
    • 位置中的唯一 ID
    • 由 1-256 个字符组成的 Unicode 字符串,由以下各项组成:
      • 数字
      • 字母
      • 下划线
      • 短划线
      • 英文句点
  4. 位置类型部分,选择以下某一类型的位置:
    • 单区域:数据集永久驻留在一个 Google Cloud 区域中。选择此类型后,在单区域字段中输入或选择位置。
    • 多区域:数据集永久驻留在跨多个 Google Cloud 区域的位置中。选择此类型后,在多区域字段中输入或选择多区域位置。
  5. 点击创建

新数据集将显示在数据集列表中。

gcloud

要创建数据集,请运行 gcloud healthcare datasets create 命令:

gcloud healthcare datasets create DATASET_ID \
    --location=LOCATION

如果请求成功,命令将返回以下输出:

Create request issued for: [DATASET_ID]
Waiting for operation [OPERATION_ID] to complete...done.
Created dataset [DATASET_ID].

创建 Pub/Sub 主题和订阅

要在创建或提取消息时收到通知,您需要使用 HL7v2 存储区配置 Pub/Sub 主题。如需了解详情,请参阅配置 Pub/Sub 通知

如需创建主题,请完成以下步骤:

控制台

  1. 进入 Google Cloud 控制台中的 Pub/Sub 主题页面。

    转到 Pub/Sub 主题页面

  2. 点击创建主题

  3. 在主题名称中输入 URI:

    projects/PROJECT_ID/topics/TOPIC_NAME

    其中 PROJECT_ID 是您的 Google Cloud 项目 ID。

  4. 点击创建

gcloud

要创建主题,请运行 gcloud pubsub topics create 命令:

gcloud pubsub topics create projects/PROJECT_ID/topics/TOPIC_NAME

如果请求成功,命令将返回以下输出:

Created topic [projects/PROJECT_ID/topics/TOPIC_NAME].

如需创建订阅,请完成以下步骤。

控制台

  1. 进入 Google Cloud 控制台中的 Pub/Sub 主题页面。

    转到 Pub/Sub 主题页面

  2. 点击项目的主题。

  3. 点击创建订阅

  4. 输入订阅名称:

    projects/PROJECT_ID/subscriptions/SUBSCRIPTION_NAME

  5. 传送类型的设置保留为拉取,然后点击创建

gcloud

要创建订阅,请运行 gcloud pubsub subscriptions create 命令:

gcloud pubsub subscriptions create SUBSCRIPTION_NAME \
    --topic=projects/PROJECT_ID/topics/TOPIC_NAME

如果请求成功,命令将返回以下输出:

Created subscription [projects/PROJECT_ID/subscriptions/SUBSCRIPTION_NAME].

创建使用 Pub/Sub 主题配置的 HL7v2 存储区

创建 HL7v2 存储区,然后使用 Pub/Sub 主题进行配置。要创建 HL7v2 存储区,必须已创建数据集。在本教程中,请对 HL7v2 存储区和 Pub/Sub 主题使用同一项目。

要创建使用 Pub/Sub 主题配置的 HL7v2 存储区,请完成以下步骤:

curl

curl -X POST \
    --data "{
      'notificationConfigs': [
        {
          'pubsubTopic': 'projects/PROJECT_ID/topics/PUBSUB_TOPIC',
          'filter': ''
        }
      ]
    }" \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    -H "Content-Type: application/json; charset=utf-8" \
    "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores?hl7V2StoreId=HL7V2_STORE_ID"

如果请求成功,服务器将以 JSON 格式返回响应:

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID",
  "notificationConfigs": [
    {
      "pubsubTopic": "projects/PROJECT_ID/topics/PUBSUB_TOPIC"
    }
  ]
}

PowerShell

$cred = gcloud auth application-default print-access-token
$headers = @{ Authorization = "Bearer $cred" }

Invoke-WebRequest `
  -Method Post `
  -Headers $headers `
  -ContentType: "application/json; charset=utf-8" `
  -Body "{
      'notificationConfigs': [
        {
          'pubsubTopic': 'projects/PROJECT_ID/topics/PUBSUB_TOPIC',
          'filter': ''
        }
      ]
  }" `
  -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores?hl7V2StoreId=HL7V2_STORE_ID" | Select-Object -Expand Content

如果请求成功,服务器将以 JSON 格式返回响应:

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID",
  "notificationConfigs": [
    {
      "pubsubTopic": "projects/PROJECT_ID/topics/PUBSUB_TOPIC"
    }
  ]
}

配置 Pub/Sub 权限

要在创建或提取 HL7v2 消息时向 Pub/Sub 发送通知,需要在 Cloud Healthcare API 上配置 Pub/Sub 权限。此步骤需要针对每个项目执行一次。

要将所需的 pubsub.publisher 角色添加到项目的服务账号,请完成以下步骤:

控制台

  1. 在 Google Cloud 控制台的 IAM 页面上,验证 Healthcare Service Agent 角色显示在相关项目服务账号的角色列中。账号名称为 service-PROJECT_NUMBER@gcp-sa-healthcare.iam.gserviceaccount.com。如需了解如何查找 PROJECT_NUMBER,请参阅 识别项目

  2. 在与角色匹配的继承列中,点击铅笔图标。修改权限窗格随即会打开。

  3. 点击添加其他角色,然后搜索 Pub/Sub 发布商角色。

  4. 选择相应角色,然后点击保存pubsub.publisher 角色已添加到服务账号。

gcloud

如需添加服务账号权限,请运行 gcloud projects add-iam-policy-binding 命令。如需了解如何查找 PROJECT_IDPROJECT_NUMBER,请参阅识别项目

gcloud projects add-iam-policy-binding PROJECT_ID \
    --member=serviceAccount:service-PROJECT_NUMBER@gcp-sa-healthcare.iam.gserviceaccount.com \
    --role=roles/pubsub.publisher

拉取预构建的 Docker 映像

MLLP 适配器是暂存在 Container Registry 内的预构建 Docker 映像中的容器化应用。

要拉取映像的最新版本,请运行以下命令:

docker pull gcr.io/cloud-healthcare-containers/mllp-adapter:latest

在本地测试 MLLP 适配器

在本地测试适配器时,可以将其配置为以接收者、发布商或两者的身份运行。接收者和发布商配置存在以下主要区别:

  • 当适配器作为接收者运行时,会接收来自外部来源的 HL7v2 消息,并调用 messages.ingest 将消息注入到 HL7v2 存储区中,从而创建 Pub/Sub 通知。该通知会发送给已订阅 HL7v2 存储区的 Pub/Sub 主题的应用。
  • 当适配器以发布商身份运行时,它会侦听使用 messages.createmessages.ingest 在 HL7v2 存储区中创建或提取的 HL7v2 消息。创建消息后,系统会将 Pub/Sub 通知发送到适配器,然后适配器将消息发布到外部接收者。

以下部分介绍了如何运行适配器,使其充当接收者发布商

验证可以在本地机器上运行 MLLP 适配器后,可以继续阅读将 MLLP 适配器部署到 Google Kubernetes Engine 中的下一部分。

以接收者的身份测试 MLLP 适配器

当适配器收到来自外部来源(例如护理中心)的 HL7v2 消息时,适配器会调用 messages.ingest 并将 HL7v2 消息提取到配置的 HL7v2 存储区中。您可以在适配器的源代码中观察到这一点。

要在本地将适配器作为接收者进行测试,请完成以下步骤:

  1. 在拉取预构建 Docker 映像的机器上,运行以下命令:

    docker run \
        --network=host \
        -v ~/.config:/root/.config \
        gcr.io/cloud-healthcare-containers/mllp-adapter \
        /usr/mllp_adapter/mllp_adapter \
        --hl7_v2_project_id=PROJECT_ID \
        --hl7_v2_location_id=LOCATION \
        --hl7_v2_dataset_id=DATASET_ID \
        --hl7_v2_store_id=HL7V2_STORE_ID \
        --export_stats=false \
        --receiver_ip=0.0.0.0 \
        --port=2575 \
        --api_addr_prefix=https://healthcare.googleapis.com:443/v1 \
        --logtostderr
    

    其中:

    • PROJECT_ID 是包含 HL7v2 存储区的 Google Cloud 项目的 ID。
    • LOCATION 是 HL7v2 存储区所在的区域。
    • DATASET_ID 是 HL7v2 存储区的父数据集的 ID。
    • HL7V2_STORE_ID 是您要向其发送 HL7v2 消息的 HL7v2 存储区 ID。

    运行上一个命令后,适配器会打印类似于以下内容的消息,并开始在本地机器上(IP 地址 127.0.0.1,端口 2575)运行:

    I0000 00:00:00.000000      1 healthapiclient.go:171] Dialing connection to https://healthcare.googleapis.com:443/v1
    I0000 00:00:00.000000      1 mllp_adapter.go:89] Either --pubsub_project_id or --pubsub_subscription is not provided, notifications of the new messages are not read and no outgoing messages will be sent to the target MLLP address.
    

    如果您遇到任何错误,请按照以下问题排查步骤操作:

  2. 要在适配器作为前台进程运行时继续进行测试,请在本地机器上打开另一个终端。

  3. 在新终端中,要安装 Netcat,请运行以下命令:

    sudo apt install netcat
    
  4. 下载 hl7v2-mllp-sample.txt 文件并将其保存到本地机器。

  5. 要将 HL7v2 消息发送到适配器,请在下载该文件的目录中运行以下命令。MLLP 适配器正在侦听本地主机的端口 2575。该命令通过 MLLP 适配器将消息发送到您的 HL7v2 存储区。

    Linux

    echo -n -e "\x0b$(cat hl7v2-mllp-sample.txt)\x1c\x0d" | nc -q1 localhost 2575 | less
    

    如果已将消息成功提取到 HL7v2 存储区中,则该命令将返回以下输出:

    ^KMSH|^~\&|TO_APP|TO_FACILITY|FROM_APP|FROM_FACILITY|19700101010000||ACK|c507a97e-438d-44b0-b236-ea95e5ecbbfb|P|2.5^MMSA|AA|20150503223000^\
    

    此输出表明 HL7v2 存储区以 AA (Application Accept) 响应类型进行响应,这意味着消息已通过验证并成功提取。

  6. 您还可以通过打开运行适配器的终端来验证消息是否已成功发送。输出应类似于以下示例:

     I0000 00:00:00.000000       1 healthapiclient.go:171] Dialing connection to https://healthcare.googleapis.com:443/v1
     I0000 00:00:00.000000       1 mllp_adapter.go:89] Either --pubsub_project_id or --pubsub_subscription is not provided, notifications of the new messages are not read and no outgoing messages will be sent to the target MLLP address.
     I0213 00:00:00.000000       1 healthapiclient.go:190] Sending message of size 319.
     I0213 00:00:00.000000       1 healthapiclient.go:223] Message was successfully sent.
    
  7. 该消息存储在您的 HL7v2 存储区中,因此您可以调用 messages.list 来查看该消息:

    curl

    curl -X GET \
         -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
         -H "Content-Type: application/json; charset=utf-8" \
         "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages"
    

    如果请求成功,服务器将在资源路径中返回消息的 ID:

    {
      "hl7V2Messages": [
        {
          "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages/MESSAGE_ID"
        }
      ]
    }
    

    PowerShell

    $cred = gcloud auth application-default print-access-token
    $headers = @{ Authorization = "Bearer $cred" }
    
    Invoke-WebRequest `
      -Method Get `
      -Headers $headers `
      -ContentType: "application/json; charset=utf-8" `
      -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages" | Select-Object -Expand Content
    

    如果请求成功,服务器将在资源路径中返回消息的 ID:

    {
      "hl7V2Messages": [
        {
          "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages/MESSAGE_ID"
        }
      ]
    }
    

以发布商的身份在本地测试 MLLP 适配器

以发布商身份测试适配器时,可以通过调用 messages.createmessages.ingest,并以二进制数据形式提供消息文件来创建消息。

适配器会自动确认通过 messages.createmessages.ingest 发送的 Pub/Sub 消息。

适配器会在成功提取并发送 Pub/Sub 消息时通知您。适配器是 Pub/Sub 订阅者,因此它会自动确认这些消息。因此,它们会从您使用适配器配置的 Pub/Sub 订阅的消息队列中移除。

要从 Pub/Sub 订阅中拉取并单独验证消息是否已发布,您需要再创建一个分配给您之前创建的主题的 Pub/Sub 订阅。适配器不会自动确认发送到第二个订阅的消息,并保留这些消息供您拉取。

要创建分配给您之前创建的主题的第二个 Pub/Sub 订阅,请完成以下步骤:

控制台

  1. 进入 Google Cloud 控制台中的 Pub/Sub 主题页面。

    转到 Pub/Sub 主题页面

  2. 点击项目的主题。这是您用于创建初始订阅的主题。

  3. 点击创建订阅

  4. 输入订阅名称:

    projects/PROJECT_ID/subscriptions/SECOND_SUBSCRIPTION_NAME

    传送类型设置保留为拉取

  5. 点击创建

gcloud

要创建分配给您之前创建的主题的第二个 Pub/Sub 订阅,请运行 gcloud pubsub subscriptions create 命令:

gcloud pubsub subscriptions create SECOND_SUBSCRIPTION_NAME --topic=projects/PROJECT_ID/topics/TOPIC_NAME

如果请求成功,命令将返回以下输出:

Created subscription [projects/PROJECT_ID/subscriptions/SECOND_SUBSCRIPTION_NAME].

要以发布商身份在本地测试适配器,请在拉取预构建 Docker 映像的机器上完成以下步骤:

  1. 安装 Netcat

    sudo apt install netcat
    
  2. 下载 hl7v2-mllp-ack-sample.txt 文件并将其保存到本地机器。该文件包含适配器在尝试发布消息时要求作为响应的 ACK 消息。

  3. 如需允许 Netcat 监听端口 2525 上的传入连接,请在下载文件的目录中运行以下命令。

    Linux

    echo -n -e "\x0b$(cat hl7v2-mllp-ack-sample.txt)\x1c\x0d" | nc -q1 -lv -p 2525 | less
    

    启动 Netcat 后,将显示类似于以下示例的输出消息:

    listening on [any] 2525 ...
    
  4. Netcat 作为前台进程运行,因此要继续测试,请在本地机器上打开另一个终端。

  5. 要启动适配器,请在新终端中运行以下命令:

    docker run \
        --network=host \
        gcr.io/cloud-healthcare-containers/mllp-adapter \
        /usr/mllp_adapter/mllp_adapter \
        --hl7_v2_project_id=PROJECT_ID \
        --hl7_v2_location_id=LOCATION \
        --hl7_v2_dataset_id=DATASET_ID \
        --hl7_v2_store_id=HL7V2_STORE_ID \
        --export_stats=false \
        --receiver_ip=127.0.0.1 --port 2575 \
        --mllp_addr=127.0.0.1:2525 \
        --pubsub_project_id=PROJECT_ID \
        --pubsub_subscription=PUBSUB_SUBSCRIPTION \
        --api_addr_prefix=https://healthcare.googleapis.com:443/v1 \
        --logtostderr
    

    其中:

    • PROJECT_ID 是包含 HL7v2 存储区的 Google Cloud 项目的 ID。
    • LOCATION 是 HL7v2 存储区所在的区域。
    • DATASET_ID 是 HL7v2 存储区的父数据集的 ID。
    • HL7V2_STORE_ID 是您要向其发送 HL7v2 消息的 HL7v2 存储区 ID。
    • PROJECT_ID 是包含 Pub/Sub 主题的 Google Cloud 项目的 ID。
    • PUBSUB_SUBSCRIPTION 是您创建的与 Pub/Sub 主题关联的第一个订阅的名称。适配器会使用来自此订阅的消息并自动确认消息,因此要查看发布到主题的消息,必须从之前创建的第二个订阅中拉取消息。

    运行上一个命令后,适配器会开始在本地计算机上(IP 地址 127.0.0.1,端口 2575)运行:

    如果您遇到任何错误,请按照以下问题排查步骤操作:

    适配器作为前台进程运行,因此要继续测试,请在本地机器上打开另一个终端。

  6. 下载 hl7v2-sample.json 文件并将其保存到本地机器。在下载该文件的目录中,调用 messages.create 方法以在 HL7v2 存储区中创建消息:

    curl

    要创建 HL7v2 消息,请发出 POST 请求并指定以下信息:

    • 父数据集的名称
    • HL7v2 存储区的名称
    • 一条消息
    • 访问令牌

    以下示例显示了使用 curlPOST 请求以及名为 hl7v2-sample.json 的示例 JSON 文件。

    curl -X POST \
         -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
         -H "Content-Type: application/json; charset=utf-8" \
         --data-binary @hl7v2-sample.json \
         "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages"
    

    如果请求成功,服务器将以 JSON 格式返回响应:

    {
      "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages/MESSAGE_ID",
      "data": "TVNIfF5+XCZ8QXxTRU5EX0ZBQ0lMSVRZfEF8QXwyMDE4MDEwMTAwMDAwMHx8VFlQRV5BfDIwMTgwMTAxMDAwMDAwfFR8MC4wfHx8QUF8fDAwfEFTQ0lJDUVWTnxBMDB8MjAxODAxMDEwNDAwMDANUElEfHwxNAExMTFeXl5eTVJOfDExMTExMTExXl5eXk1STn4xMTExMTExMTExXl5eXk9SR05NQlI=",
      "sendFacility": "SEND_FACILITY",
      "sendTime": "2018-01-01T00:00:00Z",
      "messageType": "TYPE",
      "createTime": "1970-01-01T00:00:00Z",
      "patientIds": [
        {
          "value": "14\u0001111",
          "type": "MRN"
        },
        {
          "value": "11111111",
          "type": "MRN"
        },
        {
          "value": "1111111111",
          "type": "ORGNMBR"
        }
      ]
    }
    

    PowerShell

    要创建 HL7v2 消息,请发出 POST 请求并指定以下信息:

    • 父数据集的名称
    • HL7v2 存储区的名称
    • 一条消息
    • 访问令牌

    以下示例显示了使用 Windows PowerShell 的 POST 请求以及名为 hl7v2-sample.json 的示例 JSON 文件。

    $cred = gcloud auth application-default print-access-token
    $headers = @{ Authorization = "Bearer $cred" }
    
    Invoke-WebRequest `
      -Method Post `
      -Headers $headers `
      -ContentType: "application/json; charset=utf-8" `
      -InFile hl7v2-sample.json `
      -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages" | Select-Object -Expand Content
    

    如果请求成功,服务器将以 JSON 格式返回响应:

    {
      "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages/MESSAGE_ID",
      "data": "TVNIfF5+XCZ8QXxTRU5EX0ZBQ0lMSVRZfEF8QXwyMDE4MDEwMTAwMDAwMHx8VFlQRV5BfDIwMTgwMTAxMDAwMDAwfFR8MC4wfHx8QUF8fDAwfEFTQ0lJDUVWTnxBMDB8MjAxODAxMDEwNDAwMDANUElEfHwxNAExMTFeXl5eTVJOfDExMTExMTExXl5eXk1STn4xMTExMTExMTExXl5eXk9SR05NQlI=",
      "sendFacility": "SEND_FACILITY",
      "sendTime": "2018-01-01T00:00:00Z",
      "messageType": "TYPE",
      "createTime": "1970-01-01T00:00:00Z",
      "patientIds": [
        {
          "value": "14\u0001111",
          "type": "MRN"
        },
        {
          "value": "11111111",
          "type": "MRN"
        },
        {
          "value": "1111111111",
          "type": "ORGNMBR"
        }
      ]
    }
    

    创建消息后,MLLP 适配器将返回以下响应:

    I0214 00:00:00.000000       1 healthapiclient.go:266] Started to fetch message.
    I0214 00:00:00.000000       1 healthapiclient.go:283] Message was successfully fetched.
    
  7. 在运行 Netcat 的终端中,将显示类似于以下示例的输出。此输出表明消息已发布:

    connect to [127.0.0.1] from localhost [127.0.0.1] 39522
    ^KMSH|^~\&|A|SEND_FACILITY|A|A|20180101000000||TYPE^A|20180101000000|T|0.0|||AA||00|ASCII^MEVN|A00|20180101040000^MPID||14^A111^^^^MRN|11111111^^^^MRN~1111111111^^^^ORGNMBR^\
    

    这对应于您在创建消息时收到的响应的 data 字段中的值。它与 hl7v2-sample.json 文件中的 data 值相同。

  8. 要查看适配器发布到 Pub/Sub 主题的消息,请在您创建的第二个 Pub/Sub 订阅上运行 gcloud pubsub subscriptions pull 命令:

    gcloud pubsub subscriptions pull --auto-ack SECOND_SUBSCRIPTION
    

    该命令会返回有关所创建 HL7v2 消息的以下输出。请注意 ATTRIBUTES 列中的 publish=true 值,该值表示消息已发布到 Pub/Sub:

    ┌-----------------------------------------------------------------------------------------------------------------|-----------------|---------------┐
    |                                                               DATA                                              |    MESSAGE_ID   |   ATTRIBUTES  |
    ├-----------------------------------------------------------------------------------------------------------------|-----------------|---------------|
    | projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages/HL7V2_MESSAGE_ID | 123456789012345 | msgType=ADT   |
    |                                                                                                                 |                 | publish=true  |
    └-----------------------------------------------------------------------------------------------------------------|-----------------|---------------┘
    

将消息发布到不同的外部接收者

您可以使用多个 Pub/Sub 主题配置 HL7v2 存储区,并使用过滤器向不同的 Pub/Sub 主题发送通知。然后,可以为每个 Pub/Sub 主题运行 MLLP 适配器,将消息发布到其他外部接收者。

要使用多个 Pub/Sub 主题配置 HL7v2 存储区,并为每个主题配置一个过滤器,请完成以下步骤:

  1. 创建两个 Pub/Sub 主题,并为每个主题创建一个订阅。如需了解详情,请参阅创建 Pub/Sub 主题和订阅

  2. 运行以下命令:

    curl

    curl -X PATCH \
        -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
        -H "Content-Type: application/json; charset=utf-8" \
        --data "{
          'notificationConfigs': [
              {
                  'pubsubTopic': 'projects/PROJECT_ID/topics/PUBSUB_TOPIC',
                  'filter' : 'sendFacility=\"SEND_FACILITY_1\"'
              },
              {
                  'pubsubTopic': 'projects/PROJECT_ID/topics/SECOND_PUBSUB_TOPIC',
                  'filter': 'sendFacility=\"SEND_FACILITY_2\"'
              }
          ]
        }" "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID?updateMask=notificationConfigs"
    

    如果请求成功,服务器将以 JSON 格式返回响应:

    {
      "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID",
      "notificationConfigs": [
        {
          "pubsubTopic": "projects/PROJECT_ID/topics/PUBSUB_TOPIC",
          "filter": "sendFacility=\"SEND_FACILITY_1\""
        },
        {
          "pubsubTopic": "projects/PROJECT_ID/topics/SECOND_PUBSUB_TOPIC",
          "filter": "sendFacility=\"SEND_FACILITY_2\""
        }
      ]
    }
    

    PowerShell

    $cred = gcloud auth application-default print-access-token
    $headers = @{ Authorization = "Bearer $cred" }
    
    Invoke-WebRequest `
      -Method Patch `
      -Headers $headers `
      -ContentType: "application/json; charset=utf-8" `
      -Body "{
          'notificationConfigs': [
            {
              'pubsubTopic' : 'projects/PROJECT_ID/topics/PUBSUB_TOPIC',
              'filter': 'sendFacility=\"SEND_FACILITY_1\"'
            },
            {
              'pubsubTopic' : 'projects/PROJECT_ID/topics/SECOND_PUBSUB_TOPIC',
              'filter' : 'sendFacility=\"SEND_FACILITY_2\"'
            }
          ]
      }" `
      -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores?hl7V2StoreId=HL7V2_STORE_ID?updateMask=notificationConfigs" | Select-Object -Expand Content
    

    如果请求成功,服务器将以 JSON 格式返回响应:

    {
      "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID",
      "notificationConfigs": [
        {
          "pubsubTopic": "projects/PROJECT_ID/topics/PUBSUB_TOPIC",
          "filter": "sendFacility=\"SEND_FACILITY_1\""
        },
        {
          "pubsubTopic": "projects/PROJECT_ID/topics/SECOND_PUBSUB_TOPIC",
          "filter": "sendFacility=\"SEND_FACILITY_2\""
        }
      ]
    }
    

测试消息路由

要测试邮件路由,请完成以下部分中的步骤。

配置并启动第一个接收者和适配器

要配置并启动第一个接收者和适配器,请完成以下步骤:

  1. 在拉取预构建 Docker 映像的机器上,运行以下命令以安装 Netcat

    sudo apt install netcat
    
  2. 下载 hl7v2-mllp-ack-sample.txt(如果尚未下载)。该文件包含一条 ACK 消息,由适配器在尝试发布消息时用作响应。

  3. 要为第一个接收者设置端口 2525,请运行以下命令:

    Linux

    echo -n -e "\x0b$(cat hl7v2-mllp-ack-sample.txt)\x1c\x0d" | nc -q1 -lv -p 2525 | less
    

    当 Netcat 进程启动时,将显示以下输出:

    listening on [any] 2525 ...
    
  4. 要启动第一个适配器,请在新终端中运行以下命令:

    docker run \
        --network=host \
        gcr.io/cloud-healthcare-containers/mllp-adapter \
        /usr/mllp_adapter/mllp_adapter \
        --hl7_v2_project_id=PROJECT_ID \
        --hl7_v2_location_id=LOCATION \
        --hl7_v2_dataset_id=DATASET_ID \
        --hl7_v2_store_id=HL7V2_STORE_ID \
        --export_stats=false \
        --receiver_ip=127.0.0.1 --port 2575 \
        --mllp_addr=127.0.0.1:2525 \
        --pubsub_project_id=PROJECT_ID \
        --pubsub_subscription=PUBSUB_SUBSCRIPTION \
        --api_addr_prefix=https://healthcare.googleapis.com:443/v1 \
        --logtostderr
    

    其中:

    • PROJECT_ID 是包含 HL7v2 存储区的 Google Cloud 项目的 ID。
    • LOCATION 是 HL7v2 存储区所在的区域。
    • DATASET_ID 是 HL7v2 存储区的父数据集的 ID。
    • HL7V2_STORE_ID 是您要向其发送 HL7v2 消息的 HL7v2 存储区 ID。
    • PROJECT_ID 是包含 Pub/Sub 主题的 Google Cloud 项目的 ID。
    • PUBSUB_SUBSCRIPTION 是您创建的、与第一个 Pub/Sub 主题关联的第一个订阅的名称。适配器会使用来自此订阅的消息,并自动确认消息。

    运行此命令后,适配器开始在本地机器 (127.0.0.1:2575) 上运行。它会向端口 2525 上的第一个外部接收者发布新消息。

配置并启动第二个接收者和适配器

要配置并启动第二个接收者和适配器,请完成以下步骤:

  1. 在拉取预构建 Docker 映像的机器上,运行以下命令以安装 Netcat

    sudo apt install netcat
    
  2. 下载 hl7v2-mllp-ack-sample.txt(如果尚未下载)。该文件包含一条 ACK 消息,由适配器在尝试发布消息时用作响应。

  3. 要为第二个接收者设置端口 2526,请运行以下命令。

    Linux

    echo -n -e "\x0b$(cat hl7v2-mllp-ack-sample.txt)\x1c\x0d" | nc -q1 -lv -p 2526 | less
    

    当 Netcat 进程启动时,将显示以下输出:

    listening on [any] 2526 ...
    
  4. 要启动第二个适配器,请在新终端中运行以下命令:

    docker run \
        --network=host \
        gcr.io/cloud-healthcare-containers/mllp-adapter \
        /usr/mllp_adapter/mllp_adapter \
        --hl7_v2_project_id=PROJECT_ID \
        --hl7_v2_location_id=LOCATION \
        --hl7_v2_dataset_id=DATASET_ID \
        --hl7_v2_store_id=HL7V2_STORE_ID \
        --export_stats=false \
        --receiver_ip=127.0.0.1 --port 2576 \
        --mllp_addr=127.0.0.1:2526 \
        --pubsub_project_id=PROJECT_ID \
        --pubsub_subscription=SECOND_PUBSUB_SUBSCRIPTION \
        --api_addr_prefix=https://healthcare.googleapis.com:443/v1 \
        --logtostderr
    

    其中:

    • PROJECT_ID 是包含 HL7v2 存储区的 Google Cloud 项目的 ID。
    • LOCATION 是 HL7v2 存储区所在的区域。
    • DATASET_ID 是 HL7v2 存储区的父数据集的 ID。
    • HL7V2_STORE_ID 是您要向其发送 HL7v2 消息的 HL7v2 存储区 ID。
    • PROJECT_ID 是包含 Pub/Sub 主题的 Google Cloud 项目的 ID。
    • SECOND_PUBSUB_SUBSCRIPTION 是您创建的、与第二个 Pub/Sub 主题关联的第二个订阅的名称。适配器会使用来自此订阅的消息,并自动确认消息。

    运行此命令后,适配器开始在本地机器 (127.0.0.1:2576) 上运行。它会将新消息发布到端口 2526 上的第二个外部接收者。

将消息发布到第一个接收者

要创建只会发布给第一个外部接收者的消息,请完成以下步骤:

  1. 下载 hl7v2-sample1.json

  2. 在您下载 hl7v2-sample1.json 的目录中,调用 messages.create 方法以在 HL7v2 存储区中创建消息:

    curl

    要创建 HL7v2 消息,请发出 POST 请求并指定以下信息:

    • 父数据集的名称
    • HL7v2 存储区的名称
    • 一条消息
    • 访问令牌

    以下示例显示了使用 curlPOST 请求以及示例 JSON 文件 hl7v2-sample1.json

    curl -X POST \
        -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
        -H "Content-Type: application/json; charset=utf-8" \
        --data-binary @hl7v2-sample1.json \
        "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages"
    

    如果请求成功,服务器将以 JSON 格式返回响应:

    {
     "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages/MESSAGE_ID",
     "data": "TVNIfF5+XCZ8QXxTRU5EX0ZBQ0lMSVRZXzF8QXxBfDIwMTgwMTAxMDAwMDAwfHxUWVBFXkF8MjAxODAxMDEwMDAwMDB8VHwwLjB8fHxBQXx8MDB8QVNDSUkNRVZOfEEwMHwyMDE4MDEwMTA0MDAwMA1QSUR8fDE0ATExMV5eXl5NUk58MTExMTExMTFeXl5eTVJOfjExMTExMTExMTFeXl5eT1JHTk1CUg==",
     "sendFacility": "SEND_FACILITY_1",
     "sendTime": "2018-01-01T00:00:00Z",
     "messageType": "TYPE",
     "createTime": "1970-01-01T00:00:00Z",
     "patientIds": [
       {
         "value": "14\u0001111",
         "type": "MRN"
       },
       {
         "value": "11111111",
         "type": "MRN"
       },
       {
         "value": "1111111111",
         "type": "ORGNMBR"
       }
     ]
    }
    

    PowerShell

    要创建 HL7v2 消息,请发出 POST 请求并指定以下信息:

    • 父数据集的名称
    • HL7v2 存储区的名称
    • 一条消息
    • 访问令牌

    以下示例显示了使用 Windows PowerShell 的 POST 请求以及名为 hl7v2-sample1.json 的示例 JSON 文件。

    $cred = gcloud auth application-default print-access-token
    $headers = @{ Authorization = "Bearer $cred" }
    
    Invoke-WebRequest `
     -Method Post `
     -Headers $headers `
     -ContentType: "application/json; charset=utf-8" `
     -InFile hl7v2-sample1.json `
     -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages" | Select-Object -Expand Content
    

    如果请求成功,服务器将以 JSON 格式返回响应:

    {
     "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages/MESSAGE_ID",
     "data": "TVNIfF5+XCZ8QXxTRU5EX0ZBQ0lMSVRZXzF8QXxBfDIwMTgwMTAxMDAwMDAwfHxUWVBFXkF8MjAxODAxMDEwMDAwMDB8VHwwLjB8fHxBQXx8MDB8QVNDSUkNRVZOfEEwMHwyMDE4MDEwMTA0MDAwMA1QSUR8fDE0ATExMV5eXl5NUk58MTExMTExMTFeXl5eTVJOfjExMTExMTExMTFeXl5eT1JHTk1CUg==",
     "sendFacility": "SEND_FACILITY_1",
     "sendTime": "2018-01-01T00:00:00Z",
     "messageType": "TYPE",
     "createTime": "1970-01-01T00:00:00Z",
     "patientIds": [
       {
         "value": "14\u0001111",
         "type": "MRN"
       },
       {
         "value": "11111111",
         "type": "MRN"
       },
       {
         "value": "1111111111",
         "type": "ORGNMBR"
       }
     ]
    }
    

    在此响应中,sendFacility 设置为 SEND_FACILITY_1,因此 Pub/Sub 通知仅会发送到第一个 Pub/Sub 主题。创建消息后,第一个 MLLP 适配器将返回以下响应:

    I0214 00:00:00.000000       1 healthapiclient.go:266] Started to fetch message.
    I0214 00:00:00.000000       1 healthapiclient.go:283] Message was successfully fetched.
    

    第二个 MLLP 适配器不会返回任何响应,因为没有向第二个 Pub/Sub 主题发送任何通知。

    在运行第一个 Netcat 进程的终端中,将显示以下输出。此输出表明消息已发布。

    connect to [127.0.0.1] from localhost [127.0.0.1] 39522
    ^KMSH|^~\&|A|SEND_FACILITY_1|A|A|20180101000000||TYPE^A|20180101000000|T|0.0|||AA||00|ASCII^MEVN|A00|20180101040000^MPID||14^A111^^^^MRN|11111111^^^^MRN~1111111111^^^^ORGNMBR^\
    

    此输出对应于您在创建消息时收到的响应的 data 字段中的值。它与 hl7v2-sample1.json 文件中的 data 值相同。

将消息发布到第二个接收者

要创建只会发布给第二个外部接收者的消息,请完成以下步骤:

  1. 在本地机器上打开一个新终端。

  2. 要创建只会发布给第二个外部接收者的消息,请下载 hl7v2-sample2.json

  3. 在您下载 hl7v2-sample2.json 的目录中,调用 messages.create 方法以在 HL7v2 存储区中创建消息:

    curl

    要创建 HL7v2 消息,请发出 POST 请求并指定以下信息:

    • 父数据集的名称
    • HL7v2 存储区的名称
    • 一条消息
    • 访问令牌

    以下示例显示了使用 curlPOST 请求以及示例 JSON 文件 hl7v2-sample2.json

    curl -X POST \
        -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
        -H "Content-Type: application/json; charset=utf-8" \
        --data-binary @hl7v2-sample2.json \
        "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages"
    

    如果请求成功,服务器将以 JSON 格式返回响应:

    {
     "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages/MESSAGE_ID",
     "data": "TVNIfF5+XCZ8QXxTRU5EX0ZBQ0lMSVRZXzJ8QXxBfDIwMTgwMTAxMDAwMDAwfHxUWVBFXkF8MjAxODAxMDEwMDAwMDB8VHwwLjB8fHxBQXx8MDB8QVNDSUkNRVZOfEEwMHwyMDE4MDEwMTA0MDAwMA1QSUR8fDE0ATExMV5eXl5NUk58MTExMTExMTFeXl5eTVJOfjExMTExMTExMTFeXl5eT1JHTk1CUg==",
     "sendFacility": "SEND_FACILITY_2",
     "sendTime": "2018-01-01T00:00:00Z",
     "messageType": "TYPE",
     "createTime": "1970-01-01T00:00:00Z",
     "patientIds": [
       {
         "value": "14\u0001111",
         "type": "MRN"
       },
       {
         "value": "11111111",
         "type": "MRN"
       },
       {
         "value": "1111111111",
         "type": "ORGNMBR"
       }
     ]
    }
    

    PowerShell

    要创建 HL7v2 消息,请发出 POST 请求并指定以下信息:

    • 父数据集的名称
    • HL7v2 存储区的名称
    • 一条消息
    • 访问令牌

    以下示例显示了使用 Windows PowerShell 的 POST 请求以及示例 JSON 文件 hl7v2-sample2.json

    $cred = gcloud auth application-default print-access-token
    $headers = @{ Authorization = "Bearer $cred" }
    
    Invoke-WebRequest `
     -Method Post `
     -Headers $headers `
     -ContentType: "application/json; charset=utf-8" `
     -InFile hl7v2-sample2.json `
     -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages" | Select-Object -Expand Content
    

    如果请求成功,服务器将以 JSON 格式返回响应:

    {
     "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages/MESSAGE_ID",
     "data": "TVNIfF5+XCZ8QXxTRU5EX0ZBQ0lMSVRZXzJ8QXxBfDIwMTgwMTAxMDAwMDAwfHxUWVBFXkF8MjAxODAxMDEwMDAwMDB8VHwwLjB8fHxBQXx8MDB8QVNDSUkNRVZOfEEwMHwyMDE4MDEwMTA0MDAwMA1QSUR8fDE0ATExMV5eXl5NUk58MTExMTExMTFeXl5eTVJOfjExMTExMTExMTFeXl5eT1JHTk1CUg==",
     "sendFacility": "SEND_FACILITY_2",
     "sendTime": "2018-01-01T00:00:00Z",
     "messageType": "TYPE",
     "createTime": "1970-01-01T00:00:00Z",
     "patientIds": [
       {
         "value": "14\u0001111",
         "type": "MRN"
       },
       {
         "value": "11111111",
         "type": "MRN"
       },
       {
         "value": "1111111111",
         "type": "ORGNMBR"
       }
     ]
    }
    

    请注意,sendFacility 为SEND_FACILITY_2,因此 Pub/Sub 通知只会发送到第二个 Pub/Sub 主题。创建消息后,第一个 MLLP 适配器不会返回任何响应,而第二个 MLLP 适配器会返回以下响应:

    I0214 00:00:00.000000       1 healthapiclient.go:266] Started to fetch message.
    I0214 00:00:00.000000       1 healthapiclient.go:283] Message was successfully fetched.
    

    在运行第二个 Netcat 进程的终端中,将显示以下输出。此输出表明消息已发布。

    connect to [127.0.0.1] from localhost [127.0.0.1] 39522
    ^KMSH|^~\&|A|SEND_FACILITY_2|A|A|20180101000000||TYPE^A|20180101000000|T|0.0|||AA||00|ASCII^MEVN|A00|20180101040000^MPID||14^A111^^^^MRN|11111111^^^^MRN~1111111111^^^^ORGNMBR^\
    

    此输出对应于您在创建消息时收到的响应的 data 字段中的值。它与 hl7v2-sample2.json 文件中的 data 值相同。

将 MLLP 适配器部署到 Google Kubernetes Engine

通过 MLLP 从您的护理中心传输 HL7v2 消息时,一种可能的配置是将消息发送到在 Google Cloud 中部署的适配器,并将其转发到 Cloud Healthcare API。

MLLP 适配器在 GKE 集群上作为无状态应用运行。GKE 集群是指由用于运行容器化应用的虚拟机实例组成的托管群组。无状态应用是不将数据或应用状态存储到集群或永久性存储空间的应用。此类应用会将数据和应用状态保留在客户端,因此可扩缩性更强。

GKE 使用 Deployment 控制器将无状态应用部署为统一且非唯一的 Pod。Deployment 会管理应用的“所需状态”,即应运行应用的 Pod 数、应运行的容器映像版本、应为 Pod 添加的标签等等。通过更新部署的 Pod 规范,可以动态地更改所需状态。

在部署适配器的同时,创建一个 Service 控制器,以便使用内部负载均衡将适配器连接到 Cloud Healthcare API。

如果您是 GKE 的新手,请完成 GKE 快速入门以了解产品的工作原理。

向 GKE 服务账号添加 Pub/Sub API 权限

如关于使用服务账号向 Cloud Platform 验证身份的 GKE 文档所述,容器集群中的每个节点都是一个 Compute Engine 实例。因此,当 MLLP 适配器在容器集群上运行时,它会自动继承其所部署到的 Compute Engine 实例的范围。

Google Cloud 会自动创建名为“Compute Engine 默认服务账号”的服务账号,并且 GKE 会将此服务账号与 GKE 创建的节点相关联。默认服务账号可能有权也可能无权使用其他 Cloud Platform API,具体取决于项目的配置方式。GKE 还会为 Compute Engine 实例分配一些有限的访问权限范围。

为获得最佳结果,请勿通过更新默认服务账号的权限或为 Compute Engine 实例分配更多访问权限范围,从 GKE 上运行的 Pod 向其他 Google Cloud 服务(如 Pub/Sub)验证身份。请创建您自己的服务账号

您必须向容器集群授予必要的 Pub/Sub 权限,但还可以选择授予将指标写入 Cloud Monitoring 的权限。

要创建仅包含容器集群所需范围的新服务账号,请完成以下步骤:

控制台

创建服务账号:

  1. 在 Google Cloud 控制台中,转到创建服务账号页面。

    转到“创建服务账号”

  2. 选择一个项目。

  3. 服务账号名称字段中,输入一个名称。Google Cloud 控制台会根据此名称填充服务账号 ID 字段。

    可选:在服务账号说明字段中,输入说明。

  4. 点击创建

  5. 点击选择角色字段。

    所有角色下,点击 Pub/Sub > Pub/Sub Subscriber

  6. 点击添加其他角色,然后点击选择角色字段。

    所有角色下,点击 Cloud Healthcare > Healthcare HL7v2 Message Ingest

  7. 可选:如果要启用监控,请点击添加其他角色,然后点击选择角色字段。

    所有角色下,点击 Monitoring > Monitoring Metric Writer

  8. 点击继续

  9. 点击完成以完成服务账号的创建过程。

    不要关闭浏览器窗口。您将在下一个过程中使用该窗口。

创建服务账号密钥:

  1. 在 Google Cloud 控制台中,点击您创建的服务账号的电子邮件地址。

  2. 点击密钥

  3. 依次点击添加密钥创建新密钥

  4. 点击创建。JSON 密钥文件将下载到您的计算机上。

  5. 点击关闭

gcloud

  1. 要创建服务账号,请运行 gcloud iam service-accounts create 命令。

    gcloud iam service-accounts create SERVICE_ACCOUNT_NAME
    

    输出是服务账号:

    Created service account SERVICE_ACCOUNT_NAME.
    
  2. 要每个角色授予给服务账号,请运行 gcloud projects add-iam-policy-binding 命令。

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member=serviceAccount:SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com \
      --role=roles/pubsub.subscriber
    
    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member=serviceAccount:SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com \
      --role=roles/healthcare.hl7V2Ingest
    
    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member=serviceAccount:SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com \
      --role=roles/monitoring.metricWriter
    

    输出包括更新后的政策:

    bindings:
        - members:
            - user:SERVICE_ACCOUNT_NAME
            role: roles/pubsub.publisher
        - members:
            - user:SERVICE_ACCOUNT_NAME
            roles/healthcare.hl7V2Ingest
        - members:
            - user:SERVICE_ACCOUNT_NAME
            roles/monitoring.metricWriter
        etag: ETAG
        version: 1
    
  3. 要创建服务账号密钥,请运行 gcloud iam service-accounts keys create 命令。

    gcloud iam service-accounts keys create ~/FILENAME.json \
       --iam-account=SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com
    

    创建服务账号后,系统会将包含服务账号凭据的 JSON 密钥文件下载到您的计算机。您需要使用此密钥文件来配置 MLLP 适配器,以使用 --service-account 标记在集群创建期间向 Cloud Healthcare API、Pub/Sub API 和 Cloud Monitoring API 验证身份。

    created key [e44da1202f82f8f4bdd9d92bc412d1d8a837fa83] of type [json] as
        [/usr/home/USERNAME/FILENAME.json] for
        [SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com]
    

创建集群

要在 GKE 中创建集群,请运行 gcloud container clusters create 命令:

gcloud container clusters create mllp-adapter \
    --zone=COMPUTE_ZONE \
    --service-account CLIENT_EMAIL

其中:

  • COMPUTE_ZONE 是部署集群的可用区。可用区是您的集群及其资源所在的大致区域位置。例如,us-west1-aus-west 区域中的可用区。如果使用 gcloud config set compute/zone 设置了默认可用区,则此标志的值将替换默认值。
  • CLIENT_EMAIL 是服务账号的标识符。您可以在 "client_email": 字段的服务账号密钥文件中找到此电子邮件地址。其格式如下:SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com。

该命令会返回类似于以下示例的输出:

Creating cluster mllp-adapter in COMPUTE_ZONE...
Cluster is being configured...
Cluster is being deployed...
Cluster is being health-checked...
Cluster is being health-checked (master is healthy)...done.
Created [https://container.googleapis.com/v1/projects/PROJECT_ID/zones/COMPUTE_ZONE/clusters/mllp-adapter].
To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/COMPUTE_ZONE/mllp-adapter?project=PROJECT_ID
kubeconfig entry generated for mllp-adapter.
NAME          LOCATION       MASTER_VERSION  MASTER_IP      MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
mllp-adapter  COMPUTE_ZONE   1.11.7-gke.4    203.0.113.1    n1-standard-1  1.11.7-gke.4  3          RUNNING

创建集群后,GKE 会创建三个 Compute Engine 虚拟机实例。您可以通过使用以下命令列出实例来验证这一点:

gcloud compute instances list

配置部署

将应用部署到 GKE 时,您可以使用 Deployment 清单文件(通常是 YAML 文件)定义 Deployment 的属性。如需查看示例,请参阅创建 Deployment

  1. 打开一个单独的终端。

  2. 使用文本编辑器创建名为 mllp_adapter.yaml 的 Deployment 清单文件,其中包含以下内容:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mllp-adapter-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mllp-adapter
  template:
    metadata:
      labels:
        app: mllp-adapter
    spec:
      containers:
        - name: mllp-adapter
          imagePullPolicy: Always
          image: gcr.io/cloud-healthcare-containers/mllp-adapter
          ports:
            - containerPort: 2575
              protocol: TCP
              name: "port"
          command:
            - "/usr/mllp_adapter/mllp_adapter"
            - "--port=2575"
            - "--hl7_v2_project_id=PROJECT_ID"
            - "--hl7_v2_location_id=LOCATION"
            - "--hl7_v2_dataset_id=DATASET_ID"
            - "--hl7_v2_store_id=HL7V2_STORE_ID"
            - "--api_addr_prefix=https://healthcare.googleapis.com:443/v1"
            - "--logtostderr"
            - "--receiver_ip=0.0.0.0"

其中:

  • PROJECT_ID 是包含 HL7v2 存储区的 Google Cloud 项目的 ID。
  • LOCATION 是 HL7v2 存储区所在的区域。
  • DATASET_ID 是 HL7v2 存储区的父数据集的 ID。
  • HL7V2_STORE_ID 是您要向其发送 HL7v2 消息的 HL7v2 存储区 ID。

Deployment 具有以下属性:

  • spec: replicas: 是 Deployment 管理的副本 Pod 数。
  • spec: template: metadata: labels: 是为每个 Pod 指定的标签,供 Deployment 用来管理 Pod。
  • spec: template: spec:Pod 规范,用于定义每个 Pod 的运行方式。
  • spec: containers 包括要在每个 Pod 中运行的容器的名称以及应运行的容器映像。

如需详细了解 Deployment 规范,请参阅 Deployment API 参考

配置 Service

要使 MLLP 适配器可供集群外部的应用(如护理中心)访问,您必须配置内部负载均衡器

如果尚未配置 VPN,只要应用使用相同的 VPC 网络并位于同一 Google Cloud 区域中,应用就可以通过内部负载均衡器访问 MLLP 适配器。例如,要使适配器可供同一区域内和同一 VPC 网络中的 Compute Engine 虚拟机实例访问,您可以向集群的 Service 资源添加内部负载均衡器。

在创建 Deployment 清单文件的目录中,使用文本编辑器创建名为 mllp_adapter_service.yaml 的 Service 清单文件,其中包含以下内容。此文件负责配置内部负载均衡:

apiVersion: v1
kind: Service
metadata:
  name: mllp-adapter-service
  annotations:
    cloud.google.com/load-balancer-type: "Internal"
spec:
  type: LoadBalancer
  ports:
  - name: port
    port: 2575
    targetPort: 2575
    protocol: TCP
  selector:
    app: mllp-adapter

该 Service 具有以下属性:

  • metadata: name: 是您为 Service 选择的名称。在本例中为 mllp-adapter-service
  • metadata: annotations: 是一个注解,指定要配置内部负载平衡器。
  • spec: type: 是负载均衡器的类型。
  • ports: port: 用于指定服务可以从同一集群中的其他 Service 接收流量的端口。使用默认的 2575 MLLP 端口。
  • ports: targetPort: 用于在 Service 运行的每个 Pod 上指定端口。
  • spec: selector: app: 用于指定作为 Service 目标的 Pod。

虽然可以为负载均衡器指定 IP 地址(使用 clusterIP 字段),但负载均衡器可以生成自己的 IP 地址,以便您向其发送消息。现在,请让集群生成 IP 地址,您将在本教程的后面部分用到该地址。

如需详细了解内部负载均衡,请参阅 GKE 文档。

如需详细了解 Service 规范,请参阅 Service API 参考文档

部署 Deployment

要将适配器部署到 GKE 集群,请在包含 mllp_adapter.yaml Deployment 清单文件的目录中运行以下命令:

kubectl apply -f mllp_adapter.yaml

该命令返回以下输出:

deployment.extensions "mllp-adapter-deployment" created

检查 Deployment

创建部署后,您可以使用 kubectl 工具对其进行检查。

要获取有关 Deployment 的详细信息,请运行以下命令:

kubectl describe deployment mllp-adapter

要列出 Deployment 创建的 Pod,请运行以下命令:

kubectl get pods -l app=mllp-adapter

要获取有关所创建的 Pod 的信息,请执行以下操作:

kubectl describe pod POD_NAME

如果 Deployment 成功,上一个命令的输出的最后部分应包含以下信息:

Events:
  Type    Reason     Age   From                                                  Message
  ----    ------     ----  ----                                                  -------
  Normal  Scheduled  1m    default-scheduler                                     Successfully assigned default/mllp-adapter-deployment-85b46f8-zxw68 to gke-mllp-adapter-default-pool-9c42852d-95sn
  Normal  Pulling    1m    kubelet, gke-mllp-adapter-default-pool-9c42852d-95sn  pulling image "gcr.io/cloud-healthcare-containers/mllp-adapter"
  Normal  Pulled     1m    kubelet, gke-mllp-adapter-default-pool-9c42852d-95sn  Successfully pulled image "gcr.io/cloud-healthcare-containers/mllp-adapter"
  Normal  Created    1m    kubelet, gke-mllp-adapter-default-pool-9c42852d-95sn  Created container
  Normal  Started    1m    kubelet, gke-mllp-adapter-default-pool-9c42852d-95sn  Started container

部署 Service 并创建内部负载均衡器

要创建内部负载均衡器,请在包含 mllp_adapter_service.yaml Service 清单文件的目录中运行以下命令:

kubectl apply -f mllp_adapter_service.yaml

该命令返回以下输出:

service "mllp-adapter-service" created

检查 Service

创建 Service 后,请检查以验证其是否已成功配置。

要检查内部负载均衡器,请运行以下命令:

kubectl describe service mllp-adapter-service

该命令的输出类似于以下示例:

Name:                     mllp-adapter-service
Namespace:                default
Labels:                   <none>
Annotations:              cloud.google.com/load-balancer-type=Internal
                          kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{"cloud.google.com/load-balancer-type":"Internal"},"name":"mllp-adapter-service","namespa...
Selector:                 app=mllp-adapter
Type:                     LoadBalancer
IP:                       203.0.113.1
LoadBalancer Ingress:     203.0.113.1
Port:                     port  2575/TCP
TargetPort:               2575/TCP
NodePort:                 port  30660/TCP
Endpoints:                <none>
Session Affinity:         None
External Traffic Policy:  Cluster
Events:
  Type    Reason                Age   From                Message
  ----    ------                ----  ----                -------
  Normal  EnsuringLoadBalancer  1m    service-controller  Ensuring load balancer
  Normal  EnsuredLoadBalancer   1m    service-controller  Ensured load balancer

LoadBalancer Ingress IP 地址可能需要长达一分钟来填充。在下一步中,您需要使用此 IP 地址和 2575 端口从集群外部访问 Service。

创建 Compute Engine 虚拟机并发送消息

在本教程前面的部分中,您在本地测试了 MLLP 适配器并向您的 HL7v2 存储区发送了 HL7v2 消息,而现在需要将消息从 Compute Engine 虚拟机发送到在 GKE 上运行的 MLLP 适配器。然后,系统会将这些消息转发到 HL7v2 存储区。

要将请求从新实例发送到 GKE 集群,该实例和现有实例必须位于同一区域并使用同一 VPC 网络

在本部分的结尾处,您需要列出发布到 Pub/Sub 主题的通知以及 HL7v2 存储区中的 HL7v2 消息。Compute Engine 虚拟机实例必须获得执行这些任务的权限。在创建实例之前,请按照以下步骤创建具有所需权限的新服务账号:

控制台

创建服务账号:

  1. 在 Google Cloud 控制台中,转到创建服务账号页面。

    转到“创建服务账号”

  2. 选择一个项目。

  3. 服务账号名称字段中,输入一个名称。Google Cloud 控制台会根据此名称填充服务账号 ID 字段。

    可选:在服务账号说明字段中,输入说明。

  4. 点击创建

  5. 点击选择角色字段。

    所有角色下,点击 Pub/Sub > Pub/Sub Subscriber

  6. 点击添加其他角色,然后点击选择角色字段。

    所有角色下,点击 Cloud Healthcare > Healthcare HL7v2 Message Consumer

  7. 点击继续

  8. 点击完成以完成服务账号的创建过程。

    不要关闭浏览器窗口。您将在下一个过程中使用该窗口。

创建服务账号密钥:

  1. 在 Google Cloud 控制台中,点击您创建的服务账号的电子邮件地址。

  2. 点击密钥

  3. 依次点击添加密钥创建新密钥

  4. 点击创建。JSON 密钥文件将下载到您的计算机上。

  5. 点击关闭

gcloud

  1. 要创建服务账号,请运行 gcloud iam service-accounts create 命令。

    gcloud iam service-accounts create SERVICE_ACCOUNT_NAME
    

    输出是服务账号:

    Created service account SERVICE_ACCOUNT_NAME.
    
  2. 要每个角色授予给服务账号,请运行 gcloud projects add-iam-policy-binding 命令。

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member=serviceAccount:SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com \
      --role=roles/pubsub.publisher
    
    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member=serviceAccount:SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com \
      --role=roles/healthcare.hl7V2Consumer
    

    输出包括更新后的政策:

    bindings:
        - members:
            - user:SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com
            role: roles/pubsub.publisher
        - members:
            - user:SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com
            roles/healthcare.hl7V2Consumer
        etag: ETAG
        version: 1
    
  3. 要创建服务账号密钥,请运行 gcloud iam service-accounts keys create 命令。

    gcloud iam service-accounts keys create ~/FILENAME.json \
       --iam-account=SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com
    

    创建服务账号后,系统会将包含服务账号凭据的 JSON 密钥文件下载到您的计算机。

以下步骤展示了如何在 Compute Engine 中创建 Linux 虚拟机实例:

控制台

  1. 在 Google Cloud 控制台中,进入虚拟机实例页面。

    转到“虚拟机实例”页面

  2. 点击创建实例

  3. 为与您在创建集群时所选可用区匹配的实例选择区域可用区。例如,如果在创建集群时为 COMPUTE_ZONE 使用了 us-central1-a,则在实例创建屏幕中,为区域选择 us-central1 (Iowa),为可用区选择 us-central1-a

  4. 启动磁盘部分中,点击更改以开始配置您的启动磁盘。

  5. 公共映像标签页上,选择 Debian 操作系统的版本 9

  6. 点击选择

  7. 身份和 API 访问权限部分,选择您创建的服务账号。

  8. 防火墙部分,选择允许 HTTP 流量

  9. 点击创建以创建实例。

gcloud

要创建计算实例,请使用以下选项运行 gcloud compute instances create 方法:

  • 您在创建集群时选择的 ZONE
  • 允许 HTTP 流量的 http-server 代码
  • 您创建的 SERVICE_ACCOUNT
gcloud compute instances create COMPUTE_NAME \
   --project=PROJECT_ID \
   --zone=ZONE \
   --image-family=debian-9 \
   --image-project=debian-cloud \
   --tags=http-server \
   --service-account=SERVICE_ACCOUNT

输出类似于以下示例:

Created [https://www.googleapis.com/compute/v1/projects/PROJECT_ID/zones/ZONE/instances/COMPUTE_NAME].
NAME          ZONE           MACHINE_TYPE   PREEMPTIBLE  INTERNAL_IP  EXTERNAL_IP    STATUS
COMPUTE_NAME  ZONE           n1-standard-1               INTERNAL_IP  EXTERNAL_IP    RUNNING

实例启动需要您稍等片刻。启动实例后,该实例将在“虚拟机实例”页面列出,并带有绿色状态图标。

默认情况下,实例使用的默认 VPC 网络与集群使用的相同,这意味着流量可以从实例发送到集群。

要连接到实例,请完成以下步骤:

控制台

  1. 在 Google Cloud 控制台中,打开虚拟机实例页面。

    转到“虚拟机实例”页面

  2. 在虚拟机实例列表中,点击您创建的实例行中的 SSH

gcloud

要连接到实例,请运行 gcloud compute ssh 命令:

gcloud compute ssh INSTANCE_NAME \
    --project PROJECT_ID \
    --zone ZONE

您现在具有一个用来与您的 Linux 实例互动的终端窗口。

  1. 在终端窗口中,安装 Netcat

    sudo apt install netcat
    
  2. 下载 hl7v2-mllp-sample.txt 文件并将其保存到实例。如需了解文件中使用的编码和细分终止符,请参阅 HL7v2 消息细分分隔符和编码

  3. 要开始通过 MLLP 适配器将 HL7v2 消息发送到您的 HL7v2 存储区,请在下载该文件的目录中运行以下命令。使用您在检查 Service 时显示的 LoadBalancer Ingress 值。

    echo -n -e "\x0b$(cat hl7v2-mllp-sample.txt)\x1c\x0d" | nc LOAD_BALANCER_INGRESS_IP_ADDRESS 2575
    

    运行该命令后,系统会通过 MLLP 适配器将消息发送到您的 HL7v2 存储区。如果已将消息成功提取到 HL7v2 存储区中,则该命令将返回以下输出:

    MSA|AA|20150503223000|ILITY|FROM_APP|FROM_FACILITY|20190312162410||ACK|f4c59243-19c2-4373-bea0-39c1b2ba616b|P|2.5
    

    此输出表明 HL7v2 存储区以 AA (Application Accept) 响应类型进行响应,这意味着消息已通过验证并成功提取。

  4. 如需查看发布到 Pub/Sub 主题的消息,请运行 gcloud pubsub subscriptions pull 命令:

    gcloud pubsub subscriptions pull --auto-ack PUBSUB_SUBSCRIPTION
    

    该命令返回有关提取的 HL7v2 消息的以下输出:

    ┌-----------------------------------------------------------------------------------------------------------------|-----------------|---------------┐
    |                                                               DATA                                              |    MESSAGE_ID   |   ATTRIBUTES  |
    ├-----------------------------------------------------------------------------------------------------------------|-----------------|---------------|
    | projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages/HL7V2_MESSAGE_ID | 123456789012345 | msgType=ADT   |
    └-----------------------------------------------------------------------------------------------------------------|-----------------|---------------┘
    
  5. 您还可以列出 HL7v2 存储区中的消息,以查看消息是否已添加:

    curl

    curl -X GET \
         -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
         -H "Content-Type: application/json; charset=utf-8" \
         "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages"
    

    如果请求成功,服务器将在资源路径中返回消息的 ID:

    {
      "hl7V2Messages": [
        {
          "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages/MESSAGE_ID"
        }
      ]
    }
    

    PowerShell

    $cred = gcloud auth application-default print-access-token
    $headers = @{ Authorization = "Bearer $cred" }
    
    Invoke-WebRequest `
      -Method Get `
      -Headers $headers `
      -ContentType: "application/json; charset=utf-8" `
      -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages" | Select-Object -Expand Content
    

    如果请求成功,服务器将在资源路径中返回消息的 ID:

    {
      "hl7V2Messages": [
        {
          "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages/MESSAGE_ID"
        }
      ]
    }
    

完成此部分后,您已将 MLLP 适配器成功部署到 GKE,并通过该适配器将一条 HL7v2 消息从远程实例发送到了 Cloud Healthcare API。

在本教程的其余部分中,您将学习如何在 Compute Engine 实例(充当“本地”实例)和适配器之间配置 VPN,从而安全地为传输的 HL7v2 消息加密。

配置 VPN

使用 VPN 允许您通过公共网络(例如互联网)扩展用于发送 HL7v2 消息的专用网络。通过使用 VPN,您可以通过 MLLP 适配器将消息从您的护理中心发送到 Google Cloud。此流程中的系统会像在单个专用网络上一样运行。

有两种方法可以使用 VPN 来保护 MLLP 连接:

配置 Cloud VPN

Cloud VPN 通过 IPsec VPN 连接将您的本地网络安全地连接到 Google Cloud Virtual Private Cloud (VPC) 网络。两个网络之间的流量传输通过一个 VPN 网关加密,然后通过另一个 VPN 网关解密,这样可以在通过互联网或通过护理中心网络传输数据时保护数据。

在本教程中,您配置的每个 VPN 网关都位于不同的自定义网络和不同的 Google Cloud 区域内的子网中。

us-central1 中配置的 VPN 网关在 Google Cloud 端充当 Cloud VPN 网关,而 europe-west1 中的 Cloud VPN 网关模拟您的“本地”网关。

命名和寻址参考

出于参考用途,本教程入门使用以下命名和 IP 地址:

Google Cloud 端

  • 网络名称:cloud-vpn-network
  • 子网名称:subnet-us-central-10-0-1
  • 区域:us-central1
  • 子网范围:10.0.1.0/24
  • 外部 IP 地址名称:cloud-vpn-ip
  • VPN 网关名称:vpn-us-central
  • VPN 隧道名称:vpn-us-central-tunnel-1

“本地”端

  • 网络名称:on-prem-vpn-network
  • 子网名称:subnet-europe-west-10-0-2
  • 区域:europe-west1
  • 子网范围:10.0.2.0/24
  • 外部 IP 地址名称:on-prem-vpn-ip
  • VPN 网关名称:vpn-europe-west
  • VPN 隧道名称:vpn-europe-west-tunnel-1

创建自定义 VPC 网络和子网

配置 Cloud VPN 的第一步是创建两个 VPC 网络。一个名为 on-prem-vpn-network 的网络在“本地”环境中进行配置,并在名为 on-prem-instance 的 Compute Engine 虚拟机实例上运行。另一个网络(称为 cloud-vpn-network)是运行 MLLP 适配器的 GKE 集群使用的网络。您需要连接到 on-prem-instance 虚拟机,并通过 MLLP 适配器的内部负载均衡器向在 cloud-vpn-network 网络下运行的 MLLP 适配器发送 HL7v2 消息。

通过完成以下步骤创建两个自定义 VPC 网络及其子网:

  1. 要创建第一个 VPC 网络 cloud-vpn-network,请运行以下命令:

    gcloud compute networks create cloud-vpn-network \
       --project=PROJECT_ID \
       --subnet-mode=custom
    
  2. 要为 cloud-vpn-network 网络创建 subnet-us-central-10-0-1 子网,请运行以下命令:

    gcloud compute networks subnets create subnet-us-central-10-0-1 \
       --project=PROJECT_ID \
       --region=us-central1 \
       --network=cloud-vpn-network \
       --range=10.0.1.0/24
    
  3. 要创建 on-prem-vpn-network VPC 网络,请运行以下命令:

    gcloud compute networks create on-prem-vpn-network \
       --project=PROJECT_ID \
       --subnet-mode=custom
    
  4. 要为 on-prem-vpn-network VPC 网络创建 subnet-europe-west-10-0-2 子网,请运行以下命令:

    gcloud compute networks subnets create subnet-europe-west-10-0-2 \
       --project=PROJECT_ID \
       --region=europe-west1 \
       --network=on-prem-vpn-network \
       --range=10.0.2.0/24
    

创建外部 IP 地址

在创建 VPN 网关之前,请通过完成以下步骤为每个网关保留外部 IP 地址:

  1. 要为 cloud-vpn-ip 地址保留区域外部(静态)IP 地址,请运行以下命令:

    gcloud compute addresses create cloud-vpn-ip \
       --project=PROJECT_ID \
       --region=us-central1
    
  2. 要为 on-prem-vpn-ip 地址保留区域外部(静态)IP 地址,请运行以下命令:

    gcloud compute addresses create on-prem-vpn-ip \
       --project=PROJECT_ID \
       --region=europe-west1
    
  3. 记下外部 IP 地址,以便在下一部分中使用它们配置 VPN 网关。要检索外部 IP 地址,请运行以下命令:

    Cloud VPN IP 地址

    gcloud compute addresses describe cloud-vpn-ip  \
       --project PROJECT_ID \
       --region us-central1 \
       --format='flattened(address)'
    

    “本地”VPN IP 地址

    gcloud compute addresses describe on-prem-vpn-ip \
       --project PROJECT_ID \
       --region europe-west1 \
       --format='flattened(address)'
    

    这些命令会返回类似于以下内容的输出:

    address: 203.0.113.1
    

创建 VPN 网关、隧道和路由

完成以下步骤,为 Cloud VPN 创建 VPN 网关、隧道和路由:

  1. 按照生成强预共享密钥中的说明创建加密型强预共享密钥(共享密钥令牌)。此密钥在本部分中引用为 SHARED_SECRET

  2. 要创建目标 VPN 网关对象,请运行以下命令:

    gcloud compute target-vpn-gateways create vpn-us-central \
       --project PROJECT_ID \
       --region us-central1 \
       --network cloud-vpn-network
    
  3. 要创建三条转发规则,请运行以下命令,并将 CLOUD_VPN_EXTERNAL_ADDRESS 变量替换为上一部分中 Cloud VPN IP 地址的值:

    向网关发送 ESP (IPsec) 流量

    gcloud compute forwarding-rules create vpn-us-central-rule-esp \
        --project PROJECT_ID \
        --region us-central1 \
        --address CLOUD_VPN_EXTERNAL_ADDRESS \
        --ip-protocol ESP \
        --target-vpn-gateway vpn-us-central
    

    将 UDP 500 流量发送到网关

    gcloud compute forwarding-rules create vpn-us-central-rule-udp500 \
        --project PROJECT_ID \
        --region us-central1 \
        --address CLOUD_VPN_EXTERNAL_ADDRESS \
        --ip-protocol UDP \
        --ports 500 \
        --target-vpn-gateway vpn-us-central
    

    向网关发送 UDP 4500 流量

    gcloud compute forwarding-rules create vpn-us-central-rule-udp4500 \
        --project PROJECT_ID \
        --region us-central1 \
        --address CLOUD_VPN_EXTERNAL_ADDRESS \
        --ip-protocol UDP \
        --ports 4500 \
        --target-vpn-gateway vpn-us-central
    
  4. 要创建连接到 Cloud VPN 网关的隧道,请运行以下命令。将 ON_PREM_VPN_IP 替换为上一部分中“本地” VPN IP 地址中的值。

    gcloud compute vpn-tunnels create vpn-us-central-tunnel-1 \
        --project PROJECT_ID \
        --region us-central1 \
        --peer-address ON_PREM_VPN_IP \
        --shared-secret SHARED_SECRET \
        --ike-version 2 \
        --local-traffic-selector 0.0.0.0/0 \
        --target-vpn-gateway vpn-us-central
    
  5. 要创建到 10.0.2.0/24 的静态路由,请运行以下命令:

    gcloud compute routes create "vpn-us-central-tunnel-1-route-1" \
       --project PROJECT_ID \
       --network "cloud-vpn-network" \
       --next-hop-vpn-tunnel "vpn-us-central-tunnel-1" \
       --next-hop-vpn-tunnel-region "us-central1" \
       --destination-range "10.0.2.0/24"
    

完成以下步骤,为“本地”VPN 创建 VPN 网关、隧道和路由:

  1. 要创建目标 VPN 网关对象,请运行以下命令:

    gcloud compute target-vpn-gateways create "vpn-europe-west" \
       --project PROJECT_ID \
       --region "europe-west1" \
       --network "on-prem-vpn-network"
    
  2. 要创建三条转发规则,请运行以下命令,并将 ON_PREMISES_VPN_EXTERNAL_ADDRESS 变量替换为上一部分中“本地”VPN IP 地址中的值:

    向网关发送 ESP (IPsec) 流量

    gcloud compute forwarding-rules create vpn-europe-west-rule-esp \
        --project PROJECT_ID \
        --region europe-west1 \
        --address ON_PREMISES_VPN_EXTERNAL_ADDRESS \
        --ip-protocol ESP \
        --target-vpn-gateway vpn-europe-west
    

    将 UDP 500 流量发送到网关

    gcloud compute forwarding-rules create vpn-europe-west-rule-udp500 \
        --project PROJECT_ID \
        --region europe-west1 \
        --address ON_PREMISES_VPN_EXTERNAL_ADDRESS \
        --ip-protocol UDP \
        --ports 500 \
        --target-vpn-gateway vpn-europe-west
    

    向网关发送 UDP 4500 流量

    gcloud compute forwarding-rules create vpn-europe-west-rule-udp4500 \
         --project PROJECT_ID \
         --region europe-west1 \
         --address ON_PREMISES_VPN_EXTERNAL_ADDRESS \
         --ip-protocol UDP \
         --ports 4500 \
         --target-vpn-gateway vpn-europe-west
    
  3. 要创建连接到“本地”网关的隧道,请运行以下命令:

    gcloud compute vpn-tunnels create vpn-europe-west-tunnel-1 \
       --project PROJECT_ID \
       --region europe-west1 \
       --peer-address CLOUD_VPN_IP \
       --shared-secret SHARED_SECRET \
       --ike-version 2 \
       --local-traffic-selector 0.0.0.0/0 \
       --target-vpn-gateway vpn-europe-west
    
  4. 要创建到 10.0.1.0/24 的静态路由,请运行以下命令:

    gcloud compute routes create "vpn-europe-west-tunnel-1-route-1" \
       --project PROJECT_ID \
       --network "on-prem-vpn-network" \
       --next-hop-vpn-tunnel "vpn-europe-west-tunnel-1" \
       --next-hop-vpn-tunnel-region "europe-west1" \
       --destination-range "10.0.1.0/24"
    

您已创建 Cloud VPN 和“本地”网关并启动了其隧道。在您创建防火墙规则以允许流量通过它们之间的隧道之前,这些 VPN 网关不会连接。

创建防火墙规则

您必须为 VPN 隧道的两端创建防火墙规则。这些规则允许所有 TCP、UDP 和 ICMP 流量从 VPN 隧道一端的子网进入并流向另一端。

  1. 要为 Cloud VPN 子网创建防火墙规则,请运行以下命令:

    gcloud compute firewall-rules create allow-tcp-udp-icmp-cloud-vpn \
       --project=PROJECT_ID \
       --direction=INGRESS \
       --priority=1000 \
       --network=cloud-vpn-network \
       --action=ALLOW \
       --rules=tcp,udp,icmp \
       --source-ranges=10.0.2.0/24
    
  2. 要为“本地”子网创建防火墙规则,请运行以下命令:

    gcloud compute firewall-rules create allow-tcp-udp-icmp-on-prem-vpn \
       --project=PROJECT_ID \
       --direction=INGRESS \
       --priority=1000 \
       --network=on-prem-vpn-network \
       --action=ALLOW \
       --rules=tcp,udp,icmp \
       --source-ranges=10.0.1.0/24
    
  3. 创一条建防火墙规则,允许通过运行以下命令来让 SSH 连接到端口 22 上的虚拟机实例:

    gcloud compute firewall-rules create on-prem-vpn-allow-ssh \
       --project=PROJECT_ID \
       --direction=INGRESS \
       --priority=1000 \
       --network=on-prem-vpn-network \
       --action=ALLOW \
       --rules=tcp:22 \
       --source-ranges=0.0.0.0/0
    

检查 VPN 隧道的状态

要验证隧道是否已启动,请完成以下步骤:

  1. 进入 Google Cloud 控制台中的 VPN 页面。

    转到 VPN 页面

  2. 点击 Google VPN 隧道标签页。

  3. 在每个隧道的状态字段中,查找绿色对勾标记和“已建立”字样。如果有这些项目,则说明您的网关已经协商好了隧道。如果几分钟后没有标记出现,则请参阅问题排查

    如需了解与 VPN 隧道相关的其他日志记录信息,请参阅“问题排查”页面上的检查 VPN 日志。例如,您可以查看有关已丢弃数据包、隧道状态、已接收字节和已发送字节的指标。

现在,您已成功为 Cloud VPN 配置必要的网关、隧道和防火墙规则,现在可以在“本地”虚拟机实例与在 GKE 上运行的 MLLP 适配器之间创建安全连接。

将 Deployment 合并到 GKE 和 Cloud VPN

在本教程前面的部分中,您在本地测试了 MLLP 适配器通过非 VPN 连接向该 MLLP 适配器发送了 HL7v2 消息,而现在您需要使用 Cloud VPN,通过安全连接从 Compute Engine 虚拟机向在 GKE 上运行的 MLLP 适配器发送消息。然后,系统会将这些消息转发到 HL7v2 存储区。

重新创建 Deployment

首先,在 GKE 上重新创建部署,以便集群使用您在配置 Cloud VPN 中配置的设置:

  1. 要删除您创建的 mllp-adapter 集群,请运行 gcloud container clusters delete 命令。输入您在创建集群时使用的 COMPUTE_ZONE 值。

    gcloud container clusters delete mllp-adapter --zone=COMPUTE_ZONE
    
  2. 按照将 MLLP 适配器部署到 Kubernetes Engine 中的步骤操作,但在 GKE 中创建集群时,添加您在创建自定义 VPN 网络和子网中创建的 cloud-vpn-network 网络和 subnet-us-central-10-0-1 子网。

    确保集群创建命令如下所示:

    gcloud container clusters create mllp-adapter \
       --zone=COMPUTE_ZONE \
       --service-account=CLIENT_EMAIL \
       --network=cloud-vpn-network \
       --subnetwork=subnet-us-central-10-0-1
    

    其中:

    • COMPUTE_ZONE 是部署集群的可用区。在上一部分中配置 Cloud VPN 时,您将“Google Cloud 端”网络设置为使用 us-central1。此“Google Cloud 端”网络是运行 GKE 集群的网络。在 us-central1 中使用以下任一可用区:us-central1-cus-central1-aus-central1-fus-central1-b

    • CLIENT_EMAIL 是服务账号的标识符。您可以在 "client_email": 字段的服务账号密钥文件中找到此信息。其格式如下:SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com。

使用网络设置创建新的 Compute Engine 虚拟机

以下步骤展示了如何使用 Google Cloud 控制台在 Compute Engine 中创建 Linux 虚拟机实例。与您创建的 Compute Engine 虚拟机不同,此虚拟机使用“本地端”网络设置通过 VPN 与 GKE 集群进行通信。

控制台

  1. 在 Google Cloud 控制台中,打开虚拟机实例页面。

    转到“虚拟机实例”页面

  2. 点击创建实例

  3. 为与“本地端”网络设置匹配的实例选择区域可用区:为区域选择 europe-west1 (Belgium),为可用区选择 europe-west1-b

  4. 启动磁盘部分中,点击更改以开始配置您的启动磁盘。

  5. 公共映像标签页上,选择 Debian 操作系统的版本 9

  6. 点击选择

  7. 身份和 API 访问权限部分,选择您创建的服务账号。

  8. 防火墙部分,选择允许 HTTP 流量

  9. 展开管理、安全、磁盘、网络、单独租用部分。

  10. 网络标签页的网络接口下方,指定“本地端”网络设置的网络详细信息。

    1. 网络字段中,选择 on-prem-vpn-network
    2. 子网字段,选择 subnet-europe-west-10-0-2 (10.0.2.0/24)
  11. 点击创建以创建实例。

实例启动需要您稍等片刻。准备就绪后,它会在“虚拟机实例”页面上列出,并带有绿色状态图标。

gcloud

要创建计算实例,请使用以下选项运行 gcloud compute instances create 方法:

  • “本地”端网络设置匹配的 ZONE:为区域选择 europe-west1-b
  • 通过指定 http-server 标记允许 HTTP 流量
  • 您创建的 SERVICE_ACCOUNT
gcloud compute instances create COMPUTE_NAME \
   --project=PROJECT_ID
   --zone=ZONE
   --image-family=debian-9 \
   --tags=http-server,https-server
   --service-account=SERVICE_ACCOUNT

输出类似于以下示例:

Created [https://www.googleapis.com/compute/v1/projects/PROJECT_ID/zones/ZONE/instances/COMPUTE_NAME].
NAME          ZONE           MACHINE_TYPE   PREEMPTIBLE  INTERNAL_IP  EXTERNAL_IP    STATUS
COMPUTE_NAME  ZONE           n1-standard-1               INTERNAL_IP  EXTERNAL_IP    RUNNING

要连接到实例,请完成以下步骤:

控制台

  1. 在 Google Cloud 控制台中,打开虚拟机实例页面。

    转到“虚拟机实例”页面

  2. 在虚拟机实例列表中,点击您创建的实例行中的 SSH

gcloud

要连接到实例,请运行 gcloud compute ssh 命令:

gcloud compute ssh INSTANCE_NAME \
    --project PROJECT_ID \
    --zone ZONE

您现在具有一个用来与您的 Linux 实例互动的终端窗口。

  1. 在终端窗口中,安装 Netcat

    sudo apt install netcat
    
  2. 下载 hl7v2-mllp-sample.txt 文件并将其保存到实例。

  3. 要开始通过 MLLP 适配器将 HL7v2 消息发送到您的 HL7v2 存储区,请在下载该文件的目录中运行以下命令。使用您在检查 Service 时显示的 LoadBalancer Ingress 值。

    echo -n -e "\x0b$(cat hl7v2-mllp-sample.txt)\x1c\x0d" | nc LOAD_BALANCER_INGRESS_IP_ADDRESS 2575
    

    运行该命令后,系统会通过 MLLP 适配器将消息发送到您的 HL7v2 存储区。如果已将消息成功提取到 HL7v2 存储区中,则该命令将返回以下输出:

    MSA|AA|20150503223000|ILITY|FROM_APP|FROM_FACILITY|20190312162410||ACK|f4c59243-19c2-4373-bea0-39c1b2ba616b|P|2.5
    

    此输出表明 HL7v2 存储区以 AA (Application Accept) 响应类型进行响应,这意味着消息已通过验证并成功提取。

  4. 如需查看发布到 Pub/Sub 主题的消息,请运行 gcloud pubsub subscriptions pull 命令:

    gcloud pubsub subscriptions pull --auto-ack PUBSUB_SUBSCRIPTION
    

    该命令返回有关提取的 HL7v2 消息的以下输出:

    ┌-----------------------------------------------------------------------------------------------------------------|-----------------|---------------┐
    |                                                               DATA                                              |    MESSAGE_ID   |   ATTRIBUTES  |
    ├-----------------------------------------------------------------------------------------------------------------|-----------------|---------------|
    | projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages/HL7V2_MESSAGE_ID | 123456789012345 | msgType=ADT   |
    └-----------------------------------------------------------------------------------------------------------------|-----------------|---------------┘
    
  5. 您还可以列出 HL7v2 存储区中的消息,以查看消息是否已添加:

    curl

    curl -X GET \
         -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
         -H "Content-Type: application/json; charset=utf-8" \
         "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages"
    

    如果请求成功,服务器将在资源路径中返回消息的 ID:

    {
      "hl7V2Messages": [
        {
          "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages/MESSAGE_ID"
        }
      ]
    }
    

    PowerShell

    $cred = gcloud auth application-default print-access-token
    $headers = @{ Authorization = "Bearer $cred" }
    
    Invoke-WebRequest `
      -Method Get `
      -Headers $headers `
      -ContentType: "application/json; charset=utf-8" `
      -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages" | Select-Object -Expand Content
    

    如果请求成功,服务器将在资源路径中返回消息的 ID:

    {
      "hl7V2Messages": [
        {
          "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/hl7V2Stores/HL7V2_STORE_ID/messages/MESSAGE_ID"
        }
      ]
    }
    

完成此部分后,您已将 MLLP 适配器成功部署到 GKE,并使用 VPN,通过该适配器将一条 HL7v2 消息从“本地”实例安全地发送到了 Cloud Healthcare API。

清理

为避免系统因本快速入门中使用的资源向您的 Google Cloud 账号收取费用,您可以清理在 Google Cloud 上创建的资源。

删除项目

按照以下步骤删除您在本教程中创建的项目:

  1. 在 Google Cloud 控制台中,进入管理资源页面。

    转到“管理资源”

  2. 在项目列表中,选择要删除的项目,然后点击删除
  3. 在对话框中输入项目 ID,然后点击关闭以删除项目。

问题排查

适配器故障

将 MLLP 适配器部署到 GKE 后,该适配器发生故障。

在本地运行时出现 Connection refused 错误

在本地测试 MLLP 适配器时,您会遇到错误 Connection refused

  • 某些 Mac OS 用户会遇到此错误。请使用 -p 2575:2575,而不要使用 --network=host 标志。此外,请设置 --receiver_ip=0.0.0.0,而不是设置 --receiver_ip=127.0.0.0。该命令应如下所示:

    docker run \
      -p 2575:2575 \
      gcr.io/cloud-healthcare-containers/mllp-adapter \
      /usr/mllp_adapter/mllp_adapter \
      --hl7_v2_project_id=PROJECT_ID \
      --hl7_v2_location_id=LOCATION \
      --hl7_v2_dataset_id=DATASET_ID \
      --hl7_v2_store_id=HL7V2_STORE_ID \
      --export_stats=false \
      --receiver_ip=0.0.0.0 \
      --pubsub_project_id=PROJECT_ID \
      --pubsub_subscription=PUBSUB_SUBSCRIPTION \
      --api_addr_prefix=https://healthcare.googleapis.com:443/v1 \
      --logtostderr
    

在本地运行时出现 could not find default credentials 错误

在本地测试 MLLP 适配器时,您会遇到错误 healthapiclient.NewHL7V2Client: oauth2google.DefaultTokenSource: google: could not find default credentials. See https://developers.google.com/accounts/docs/application-default-credentials for more information.

当适配器找不到您的 Google Cloud 凭据时,会出现此错误。要修复该错误,请在重新运行该命令之前尝试以下方法之一:

身份验证错误

如果您在在本地测试 MLLP 适配器时遇到任何身份验证错误(本部分其他地方并未介绍的错误),请重新运行 docker run 命令并在命令末尾添加 -v ~/.config:/root/.config 标志,如下所示:

docker run \
-v ~/.config:/root/.config \
...