为内部 HTTP(S) 负载平衡器设置 HTTP 到 HTTPS 重定向

本示例演示了对端口 80 的所有请求如何重定向到其各自的 HTTPS 服务。

如需了解如何为外部负载平衡设置 HTTP 到 HTTPS 重定向,请参阅为外部 HTTP(S) 负载平衡器设置 HTTP 到 HTTPS 重定向

为使用具有共享 IP 地址的 HTTP 到 HTTPS 重定向,您必须创建两个负载平衡器,一个用于 HTTPS 流量,另一个用于 HTTP 流量。每个负载平衡器都有自己的转发规则和网址映射,但共享相同的 IP 地址。对于 HTTP 负载平衡器,您无需配置后端,因为前端会将流量重定向到 HTTPS 负载平衡器的后端。

本示例演示了如何将所有请求从端口 80 重定向到端口 443。

概括来讲,如需将 HTTP 流量重定向到 HTTPS,您必须执行以下操作:

  1. 使用预留的共享内部 IP 地址创建普通内部 HTTPS 负载平衡器。
  2. 测试内部 HTTPS 负载平衡器,以确保其正常运行。
  3. 将流量重定向到内部 HTTPS 负载平衡器。
    为此,您必须添加具有前端但没有后端的部分内部 HTTP 负载平衡器。前端接收请求,然后将其重定向到内部 HTTPS 负载平衡器。它通过使用以下要素来执行此操作:
    • 具有您的 HTTPS 负载平衡器所使用的预留内部 IP 地址的转发规则(请查看第 1 步)
    • 目标 HTTP 代理
    • 将流量重定向到 HTTPS 负载平衡器的网址映射

如下图所示,内部 HTTPS 负载平衡器是具有预期的负载平衡器组件的普通负载平衡器。

HTTP 负载平衡器具有与 HTTPS 负载平衡器相同的 IP 地址,在网址映射中有重定向指令,并且没有后端。

内部 HTTP 到 HTTPS 重定向配置(点击可放大)
内部 HTTP 到 HTTPS 重定向配置

创建内部 HTTPS 负载平衡器

此过程与设置内部 HTTP(S) 负载平衡器类似。

内部 HTTP(S) 负载平衡的设置包括两个部分:

  • 执行前提任务,例如确保所需帐号拥有正确权限以及准备 Virtual Private Cloud (VPC) 网络。
  • 设置负载平衡器资源。

在按照本指南进行操作之前,请先熟悉以下内容:

权限

若要按照本指南中的说明进行操作,您必须能够创建实例以及修改项目中的网络。因此,您必须是项目 Owner 或 Editor,或者必须具有以下所有 Compute Engine IAM 角色

任务 所需角色
创建网络、子网和负载平衡器组件 Network Admin
添加和移除防火墙规则 Security Admin
创建实例 Instance Admin

如需了解详情,请参阅以下指南:

配置网络和子网

您需要一个包含两个子网的 VPC 网络:一个用于负载平衡器的后端,另一个用于负载平衡器的代理。内部 HTTP(S) 负载平衡器是地区负载平衡器。对于 VPC 网络中的流量,如果其来源所在的子网与负载平衡器位于同一地区,那么该流量会被路由到负载平衡器。

本示例使用以下 VPC 网络、地区和子网:

  • 网络:网络是名为 lb-network自定义模式 VPC 网络

  • 后端子网us-west1 地区中名为 backend-subnet 的子网使用 10.1.2.0/24 作为其主要 IP 地址范围。

  • 代理子网us-west1 地区中名为 proxy-only-subnet 的子网使用 10.129.0.0/23 作为其主要 IP 地址范围。

为后端配置网络和子网

控制台

  1. 转到 Google Cloud Console 中的“VPC 网络”页面。
    转到“VPC 网络”页面
  2. 点击创建 VPC 网络
  3. 对于名称,请输入 lb-network
  4. 子网部分中执行以下操作:
    • 子网创建模式设置为自定义
    • 新子网部分中,输入以下信息:
      • 名称backend-subnet
      • 地区us-west1
      • IP 地址范围10.1.2.0/24
    • 点击完成
  5. 点击创建

gcloud

  1. 使用 gcloud compute networks create 命令创建自定义 VPC 网络:

    gcloud compute networks create lb-network --subnet-mode=custom
    
  2. 使用 gcloud compute networks subnets create 命令在 us-west1 地区的 lb-network 网络中创建子网:

    gcloud compute networks subnets create backend-subnet \
        --network=lb-network \
        --range=10.1.2.0/24 \
        --region=us-west1
    

API

networks.insert 方法发出 POST 请求,并将 PROJECT_ID 替换为您的项目 ID。

POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/networks

{
  "routingConfig": {
    "routingMode": "REGIONAL"
  },
  "name": "lb-network",
  "autoCreateSubnetworks": false
}

subnetworks.insert 方法发出 POST 请求,并将 PROJECT_ID 替换为您的项目 ID。

POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/regions/us-west1/subnetworks

{
  "name": "backend-subnet",
  "network": "projects/project-id/global/networks/lb-network",
  "ipCidrRange": "10.1.2.0/24",
  "region": "projects/project-id/regions/us-west1",
}

配置代理专用子网

代理专用子网适用于 us-west1 地区内的所有内部 HTTP(S) 负载平衡器。

控制台

如果您使用的是 Google Cloud Console,则可以稍后在“负载平衡”页面上创建代理专用子网。

gcloud

使用 gcloud compute networks subnets create 命令创建代理专用子网。

gcloud compute networks subnets create proxy-only-subnet \
  --purpose=INTERNAL_HTTPS_LOAD_BALANCER \
  --role=ACTIVE \
  --region=us-west1 \
  --network=lb-network \
  --range=10.129.0.0/23

API

使用 subnetworks.insert 方法创建代理专用子网,并将 PROJECT_ID 替换为您的项目 ID。

POST https://compute.googleapis.com/compute/projects/PROJECT_ID/regions/us-west1/subnetworks

{
  "name": "proxy-only-subnet",
  "ipCidrRange": "10.129.0.0/23",
  "network": "projects/project-id/global/networks/lb-network",
  "region": "projects/project-id/regions/us-west1",
  "purpose": "INTERNAL_HTTPS_LOAD_BALANCER",
  "role": "ACTIVE"
}

配置防火墙规则

此示例使用以下防火墙规则:

  • fw-allow-ssh。适用于负载平衡实例的入站流量规则,该规则允许从任何地址到 TCP 端口 22 的传入 SSH 连接。您可以为此规则选择限制性更高的来源 IP 地址范围;例如,您可以仅指定要从中启动 SSH 会话的系统的 IP 地址范围。此示例使用目标标记 allow-ssh

  • fw-allow-health-check。适用于负载平衡实例的入站流量规则,该规则允许来自 Google Cloud 运行状况检查系统(130.211.0.0/2235.191.0.0/16)的所有 TCP 流量。此示例使用目标标记 load-balanced-backend

  • fw-allow-proxies。适用于负载平衡实例的入站流量规则,该规则允许从内部 HTTP(S) 负载平衡器的代管式代理发送到端口 804438080 的 TCP 流量。此示例使用目标标记 load-balanced-backend

如果不使用上述防火墙规则,则默认拒绝入站规则会阻止传入后端实例的流量。

目标标记定义了后端实例。没有目标标记,防火墙规则将应用于 VPC 网络中的所有后端实例。创建后端虚拟机时,请务必包括指定的目标标记,如创建代管实例组中所示。

控制台

  1. 转到 Google Cloud Console 中的“防火墙规则”页面。
    转到“防火墙规则”页面
  2. 点击创建防火墙规则,以创建允许传入 SSH 连接的规则:
    • 名称fw-allow-ssh
    • 网络lb-network
    • 流量方向入站
    • 对匹配项执行的操作允许
    • 目标指定的目标标记
    • 目标标记allow-ssh
    • 来源过滤条件IP 地址范围
    • 来源 IP 地址范围0.0.0.0/0
    • 协议和端口
      • 选择指定的协议和端口
      • 选中 tcp 复选框,然后输入 22 作为端口号。
  3. 点击创建
  4. 再次点击创建防火墙规则,创建允许 Google Cloud 运行状况检查的规则:
    • 名称fw-allow-health-check
    • 网络lb-network
    • 流量方向入站
    • 对匹配项执行的操作允许
    • 目标指定的目标标记
    • 目标标记load-balanced-backend
    • 来源过滤条件IP 地址范围
    • 来源 IP 地址范围130.211.0.0/2235.191.0.0/16
    • 协议和端口
      • 选择指定的协议和端口
      • 选中 tcp 复选框,然后输入 80 作为端口号。
        最佳做法是将此规则限制为仅使用与运行状况检查所使用的协议和端口匹配的协议和端口。如果您使用 tcp:80 协议和端口,则 Google Cloud 可以使用 HTTP 通过端口 80 联系您的虚拟机,但无法使用 HTTPS 通过端口 443 联系这些虚拟机。
  5. 点击创建
  6. 第三次点击创建防火墙规则,以创建允许负载平衡器的代理服务器连接后端的规则:
    • 名称fw-allow-proxies
    • 网络lb-network
    • 流量方向入站
    • 对匹配项执行的操作允许
    • 目标指定的目标标记
    • 目标标记load-balanced-backend
    • 来源过滤条件IP 地址范围
    • 来源 IP 地址范围10.129.0.0/23
    • 协议和端口
      • 选择指定的协议和端口
      • 选中 tcp 复选框,然后输入 80, 443, 8080 作为端口号。
  7. 点击创建

gcloud

  1. 创建 fw-allow-ssh 防火墙规则,允许通过 SSH 连接到网络标记为 allow-ssh 的虚拟机。如果省略 source-ranges,Google Cloud 会将规则解释为表示所有来源

    gcloud compute firewall-rules create fw-allow-ssh \
        --network=lb-network \
        --action=allow \
        --direction=ingress \
        --target-tags=allow-ssh \
        --rules=tcp:22
    
  2. 创建 fw-allow-health-check 规则以允许 Google Cloud 运行状况检查。本示例允许来自运行状况检查探测工具的所有 TCP 流量;但是,您可以根据自己的需求配置较小范围的端口集。

    gcloud compute firewall-rules create fw-allow-health-check \
        --network=lb-network \
        --action=allow \
        --direction=ingress \
        --source-ranges=130.211.0.0/22,35.191.0.0/16 \
        --target-tags=load-balanced-backend \
        --rules=tcp
    
  3. 创建 fw-allow-proxies 规则以允许内部 HTTP(S) 负载平衡器的代理连接到您的后端。 将 source-ranges 设置为该代理专用子网的分配范围,例如 10.129.0.0/23

    gcloud compute firewall-rules create fw-allow-proxies \
      --network=lb-network \
      --action=allow \
      --direction=ingress \
      --source-ranges=source-range \
      --target-tags=load-balanced-backend \
      --rules=tcp:80,tcp:443,tcp:8080
    

API

通过向 firewalls.insert 方法发出 POST 请求以创建 fw-allow-ssh 防火墙规则,注意要将 PROJECT_ID 替换为您的项目 ID。

POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/firewalls

{
  "name": "fw-allow-ssh",
  "network": "projects/project-id/global/networks/lb-network",
  "sourceRanges": [
    "0.0.0.0/0"
  ],
  "targetTags": [
    "allow-ssh"
  ],
  "allowed": [
   {
     "IPProtocol": "tcp",
     "ports": [
       "22"
     ]
   }
  ],
 "direction": "INGRESS"
}

通过向 firewalls.insert 方法发出 POST 请求以创建 fw-allow-health-check 防火墙规则,注意要将 PROJECT_ID 替换为您的项目 ID。

POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/firewalls

{
  "name": "fw-allow-health-check",
  "network": "projects/project-id/global/networks/lb-network",
  "sourceRanges": [
    "130.211.0.0/22",
    "35.191.0.0/16"
  ],
  "targetTags": [
    "load-balanced-backend"
  ],
  "allowed": [
    {
      "IPProtocol": "tcp"
    }
  ],
  "direction": "INGRESS"
}

通过 firewalls.insert 方法创建 fw-allow-proxies 防火墙规则,以允许代理子网内的 TCP 流量,注意要将 PROJECT_ID 替换为您的项目 ID。

POST https://compute.googleapis.com/compute/v1/projects/{project}/global/firewalls

{
  "name": "fw-allow-proxies",
  "network": "projects/project-id/global/networks/lb-network",
  "sourceRanges": [
    "10.129.0.0/23"
  ],
  "targetTags": [
    "load-balanced-backend"
  ],
  "allowed": [
    {
      "IPProtocol": "tcp",
      "ports": [
        "80"
      ]
    },
  {
      "IPProtocol": "tcp",
      "ports": [
        "443"
      ]
    },
    {
      "IPProtocol": "tcp",
      "ports": [
        "8080"
      ]
    }
  ],
  "direction": "INGRESS"
}

创建内部 HTTPS 负载平衡器资源

此示例使用 Compute Engine 上的代管式实例组中的虚拟机后端。您可以改为使用其他受支持的后端类型

使用 HTTP 服务器创建实例模板

gcloud

gcloud compute instance-templates create l7-ilb-backend-template \
    --region=us-west1 \
    --network=lb-network \
    --subnet=backend-subnet \
    --tags=allow-ssh,load-balanced-backend \
    --image-family=debian-9 \
    --image-project=debian-cloud \
    --metadata=startup-script='#! /bin/bash
    apt-get update
    apt-get install apache2 -y
    a2ensite default-ssl
    a2enmod ssl
    vm_hostname="$(curl -H "Metadata-Flavor:Google" \
    http://169.254.169.254/computeMetadata/v1/instance/name)"
    echo "Page served from: $vm_hostname" | \
    tee /var/www/html/index.html
    systemctl restart apache2'

在区域中创建代管式实例组

gcloud

gcloud compute instance-groups managed create l7-ilb-backend \
    --zone=us-west1-a \
    --size=2 \
    --template=l7-ilb-backend-template

创建 HTTP 运行状况检查

gcloud

gcloud compute health-checks create http l7-ilb-basic-check \
     --region=us-west1 \
     --use-serving-port

创建后端服务

gcloud

gcloud compute backend-services create l7-ilb-backend-service \
    --load-balancing-scheme=INTERNAL_MANAGED \
    --protocol=HTTP \
    --health-checks=l7-ilb-basic-check \
    --health-checks-region=us-west1 \
    --region=us-west1

将后端添加到后端服务

gcloud

gcloud compute backend-services add-backend l7-ilb-backend-service \
    --balancing-mode=UTILIZATION \
    --instance-group=l7-ilb-backend \
    --instance-group-zone=us-west1-a \
    --region=us-west1

创建网址映射

gcloud

gcloud compute url-maps create l7-ilb-service-url-map \
    --default-service=l7-ilb-backend-service \
    --region=us-west1

创建地区 SSL 证书

以下示例展示了如何使用 gcloud 创建自行管理的 SSL 证书。如需了解详情,请参阅使用自行管理的 SSL 证书使用 Google 管理的 SSL 证书

gcloud

gcloud compute ssl-certificates create CERTIFICATE_NAME \
    --certificate=CERTIFICATE_FILE \
    --private-key=PRIVATE_KEY_FILE \
    --region=us-west1

使用地区 SSL 证书创建目标代理

gcloud

gcloud compute target-https-proxies create l7-ilb-https-proxy \
    --url-map=l7-ilb-service-url-map \
    --region=us-west1 \
    --ssl-certificates=l7-ilb-cert

为转发规则预留共享 IP 地址

gcloud

gcloud beta compute addresses create \
    --addresses=10.1.2.99 \
    --region=us-west1 \
    --subnet=backend-subnet \
    --purpose=SHARED_LOADBALANCER_VIP

创建 HTTPS 转发规则

gcloud

gcloud compute forwarding-rules create l7-ilb-https-forwarding-rule \
    --load-balancing-scheme=INTERNAL_MANAGED \
    --network=lb-network \
    --subnet=backend-subnet \
    --address=10.1.2.99 \
    --ports=443 \
    --region=us-west1 \
    --target-https-proxy=l7-ilb-https-proxy \
    --target-https-proxy-region=us-west1

测试 HTTPS 负载平衡器

此时,负载平衡器(包括后端服务、网址映射和转发规则)已准备就绪。测试此负载平衡器以验证其是否按预期工作。

创建客户端虚拟机实例以测试连接性。

gcloud

gcloud compute instances create l7-ilb-client-us-west1-a \
    --image-family=debian-9 \
    --image-project=debian-cloud \
    --network=lb-network \
    --subnet=backend-subnet \
    --zone=us-west1-a \
    --tags=allow-ssh

通过 SSH 连接到客户端虚拟机。

gcloud

gcloud compute ssh l7-ilb-client-us-west1-a \
    --zone=us-west1-a

使用 Curl 连接到 HTTPS 负载平衡器。

curl -k -s 'https://10.1.2.99:443' --connect-to 10.1.2.99:443

示例输出:

Page served from: l7-ilb-backend-850t

发送 100 个请求并验证它们是否都已进行负载平衡。

{
  RESULTS=
  for i in {1..100}
  do
      RESULTS="$RESULTS:$(curl -k -s 'https://test.example.com:443' --connect-to test.example.com:443:10.1.2.99:443)"
  done
  echo "***"
  echo "*** Results of load-balancing to 10.1.2.99: "
  echo "***"
  echo "$RESULTS" | tr ':' '\n' | grep -Ev "^$" | sort | uniq -c
  echo
}

示例输出:

***
*** Results of load-balancing to 10.1.2.99:
***
     51  l7-ilb-backend-https-850t
     49  l7-ilb-backend-https-w11t
    100 Page served from

将流量重定向到 HTTPS 负载平衡器

HTTP 负载平衡器具有共享 IP 地址,可将流量从端口 80 重定向到 443。

创建新的网址映射以重定向流量

使用流量重定向配置创建 YAML 文件。

echo "defaultService: regions/us-west1/backendServices/l7-ilb-backend-service
kind: compute#urlMap
name: l7-ilb-redirect-url-map
hostRules:
- hosts:
  - '*'
  pathMatcher: matcher1
pathMatchers:
- name: matcher1
  defaultUrlRedirect:
        hostRedirect: 10.1.2.99:443
        pathRedirect: /
        redirectResponseCode: PERMANENT_REDIRECT
        httpsRedirect: True
        stripQuery: True" > /tmp/url_map.yaml

将 YAML 文件导入到新的网址映射。

gcloud

gcloud compute url-maps import l7-ilb-redirect-url-map \
    --source /tmp/url_map.yaml \
    --region us-west1

创建 HTTP 负载平衡器的目标代理

gcloud

gcloud compute target-http-proxies create l7-ilb-http-proxy \
    --url-map=l7-ilb-redirect-url-map \
    --url-map-region=us-west1 \
    --region=us-west1

创建新的转发规则和共享 IP 地址

gcloud

gcloud compute forwarding-rules create l7-ilb-forwarding-rule \
    --load-balancing-scheme=INTERNAL_MANAGED \
    --network=lb-network \
    --subnet=backend-subnet \
    --address=10.1.2.99 \
    --ports=80 \
    --region=us-west1 \
    --target-http-proxy=l7-ilb-http-proxy \
    --target-http-proxy-region=us-west1

测试流量重定向

连接到您的客户端虚拟机。

gcloud

gcloud compute ssh l7-ilb-client-us-west1-a \
    --zone=us-west1-a

向端口 80 上的 10.1.2.99 发送 HTTP 请求,需要进行流量重定向。

curl -L -k 10.1.2.99

输出示例。

Page served from: l7-ilb-backend-w11t

您可以添加 -vvv 以查看更多详细信息。

curl -L -k 10.1.2.99 -vvv

* Rebuilt URL to: 10.1.2.99/
*   Trying 10.1.2.99...
* TCP_NODELAY set
* Connected to 10.1.2.99 (10.1.2.99) port 80 (#0)
> GET / HTTP/1.1
> Host: 10.1.2.99
> User-Agent: curl/7.52.1
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< location: https://10.1.2.99:443/
< date: Fri, 07 Aug 2020 05:07:18 GMT
< via: 1.1 google
< content-length: 0
<
* Curl_http_done: called premature == 0
* Connection #0 to host 10.1.2.99 left intact
* Issue another request to this URL: 'https://10.1.2.99:443/'
*   Trying 10.1.2.99...
* TCP_NODELAY set
* Connected to 10.1.2.99 (10.1.2.99) port 443 (#1)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
...
...
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: O=Google TESTING; CN=test_cert_1
*  start date: Jan  1 00:00:00 2015 GMT
*  expire date: Jan  1 00:00:00 2025 GMT
*  issuer: O=Google TESTING; CN=Intermediate CA
*  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x561a6b0e3ea0)
> GET / HTTP/1.1
> Host: 10.1.2.99
> User-Agent: curl/7.52.1
> Accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
< HTTP/2 200
< date: Fri, 07 Aug 2020 05:07:18 GMT
< server: Apache/2.4.25 (Debian)
< last-modified: Thu, 06 Aug 2020 13:30:21 GMT
< etag: "2c-5ac357d7a47ec"
< accept-ranges: bytes
< content-length: 44
< content-type: text/html
< via: 1.1 google
<
Page served from: l7-ilb-backend-https-w11t
* Curl_http_done: called premature == 0
* Connection #1 to host 10.1.2.99 left intact

后续步骤