使用路由

本页面介绍如何在 Google Cloud 中为 Virtual Private Cloud (VPC) 网络创建和管理路由。本页面假定您熟悉路由中介绍的不同类型的 Google Cloud 路由及其特性。

每个新网络都具有两种由系统生成的路由:默认路由(您可以将其移除或替换);以及子网路由(每个子网具有一个对应的子网路由)。除非删除相应的子网本身,否则无法移除子网路由。

除了由系统生成的路由外,您还可以创建其他自定义静态路由

列出 VPC 网络的路由

您可以使用 Google Cloud CLI 或 API 列出和查看以下类型路由的详细信息:

gcloud CLI 命令和 API 方法均不会显示以下类型的路由:

如需查看完整的路由视图,请使用 Google Cloud 控制台。如需列出和描述基于政策的路由,请参阅使用基于政策的路由

控制台

  1. 在 Google Cloud 控制台中,转到路由页面。

    进入“路由”

  2. 有效路由标签页上,执行以下操作:

    • 选择 VPC 网络。
    • 选择一个区域。
  3. 点击视图

  4. 您可以按属性(包括路由类型、目的地 IP 范围和下一个跃点类型)过滤。

  5. 可选:点击 Show suppressed routes 切换开关切换到开启位置,以查看被抑制的路由。如需查看路线被抑制的原因,请将光标指向状态列中的图标。

gcloud

如需列出和查看路由的详细信息,请使用 gcloud compute routes 命令。系统会显示本地 VPC 网络和任何对等互连 VPC 网络中的子网路由和静态路由。其他路由类型不会显示。如需查看所有路由,请使用 Google Cloud 控制台。

如需列出路由,请执行以下操作:

gcloud compute routes list \
    --filter="network=NETWORK_NAME" \
    --project=PROJECT_ID

如需获取路由的详细信息,请执行以下操作:

gcloud compute routes describe ROUTE_NAME \
    --format="flattened()" \
    --project=PROJECT_ID

替换以下内容:

  • NETWORK_NAME:VPC 网络的名称。
  • PROJECT_ID:包含 VPC 网络的项目 ID。
  • ROUTE_NAME:路由的名称。

API

如需列出和查看路由的详细信息,请使用 routes.listroutes.get 方法。系统会显示本地 VPC 网络和任何对等互连 VPC 网络中的子网路由和静态路由。其他路由类型不会显示。如需查看所有路由,请使用 Google Cloud 控制台。

如需列出路由,请执行以下操作:

GET https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/routes?filter=network="NETWORK_URL

如需获取路由的详细信息,请执行以下操作:

GET https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/routes/ROUTE_NAME

替换以下内容:

  • PROJECT_ID:包含 VPC 网络的项目 ID。
  • NETWORK_URL:VPC 网络的网址。
  • ROUTE_NAME:路由的名称。

列出虚拟机网络接口的适用路由

您可以使用 Google Cloud 控制台查看虚拟机网络接口的适用路由。这种查看方式会将可用于出站流量的路由的列表缩小到一定的范围。

如需查看虚拟机特定网络接口的适用路由,请按照以下步骤操作。

控制台

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

    转到虚拟机实例

  2. 在列表中找到虚拟机实例。在该行末尾的 更多操作菜单中,选择查看网络详情

  3. 如果某个实例具有多个网络接口,请在网络接口详情部分中,选择您要查看的网络接口。

  4. 防火墙和路由详情部分中,点击路由标签页以查看适用于该网络接口的所有路由(按路由名称排序)。

添加和移除静态路由

您可以在 VPC 网络中添加或移除本地静态路由和基于政策的路由。本部分介绍如何添加和删除本地静态路由。如需详细了解如何添加和移除基于政策的路由,请参阅使用基于政策的路由

当您添加或删除子网时,子网路由会自动添加和删除。如需详细了解如何添加和移除子网,请参阅使用子网

由 VPC 网络对等互连连接的 VPC 网络中的所有路由都必须在导出这些路由的 VPC 网络中操作。如需了解详情,请参阅路由交换选项

添加静态路由前的准备工作

在添加静态路由之前,请考虑以下事项:

  • 请务必了解静态路由可以使用的不同类型的下一个跃点。如需了解不同类型的静态路由下一个跃点(包括哪些支持 IPv6 目标),请参阅下一个跃点和功能
  • 除非您使用混合子网,否则静态路由的目标范围不能与子网或对等互连子网路由的目标范围一致,也不能比其更具体。如需了解详情,请参阅路由概览中的与自定义静态路由的交互和 VPC 网络对等互连文档中的子网和静态路由交互
  • 为避免在使用自动模式 VPC 网络时发生冲突,请不要创建目标在 10.128.0.0/9 范围内的静态路由。如需了解详情,请查看自动模式 IPv4 范围
  • 自定义静态路由的目标不能与任何内部分配的范围重叠。
  • 在创建将虚拟机用作下一个跃点的自定义静态路由之前,请确保您熟悉充当下一个跃点的实例。如果您选择下一个跃点实例,Google Cloud 仅验证在创建路由时虚拟机存在。
  • 如果您使用网络标记创建路由,则只有具有该标记的虚拟机才会接收该路由。但是,已标记的 VM 仍会接收所有没有网络标记的路由。

添加静态路由

向网络添加静态路由。如需详细了解不同类型的静态路由下一个跃点(包括哪些支持 IPv6 目标),请参阅下一个跃点和功能

控制台

  1. 在 Google Cloud 控制台中,转到路由页面。

    进入“路由”

  2. 点击路由管理标签页。

  3. 点击创建路由

  4. 指定该路由的名称和说明。

  5. 网络列表中,为路由选择一个现有网络。

  6. 路由类型列表中,选择静态路由

  7. IP 版本列表中,选择所需的 IP 版本:

    • 如需创建 IPv4 静态路由,请选择 IPv4
    • 如需创建 IPv6 静态路由,请选择 IPv6
  8. 指定目标 IP 地址范围。支持的最宽泛目标是 0.0.0.0/0 (IPv4) 或 ::/0 (IPv6)。

  9. 指定该路由的优先级。优先级可以从 0(最高优先级)到 65535(最低优先级)。

  10. 如需使该路由仅适用于具有匹配网络标记的部分实例,请在实例标记字段中指定标记。如果将此字段留空,则该路由将适用于网络中的所有实例。

  11. 为该路由选择下一个跃点

    • 默认互联网网关:将数据包发送到互联网以及 Google API 和服务
    • 指定实例:将数据包发送到虚拟机实例的网络接口。请使用名称和可用区指定虚拟机实例。如果路由目标是 IPv6 地址,则虚拟机实例必须是双栈。
    • 指定实例的 IP 地址:指定 VPC 网络中现有实例的 IP 地址。对于 IPv6 静态路由(预览版),实例必须是双栈。如需了解有效的下一个跃点 IP 地址的重要限制,请参阅静态路由的下一个跃点
    • 指定 VPN 隧道使用静态路由将数据包发送到现有传统 VPN 隧道。
    • 指定内部直通式网络负载均衡器的转发规则:将数据包发送到内部直通式网络负载均衡器,该负载均衡器由其内部转发规则名称和区域指定。
  12. 点击创建

gcloud

使用以下 gcloud CLI 命令创建新的自定义静态路由:

gcloud compute routes create ROUTE_NAME \
    --network=NETWORK \
    --destination-range=DESTINATION_RANGE \
    --priority=PRIORITY \
    NEXT_HOP_SPECIFICATION

替换以下内容:

  • ROUTE_NAME:路由的名称。
  • NETWORK:包含该路由的 VPC 网络的名称
  • DESTINATION_RANGE:应用此路由的目标 IPv4 或 IPv6 地址。支持的最宽泛目标是 0.0.0.0/0 (IPv4) 或 ::/0 (IPv6)。
  • PRIORITY:路由优先级,可以从 0(最高优先级)到 65535(最低优先级)
  • NEXT_HOP_SPECIFICATION:静态路由的下一个跃点。请使用以下参数之一或参数组合:

    • --next-hop-gateway=default-internet-gateway:将数据包发送到互联网以及 Google API 和服务。
    • --next-hop-instance=INSTANCE_NAME--next-hop-instance-zone=ZONE:将数据包发送到现有虚拟机实例的网络接口。请使用名称和可用区指定虚拟机实例。如果路由目标是 IPv6 地址,则虚拟机实例必须是双栈。
    • --next-hop-address=ADDRESS:指定 VPC 网络中现有实例的 IP 地址。对于 IPv6 静态路由(预览版),实例必须是双栈。如需了解有效的下一个跃点 IP 地址的重要限制,请参阅下一个跃点和功能
    • --next-hop-vpn-tunnel=VPN_TUNNEL_NAME--next-hop-vpn-tunnel-region=REGION使用静态路由将数据包发送到现有传统 VPN 隧道。
    • --next-hop-ilb=FORWARDING_RULE--next-hop-ilb-region=REGION:将数据包发送到内部直通式网络负载均衡器。请使用内部转发规则名称(或 IPv4 地址)和区域指定虚拟机实例。

    如需使自定义静态路由仅适用于精选虚拟机(按网络标记),请添加 --tags 标志并指定一个或多个网络标记。如需详细了解网络标记与自定义静态路由如何协同工作,请参阅“路由概览”中的适用路由。您可以将标记与任何自定义静态路由搭配使用。

如需详细了解 gcloud CLI 语法,请参阅 SDK 文档

API

创建一个新的自定义静态路由。

POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/routes
{
  "name": "ROUTE_NAME",
  "network": "NETWORK_NAME",
  "destRange": "DESTINATION_RANGE",
  "priority": PRIORITY,
  "NEXT_HOP_SPECIFICATION"
}

替换以下内容:

  • PROJECT_ID:创建路由的项目的 ID
  • ROUTE_NAME:路由的名称。
  • NETWORK:包含该路由的 VPC 网络的名称。
  • DESTINATION_RANGE:应用此路由的目标 IPv4 或 IPv6 地址范围。支持的最宽泛目标是 0.0.0.0/0 (IPv4) 或 ::/0 (IPv6)。
  • PRIORITY:路由优先级,可以从 0(最高优先级)到 65535(最低优先级)
  • NEXT_HOP_SPECIFICATION:静态路由的下一个跃点。请使用以下参数之一或参数组合:
    • nextHopGateway: https://www.googleapis.com/compute/v1/projects/PROJECT_ID/global/gateways/default-internet-gateway:将数据包发送到互联网以及 Google API 和服务
    • nextHopInstance: https://www.googleapis.com/compute/v1/projects/PROJECT_ID/zones/ZONE/instances/INSTANCE_NAME:将数据包发送到虚拟机实例的网络接口。请使用名称和可用区指定虚拟机实例。如果路由目标是 IPv6 地址,则虚拟机实例必须是双栈。
    • nextHopIp: ADDRESS:指定 VPC 网络中现有实例的 IP 地址。对于 IPv6 静态路由(预览版),实例必须是双栈。如需了解有效的下一个跃点 IP 地址的重要限制,请参阅下一个跃点和功能
    • nextHopVpnTunnel: https://www.googleapis.com/compute/v1/projects/PROJECT_ID/regions/REGION/vpnTunnels/VPN_TUNNEL_NAME使用静态路由将数据包发送到现有传统 VPN 隧道。
    • nextHopIlb: https://www.googleapis.com/compute/v1/projects/PROJECT_ID/regions/REGION/forwardingRules/FORWARDING_RULE:将数据包发送到内部直通式网络负载均衡器。请使用内部转发规则名称(或 IPv4 地址)和区域指定虚拟机实例。

如需使自定义静态路由仅适用于精选虚拟机(按网络标记),请添加 tags 字段并指定一个或多个网络标记。如需详细了解网络标记与自定义静态路由如何协同工作,请参阅“路由概览”中的适用路由。您可以将标记与任何自定义静态路由搭配使用。

如需了解详情,请参阅 routes.insert 方法。

Terraform

您可以使用 Terraform 模块来创建静态路由。

此静态路由会创建一个通向互联网的默认路由。

module "google_compute_route" {
  source       = "terraform-google-modules/network/google//modules/routes"
  version      = "~> 9.0"
  project_id   = var.project_id # Replace this with your project ID in quotes
  network_name = "default"

  routes = [
    {
      name              = "egress-internet"
      description       = "route through IGW to access internet"
      destination_range = "0.0.0.0/0"
      tags              = "egress-inet"
      next_hop_internet = "true"
    }
  ]
}

如需了解如何应用或移除 Terraform 配置,请参阅基本 Terraform 命令

Go

import (
	"context"
	"fmt"
	"io"

	compute "cloud.google.com/go/compute/apiv1"
	computepb "cloud.google.com/go/compute/apiv1/computepb"
	"google.golang.org/protobuf/proto"
)

// createRoute creates a route with given name inside given project.
func createRoute(w io.Writer, projectID, name string) error {
	// projectID := "your_project_id"
	// name := "testname"

	ctx := context.Background()
	client, err := compute.NewRoutesRESTClient(ctx)
	if err != nil {
		return fmt.Errorf("NewRoutesRESTClient: %w", err)
	}
	defer client.Close()

	route := &computepb.Route{
		Name:           proto.String(name),
		Network:        proto.String("global/networks/default"),
		DestRange:      proto.String("0.0.0.0/0"),
		NextHopGateway: proto.String("global/gateways/default-internet-gateway"),
	}

	req := &computepb.InsertRouteRequest{
		Project:       projectID,
		RouteResource: route,
	}
	op, err := client.Insert(ctx, req)

	if err != nil {
		return fmt.Errorf("unable to insert a route: %w", err)
	}

	if err := op.Wait(ctx); err != nil {
		return fmt.Errorf("unable to wait for the operation: %w", err)
	}

	fmt.Fprintf(w, "Route created\n")

	return nil
}

Java


import com.google.cloud.compute.v1.InsertRouteRequest;
import com.google.cloud.compute.v1.Operation;
import com.google.cloud.compute.v1.Route;
import com.google.cloud.compute.v1.RoutesClient;
import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CreateRoute {

  public static void main(String[] args)
          throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // TODO(developer): Replace these variables before running the sample.
    // Project ID or project number of the Cloud project you want to use.
    String projectId = "your-project-id";
    // Route name you want to use.
    String routeName = "your-route-name";
    createRoute(projectId, routeName);
  }

  // Create route for a project.
  public static Operation.Status createRoute(String projectId, String routeName)
          throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests.
    try (RoutesClient routesClient = RoutesClient.create()) {
      String nextHopGateway =
              String.format("projects/%s/global/gateways/default-internet-gateway", projectId);

      Route route = Route.newBuilder()
              .setName(routeName)
              .setDestRange("10.0.0.0/16")
              .setNetwork("global/networks/default")
              .setNextHopGateway(nextHopGateway)
              .build();

      InsertRouteRequest request = InsertRouteRequest.newBuilder()
              .setProject(projectId)
              .setRequestId(UUID.randomUUID().toString())
              .setRouteResource(route)
              .build();

      return routesClient.insertCallable().futureCall(request)
              .get(30, TimeUnit.SECONDS).getStatus();
    }
  }
}

Python

from __future__ import annotations

import sys
from typing import Any

from google.api_core.extended_operation import ExtendedOperation
from google.cloud import compute_v1


def wait_for_extended_operation(
    operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300
) -> Any:
    """
    Waits for the extended (long-running) operation to complete.

    If the operation is successful, it will return its result.
    If the operation ends with an error, an exception will be raised.
    If there were any warnings during the execution of the operation
    they will be printed to sys.stderr.

    Args:
        operation: a long-running operation you want to wait on.
        verbose_name: (optional) a more verbose name of the operation,
            used only during error and warning reporting.
        timeout: how long (in seconds) to wait for operation to finish.
            If None, wait indefinitely.

    Returns:
        Whatever the operation.result() returns.

    Raises:
        This method will raise the exception received from `operation.exception()`
        or RuntimeError if there is no exception set, but there is an `error_code`
        set for the `operation`.

        In case of an operation taking longer than `timeout` seconds to complete,
        a `concurrent.futures.TimeoutError` will be raised.
    """
    result = operation.result(timeout=timeout)

    if operation.error_code:
        print(
            f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}",
            file=sys.stderr,
            flush=True,
        )
        print(f"Operation ID: {operation.name}", file=sys.stderr, flush=True)
        raise operation.exception() or RuntimeError(operation.error_message)

    if operation.warnings:
        print(f"Warnings during {verbose_name}:\n", file=sys.stderr, flush=True)
        for warning in operation.warnings:
            print(f" - {warning.code}: {warning.message}", file=sys.stderr, flush=True)

    return result


def create_route(
    project_id: str,
    network: str,
    route_name: str,
    destination_range: str,
    *,
    next_hop_gateway: str | None = None,
    next_hop_ip: str | None = None,
    next_hop_instance: str | None = None,
    next_hop_vpn_tunnel: str | None = None,
    next_hop_ilb: str | None = None,
) -> compute_v1.Route:
    """
    Create a new route in selected network by providing a destination and next hop name.

    Note: The set of {next_hop_gateway, next_hop_ip, next_hop_instance, next_hop_vpn_tunnel,
        next_hop_ilb} is exclusive, you and only specify one of those parameters.

    Args:
        project_id: project ID or project number of the Cloud project you want to use.
        network: name of the network the route will be created in. Available name formats:
            * https://www.googleapis.com/compute/v1/projects/{project_id}/global/networks/{network}
            * projects/{project_id}/global/networks/{network}
            * global/networks/{network}
        route_name: name of the new route.
        destination_range: range of destination IPs this route should be applied to. E.g. 10.0.0.0/16.
        next_hop_gateway: name of the gateway the traffic should be directed to.
        next_hop_ip: IP address the traffic should be directed to.
        next_hop_instance: name of the instance the traffic should be directed to. Name format:
            "projects/{project}/zones/{zone}/instances/{instance_name}"
        next_hop_vpn_tunnel: name of the VPN tunnel the traffic should be directed to. Name format:
            "projects/{project}/regions/{region}/vpnTunnels/{vpn_tunnel_name}"
        next_hop_ilb: name of a forwarding rule of the Internal Load Balancer the traffic
            should be directed to. Name format:
            "projects/{project}/regions/{region}/forwardingRules/{forwarding_rule_region}"

    Returns:
        A new compute_v1.Route object.
    """
    excl_args = {
        next_hop_instance,
        next_hop_ilb,
        next_hop_vpn_tunnel,
        next_hop_gateway,
        next_hop_ip,
    }
    args_set = sum(1 if arg is not None else 0 for arg in excl_args)

    if args_set != 1:
        raise RuntimeError("You must specify exactly one next_hop_* parameter.")

    route = compute_v1.Route()
    route.name = route_name
    route.network = network
    route.dest_range = destination_range

    if next_hop_gateway:
        route.next_hop_gateway = next_hop_gateway
    elif next_hop_ip:
        route.next_hop_ip = next_hop_ip
    elif next_hop_instance:
        route.next_hop_instance = next_hop_instance
    elif next_hop_vpn_tunnel:
        route.next_hop_vpn_tunnel = next_hop_vpn_tunnel
    elif next_hop_ilb:
        route.next_hop_ilb = next_hop_ilb

    route_client = compute_v1.RoutesClient()
    operation = route_client.insert(project=project_id, route_resource=route)

    wait_for_extended_operation(operation, "route creation")

    return route_client.get(project=project_id, route=route_name)

添加 IPv4 默认路由

系统会自动为每个 VPC 网络配置 IPv4 默认静态路由 (0.0.0.0/0),并将 next-hop-gateway 设置为 default-internet-gateway。如有必要,请按照以下步骤重新创建此路由。

控制台

  1. 在 Google Cloud 控制台中,转到路由页面。

    进入“路由”

  2. 点击路由管理标签页。

  3. 点击创建路由

  4. 指定该路由的名称和说明。

  5. 为路由选择一个现有网络。

  6. 对于目标 IP 地址范围,输入 0.0.0.0/0

  7. 指定该路由的优先级。优先级可以从 0(最高优先级)到 65535(最低优先级)。

  8. 对于下一个跃点,选择默认互联网网关

  9. 点击创建

gcloud

重新创建网络的 IPv4 默认路由。

gcloud compute routes create ROUTE_NAME \
    --destination-range=0.0.0.0/0 \
    --network=NETWORK \
    --next-hop-gateway=default-internet-gateway

替换以下内容:

  • ROUTE_NAME:路由的名称
  • NETWORK:包含该路由的 VPC 网络的名称

API

重新创建网络的 IPv4 默认路由。

POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/routes
{
  "destRange": "0.0.0.0/0",
  "name": "ROUTE_NAME",
  "network": "NETWORK_NAME",
  "nextHopGateway": "projects/PROJECT_ID/global/gateways/default-internet-gateway"
}

替换以下内容:

  • PROJECT_ID:创建路由的项目的 ID
  • ROUTE_NAME:路由的名称
  • NETWORK_NAME:包含该路由的 VPC 网络的名称

添加 IPv6 默认路由

当您创建具有外部 IP 地址访问类型的双栈子网时,系统会自动为 VPC 网络配置 next-hop-gateway 设置为 default-internet-gateway 的 IPv6 默认静态路由 (::/0)。您可以删除路由,以阻止从虚拟机到互联网的所有 IPv6 流量。如果需要,您可以重新创建该路由。

控制台

  1. 在 Google Cloud 控制台中,转到路由页面。

    进入“路由”

  2. 点击路由管理标签页。

  3. 点击创建路由

  4. 指定该路由的名称和说明。

  5. 为路由选择一个现有网络。

  6. 对于目标 IP 地址范围,输入 ::/0

  7. 指定该路由的优先级。优先级可以从 0(最高优先级)到 65535(最低优先级)。

  8. 对于下一个跃点,选择默认互联网网关

  9. 点击创建

gcloud

重新创建网络的 IPv6 默认路由。

gcloud compute routes create ROUTE_NAME \
    --destination-range=::/0 \
    --network=NETWORK \
    --next-hop-gateway=default-internet-gateway

替换以下内容:

  • ROUTE_NAME:路由的名称。
  • NETWORK:包含该路由的 VPC 网络的名称。

API

重新创建网络的 IPv6 默认路由。

POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/routes
{
  "destRange": "::/0",
  "name": "ROUTE_NAME",
  "network": "NETWORK_NAME",
  "nextHopGateway": "projects/PROJECT_ID/global/gateways/default-internet-gateway"
}

替换以下内容:

  • PROJECT_ID:创建路由的项目的 ID
  • ROUTE_NAME:路由的名称
  • NETWORK_NAME:包含该路由的 VPC 网络的名称

修改静态路由

静态路由一经创建便无法修改或更新。如需修改静态路由,必须将其删除并创建替换路由。

删除静态路由

如需删除路由,请执行以下操作。

控制台

  1. 在 Google Cloud 控制台中,转到路由页面。

    进入“路由”

  2. 点击路由管理标签页。

  3. 选择要删除的规则旁边的复选框。

  4. 点击 删除

  5. 再次点击删除进行确认。

gcloud

使用以下 gcloud CLI 命令删除自定义静态路由:

gcloud compute routes delete ROUTE_NAME

ROUTE_NAME 替换为要删除的路由的名称。

API

使用 routes.delete 方法删除自定义静态路由,以将其从您的 VPC 网络中移除:

DELETE https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/routes/ROUTE_NAME

替换以下内容:

  • PROJECT_ID:路由所在项目的 ID。
  • ROUTE_NAME:要删除的路由的名称。

Go

import (
	"context"
	"fmt"
	"io"

	compute "cloud.google.com/go/compute/apiv1"
	computepb "cloud.google.com/go/compute/apiv1/computepb"
)

// deleteRoute deletes a route by name in given project.
func deleteRoute(w io.Writer, projectID, name string) error {
	// projectID := "your_project_id"
	// name := "testname"

	ctx := context.Background()
	client, err := compute.NewRoutesRESTClient(ctx)
	if err != nil {
		return fmt.Errorf("NewRoutesRESTClient: %w", err)
	}
	defer client.Close()

	req := &computepb.DeleteRouteRequest{
		Project: projectID,
		Route:   name,
	}
	op, err := client.Delete(ctx, req)

	if err != nil {
		return fmt.Errorf("unable to delete a route: %w", err)
	}

	if err := op.Wait(ctx); err != nil {
		return fmt.Errorf("unable to wait for the operation: %w", err)
	}

	fmt.Fprintf(w, "Route deleted\n")

	return nil
}

Java


import com.google.cloud.compute.v1.DeleteRouteRequest;
import com.google.cloud.compute.v1.RoutesClient;
import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class DeleteRoute {

  public static void main(String[] args)
          throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // TODO(developer): Replace these variables before running the sample.
    // Project ID or project number of the Cloud project you want to use.
    String projectId = "your-project-id";
    // Route name you want to delete.
    String routeName = "your-route-name";

    deleteRoute(projectId, routeName);
  }

  // Deletes a route from a project.
  public static void deleteRoute(String projectId, String routeName)
          throws IOException, ExecutionException, InterruptedException, TimeoutException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests.
    try (RoutesClient routesClient = RoutesClient.create()) {
      DeleteRouteRequest request = DeleteRouteRequest.newBuilder()
              .setProject(projectId)
              .setRoute(routeName)
              .setRequestId(UUID.randomUUID().toString())
              .build();
      routesClient.deleteCallable().futureCall(request).get(30, TimeUnit.SECONDS);
    }
  }
}

Python

from __future__ import annotations

import sys
from typing import Any

from google.api_core.extended_operation import ExtendedOperation
from google.cloud import compute_v1


def wait_for_extended_operation(
    operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300
) -> Any:
    """
    Waits for the extended (long-running) operation to complete.

    If the operation is successful, it will return its result.
    If the operation ends with an error, an exception will be raised.
    If there were any warnings during the execution of the operation
    they will be printed to sys.stderr.

    Args:
        operation: a long-running operation you want to wait on.
        verbose_name: (optional) a more verbose name of the operation,
            used only during error and warning reporting.
        timeout: how long (in seconds) to wait for operation to finish.
            If None, wait indefinitely.

    Returns:
        Whatever the operation.result() returns.

    Raises:
        This method will raise the exception received from `operation.exception()`
        or RuntimeError if there is no exception set, but there is an `error_code`
        set for the `operation`.

        In case of an operation taking longer than `timeout` seconds to complete,
        a `concurrent.futures.TimeoutError` will be raised.
    """
    result = operation.result(timeout=timeout)

    if operation.error_code:
        print(
            f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}",
            file=sys.stderr,
            flush=True,
        )
        print(f"Operation ID: {operation.name}", file=sys.stderr, flush=True)
        raise operation.exception() or RuntimeError(operation.error_message)

    if operation.warnings:
        print(f"Warnings during {verbose_name}:\n", file=sys.stderr, flush=True)
        for warning in operation.warnings:
            print(f" - {warning.code}: {warning.message}", file=sys.stderr, flush=True)

    return result


def delete_route(project_id: str, route_name: str) -> None:
    """
    Delete a route in project.

    Args:
        project_id: project ID or project number of the Cloud project you want to use.
        route_name: name of the route to delete.
    """

    route_client = compute_v1.RoutesClient()
    operation = route_client.delete(project=project_id, route=route_name)

    wait_for_extended_operation(operation, "route deletion")

路由更改的传播

添加或删除静态路由时,该路由会传播到 VPC 网络中的所有区域和虚拟机实例。如果路由运行状态为 PENDINGRUNNING,则表示路由更改已加入队列。

加入队列后,路由运行状态会变为 DONE。然后,再经过 30 秒,VPC 网络和 VPC 网络对等互连网络中的所有虚拟机实例才会使用新路由或停止使用旧路由。

如果您同时添加或移除多个静态路由,更改可能会按任何顺序应用。路由更改的处理顺序不一定与您提交更改的顺序相同。不同实例可能会在不同时间获知这些更改。

如果您需要进行相互依赖的多项路由更改,则必须依次进行更改:在前一项更改的状态变为 DONE 并且再经过 30 秒后,才能执行后续更改。

为实例启用 IP 转发

默认情况下,IP 转发处于停用状态,Google Cloud 会执行严格的来源地址检查。根据有效的出站防火墙配置,虚拟机可以发出具有以下来源的数据包:

  • 实例的网络接口 (NIC) 的主要内部 IPv4 地址。
  • 实例的 NIC 上任何已配置的别名 IP 地址范围。
  • 如果在子网上配置 IPv6 地址范围并且实例是双栈,则为分配给 NIC 的任何 IPv6 地址。
  • 与用于直通式负载均衡或协议转发的转发规则相关联的内部或外部 IP 地址(如果实例是内部直通式网络负载均衡器、外部直通式网络负载均衡器的后端或由目标实例引用)。

如需将某个虚拟机用作路由的下一个跃点,该虚拟机需要转发来源与上述列表中的 IP 地址或范围不匹配的数据包。如需转发具有任意来源地址的数据包,您必须启用 IP 转发:

  • 创建或更新虚拟机时,请按照本部分中的说明启用 IP 转发。启用 IP 转发适用于虚拟机上的所有 NIC。
  • 除了本部分中的步骤外,您还必须在虚拟机客机操作系统内启用 IP 转发。如需在 Linux 上执行此操作,请将以下一个或两个内核参数的值设置为 1net.ipv4.ip_forward(适用于 IPv4)或 net.ipv6.conf.all.forwarding(适用于 IPv6)。

如需在创建虚拟机时启用 IP 转发,请完成以下步骤。

控制台

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

    转到虚拟机实例

  2. 点击创建实例

  3. 高级选项部分中,展开网络、磁盘、安全、管理、单租户

  4. 展开网络部分。

  5. IP 转发部分中,选中启用复选框。

gcloud

创建实例时,请在命令中添加 --can-ip-forward 标志:

gcloud compute instances create ... --can-ip-forward

API

创建实例时,请使用 canIpForward 字段启用 IP 转发:

POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/zones/ZONE/instances
{
  "canIpForward": true,
  ...other fields
}

替换以下内容:

  • PROJECT_ID:包含实例的项目的 ID。
  • ZONE:包含实例的 Google Cloud 可用区

如需了解详情,请参阅 instances.insert 方法。

Terraform

您可以使用 Terraform 资源创建启用了 IP 转发的虚拟机实例。

在此示例中,Terraform 参数分配了您可以更改的值。

resource "google_compute_instance" "default" {
  project      = var.project_id # Replace this with your project ID in quotes
  zone         = "southamerica-east1-b"
  name         = "instance-next-hop"
  machine_type = "e2-medium"
  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-9"
    }
  }
  network_interface {
    network = "default"
  }
  can_ip_forward = true
}

如需了解如何应用或移除 Terraform 配置,请参阅基本 Terraform 命令

启用 IP 转发后,请继续执行虚拟机创建过程

如需在现有虚拟机上启用 IP 转发,请更新 canIpForward 实例属性

后续步骤