הגדרת כתובות IP חיצוניות סטטיות

אתם יכולים להקצות כתובות IP חיצוניות סטטיות למכונות הווירטואליות ולמכונות Bare Metal. אפשר גם לשנות, להציג ולשחרר כתובות IP סטטיות של המכונות. כדי לשמור כתובת IP חיצונית סטטית, אפשר לעיין במאמר בנושא שמירת כתובת IP חיצונית סטטית.

כתובות IP חיצוניות יכולות להיות סטטיות או זמניות. אם מכונה דורשת כתובת IP חיצונית קבועה שלא משתנה, צריך לבצע את הפעולות הבאות:

  1. מקבלים כתובת IP חיצונית סטטית. אתם יכולים לשמור כתובות IP חיצוניות חדשות או להפוך כתובות IP חיצוניות ארעיות קיימות לכתובות קבועות.
  2. מקצים את כתובת ה-IP השמורה למכונה וירטואלית קיימת, או מקצים אותה כשיוצרים מכונה וירטואלית חדשה.

אם אתם צריכים כתובת IP סטטית ברשת הפנימית של Compute Engine, כדאי לעיין במאמר שמירת כתובת IP פנימית סטטית.

במאמר שמירת כתובת IP חיצונית סטטית מוסבר איך שומרים כתובת IP חיצונית סטטית או יוצרים כתובת IP חיצונית גלובלית.

לפני שמתחילים

התפקידים הנדרשים

כדי לקבל את ההרשאות שדרושות להגדרה ולניהול של כתובות IP סטטיות, בקשו מהאדמין להקצות לכם את התפקידים הבאים ב-IAM בפרויקט:

להסבר על מתן תפקידים, ראו איך מנהלים את הגישה ברמת הפרויקט, התיקייה והארגון.

אלה תפקידים מוגדרים מראש שכוללים את ההרשאות שנדרשות כדי להגדיר ולנהל כתובות IP סטטיות. כדי לראות בדיוק אילו הרשאות נדרשות, אפשר להרחיב את הקטע ההרשאות הנדרשות:

ההרשאות הנדרשות

כדי להגדיר ולנהל כתובות IP סטטיות, נדרשות ההרשאות הבאות:

  • compute.instances.update
  • compute.instances.updateNetworkInterface
  • compute.instances.addAccessConfig
  • compute.instances.deleteAccessConfig
  • compute.networks.list
  • compute.subnetworks.use
  • compute.subnetworks.list
  • כדי ליצור מכונות:
    • ‫compute.instances.create בפרויקט
    • כדי להשתמש באימג' בהתאמה אישית ליצירת המכונה הווירטואלית (VM): compute.images.useReadOnly בקובץ אימג'
    • כדי להשתמש ב-snapshot ליצירת המכונה הווירטואלית: compute.snapshots.useReadOnly בקובץ ה-snapshot
    • כדי להשתמש בתבנית של הגדרות מכונה ליצירת המכונה הווירטואלית: compute.instanceTemplates.useReadOnly בתבנית של הגדרות המכונה
    • כדי להקצות רשת מדור קודם למכונה הווירטואלית: ‫compute.networks.use בפרויקט
    • כדי לציין כתובת IP סטטית למכונה הווירטואלית: compute.addresses.use בפרויקט
    • כדי להקצות כתובת IP חיצונית למכונה הווירטואלית כשמשתמשים ברשת מדור קודם: compute.networks.useExternalIp בפרויקט
    • כדי לציין רשת משנה למכונה הווירטואלית: compute.subnetworks.use בפרויקט או ברשת המשנה שנבחרה
    • כדי להקצות כתובת IP חיצונית למכונה הווירטואלית כשמשתמשים ברשת VPC: compute.subnetworks.useExternalIp בפרויקט או ברשת המשנה שנבחרה
    • כדי להגדיר מטא-נתונים של המכונה הווירטואלית: compute.instances.setMetadata בפרויקט
    • כדי להגדיר תגים למכונה הווירטואלית: compute.instances.setTags במכונה הווירטואלית
    • כדי להגדיר תוויות למכונה הווירטואלית: compute.instances.setLabels במכונה הווירטואלית
    • כדי להגדיר חשבון שירות לשימוש של המכונה הווירטואלית: compute.instances.setServiceAccount במכונה הווירטואלית
    • כדי ליצור דיסק חדש למכונה הווירטואלית: compute.disks.create בפרויקט
    • כדי לצרף דיסק קיים במצב קריאה-בלבד או במצב קריאה וכתיבה: compute.disks.use בדיסק
    • כדי לצרף דיסק קיים במצב קריאה-בלבד: compute.disks.useReadOnly בדיסק
  • כדי לערוך את מדיניות הארגון:
    • orgpolicy.policy.get
    • orgpolicy.policies.create
    • orgpolicy.policies.delete
    • orgpolicy.policies.update

יכול להיות שתקבלו את ההרשאות האלה באמצעות תפקידים בהתאמה אישית או תפקידים מוגדרים מראש אחרים.

מגבלות

  • רק משאב אחד בכל פעם יכול להשתמש בכתובת IP חיצונית סטטית.

  • לכל מכונת חישוב יכולים להיות כמה ממשקי רשת, ולכל ממשק יכולות להיות כתובות ה-IP הבאות שמוקצות בהתאם לסוג המערך:

    • ממשקי IPv4 בלבד:
      • כתובת IPv4 פנימית (חובה)
      • כתובת IPv4 חיצונית (אופציונלי)
    • ממשקי Dual-stack‏ (IPv4 ו-IPv6):
      • כתובת IPv4 פנימית (חובה)
      • כתובת IPv4 חיצונית (אופציונלי)
      • טווח כתובות IPv6 של /96, פנימי או חיצוני, אבל לא שניהם (חובה)
    • ממשקים מסוג IPv6 בלבד:
      • טווח כתובות IPv6 מסוג /96, פנימי או חיצוני, אבל לא שניהם (חובה)
  • אי אפשר לבטל את ההקצאה או לשנות את כתובת ה-IPv6 החיצונית של מכונת Compute עם ממשק רשת מסוג IPv6 בלבד. עם זאת, אתם יכולים לשדרג כתובת IP חיצונית זמנית של משאב לכתובת IP חיצונית סטטית, כדי שהכתובת תישאר שמורה גם אחרי שהמשאב יימחק.

  • אי אפשר לשנות את השם של כתובת IP סטטית.

הערה: ממשקי רשת יכולים לקבל תנועה מ כללי העברה מרובים, שעשויים לשרת כתובות IP חיצוניות אחרות. כל מספר של כתובות IP חיצוניות יכול להפנות לממשק רשת באמצעות כללי ההעברה האלה, אבל לכל ממשק רשת אפשר להקצות רק כתובת IPv4 חיצונית אחת וטווח כתובות /96 IPv6 חיצוניות אחד.

מידע נוסף על איזון עומסים וכללי העברה זמין במאמרי העזרה בנושא איזון עומסים.

הצגת כתובות IP חיצוניות סטטיות זמינות

כדי להציג רשימה של כתובות IP חיצוניות סטטיות ששמרתם לפרויקט, בצעו את השלבים הבאים.

המסוף

  1. נכנסים לדף IP addresses במסוף Google Cloud .

    מעבר אל כתובות IP

  2. לוחצים על External IP addresses (כתובות IP חיצוניות).

gcloud

משתמשים בפקודה gcloud compute addresses list:

  • כדי לראות את כל כתובות ה-IP, משתמשים בפקודה הבאה:

    gcloud compute addresses list
  • כדי להציג את כל כתובות ה-IP הגלובליות, משתמשים בפקודה הבאה:

    gcloud compute addresses list --global
  • כדי להציג את כל כתובות ה-IP האזוריות באזור מסוים, משתמשים בפקודה הבאה:

    gcloud compute addresses list \
        --regions=REGION
    

    מחליפים את REGION באזור שרוצים להציג את הכתובות שלו. אפשר לציין רשימה של שמות אזורים שמופרדים בפסיקים כדי להציג את הכתובות של כמה אזורים:

    gcloud compute addresses list \
        --regions=REGION1,REGION2,..REGION_n_
    

API

  • כדי להציג רשימה של כתובות IPv4 או IPv6 אזוריות, קוראים לשיטה addresses.list:

    GET https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/regions/REGION/addresses
    

    מחליפים את מה שכתוב בשדות הבאים:

    • ‫PROJECT_ID: מזהה הפרויקט של הבקשה הזו
    • ‫REGION: שם האזור של הבקשה הזו
  • כדי לראות את כל הכתובות בכל האזורים, קוראים לשיטה addresses.aggregatedList:

    GET https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/aggregated/addresses
    
  • כדי להציג רשימה של כתובות IPv4 או IPv6 גלובליות, קוראים לשיטה globalAddresses.list:

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

    מחליפים את מה שכתוב בשדות הבאים:

    ‫PROJECT_ID: מזהה הפרויקט של הבקשה הזו

המשך

import (
	"context"
	"fmt"
	"io"

	compute "cloud.google.com/go/compute/apiv1"
	"google.golang.org/api/iterator"

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

// listRegionalExternal retrieves list external IP addresses in Google Cloud Platform region.
func listRegionalExternal(w io.Writer, projectID, region string) ([]*computepb.Address, error) {
	// projectID := "your_project_id"
	// region := "europe-west3"

	ctx := context.Background()
	// Create the service client.
	addressesClient, err := compute.NewAddressesRESTClient(ctx)
	if err != nil {
		return nil, err
	}
	defer addressesClient.Close()

	// Build the request.
	req := &computepb.ListAddressesRequest{
		Project: projectID,
		Region:  region,
	}

	// List the addresses.
	it := addressesClient.List(ctx, req)

	// Iterate over the results.
	var addresses []*computepb.Address
	for {
		address, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return nil, err
		}
		addresses = append(addresses, address)
	}

	// Print the addresses.
	fmt.Fprint(w, "Fetched addresses: \n")
	for _, address := range addresses {
		fmt.Fprintf(w, "%s\n", *address.Name)
	}

	return addresses, nil
}

// listGlobalExternal retrieves list external global IP addresses in Google Cloud Platform.
func listGlobalExternal(w io.Writer, projectID string) ([]*computepb.Address, error) {
	// projectID := "your_project_id"

	ctx := context.Background()
	// Create the service client.
	addressesClient, err := compute.NewGlobalAddressesRESTClient(ctx)
	if err != nil {
		return nil, err
	}
	defer addressesClient.Close()

	// Build the request.
	req := &computepb.ListGlobalAddressesRequest{
		Project: projectID,
	}

	// List the addresses.
	it := addressesClient.List(ctx, req)

	// Iterate over the results.
	var addresses []*computepb.Address
	for {
		address, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return nil, err
		}
		addresses = append(addresses, address)
	}

	// Print the addresses.
	fmt.Fprint(w, "Fetched addresses: \n")
	for _, address := range addresses {
		fmt.Fprintf(w, "%s\n", *address.Name)
	}

	return addresses, nil
}

Java


import com.google.cloud.compute.v1.Address;
import com.google.cloud.compute.v1.AddressesClient;
import com.google.cloud.compute.v1.GlobalAddressesClient;
import com.google.cloud.compute.v1.ListAddressesRequest;
import com.google.cloud.compute.v1.ListGlobalAddressesRequest;
import com.google.common.collect.Lists;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;

public class ListStaticExternalIp {

  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 Google Cloud project you want to use.
    String projectId = "your-project-id";
    // Region where the VM and IP is located.
    String region = "your-region-id";

    listStaticExternalIp(projectId, region);
  }

  // Lists all static external IP addresses, either regional or global.
  public static List<Address> listStaticExternalIp(String projectId, String region)
          throws IOException {
    // Use regional client if a region is specified
    if (region != null) {
      // 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 (AddressesClient client = AddressesClient.create()) {
        ListAddressesRequest request = ListAddressesRequest.newBuilder()
                .setProject(projectId)
                .setRegion(region)
                .build();

        return Lists.newArrayList(client.list(request).iterateAll());
      }
    } else {
      // 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 (GlobalAddressesClient client = GlobalAddressesClient.create()) {
        ListGlobalAddressesRequest request = ListGlobalAddressesRequest.newBuilder()
                .setProject(projectId)
                .build();

        return Lists.newArrayList(client.list(request).iterateAll());
      }
    }
  }
}

Python

from typing import List, Optional

from google.cloud.compute_v1.services.addresses.client import AddressesClient
from google.cloud.compute_v1.services.global_addresses import GlobalAddressesClient
from google.cloud.compute_v1.types import Address


def list_static_ip_addresses(
    project_id: str, region: Optional[str] = None
) -> List[Address]:
    """
    Lists all static external IP addresses, either regional or global.

    Args:
    project_id (str): project ID.
    region (Optional[str]): The region of the IP addresses if regional. None if global.

    Returns:
    List[Address]: A list of Address objects containing details about the requested IPs.
    """
    if region:
        # Use regional client if a region is specified
        client = AddressesClient()
        addresses_iterator = client.list(project=project_id, region=region)
    else:
        # Use global client if no region is specified
        client = GlobalAddressesClient()
        addresses_iterator = client.list(project=project_id)

    return list(addresses_iterator)  # Convert the iterator to a list to return

הגדרת כתובות IP חיצוניות סטטיות

בקטעים הבאים מוסבר איך להגדיר כתובות IP חיצוניות סטטיות למופעים.

יצירת מכונה שמשתמשת בכתובת IP חיצונית סטטית

אחרי ששומרים כתובת IP חיצונית סטטית, אפשר להקצות אותה למכונה.

המסוף

  1. נכנסים לדף Create an instance במסוף Google Cloud .

    כניסה לדף Create an instance

  2. כדי להקצות כתובת IP חיצונית סטטית למופע, מבצעים את הפעולות הבאות:

    1. בתפריט הניווט, לוחצים על Networking (רשת).

    2. בקטע Network interfaces (ממשקי רשת), מציינים את ממשקי הרשת שרוצים להגדיר למופע באמצעות האפשרויות הבאות:

      • כדי להוסיף ממשק רשת, לוחצים על הוספת ממשק רשת. אחר כך, בוחרים רשת מהרשימה רשת.

      • כדי למחוק ממשק רשת, לוחצים על מחיקה.

    3. בוחרים באחת מהאפשרויות הבאות:

      • כדי להקצות כתובת IPv4 חיצונית סטטית, מבצעים את הפעולות הבאות:

        1. מרחיבים את ממשק הרשת.
        2. בוחרים את כתובת ה-IP מהרשימה External IPv4 address.
      • כדי להקצות כתובת IPv6 חיצונית סטטית, מבצעים את הפעולות הבאות:

        1. מרחיבים את ממשק הרשת שמכיל תת-רשת עם טווח כתובות IPv6 חיצוניות.
        2. בוחרים את רשת המשנה מהרשימה Subnetwork.
        3. בקטע IP stack type, בוחרים באפשרות IPv4 and IPv6 (dual-stack) או באפשרות IPv6 (single-stack).
        4. בוחרים את כתובת ה-IPv6 החיצונית ששמרתם מהרשימה External IPv6 address. אפשר גם לבחור באפשרות שמירת כתובת IPv6 חיצונית סטטית ולשמור כתובת IPv6 חיצונית סטטית חדשה.
        5. בקטע Network Service Tier, לוחצים על Premium.
    4. כדי לסיים את השינוי של ממשק הרשת, לוחצים על Done.

  3. ממשיכים בתהליך יצירת המופע.

gcloud

אתם יכולים ליצור מכונה ולהקצות לה כתובת IP חיצונית סטטית אזורית שכבר שמרתם.

  • כדי להקצות כתובת IPv4 חיצונית סטטית, מבצעים את הפעולות הבאות:

    gcloud compute instances create INSTANCE_NAME \
        --zone=ZONE \
        --address=IPV4_ADDRESS
    
  • כדי להקצות כתובת IPv6 חיצונית סטטית, מבצעים את הפעולות הבאות:

    gcloud compute instances create INSTANCE_NAME \
        --zone=ZONE \
        --subnet=SUBNET \
        --stack-type=STACK_TYPE \
        --external-ipv6-address=IPV6_ADDRESS \
        --external-ipv6-prefix-length=96 \
        --ipv6-network-tier=PREMIUM
    

    מחליפים את מה שכתוב בשדות הבאים:

    • ‫INSTANCE_NAME: השם של מכונת Compute.
    • ‫ZONE: האזור שבו יוצרים את המכונה
    • ‫IPV4_ADDRESS: כתובת ה-IPv4 להקצאה למכונה. משתמשים בכתובת ה-IP החיצונית הסטטית השמורה, ולא בשם הכתובת.
    • ‫SUBNET: רשת משנה שמכילה כתובות IPv6 חיצוניות
    • ‫STACK_TYPE: סוג המחסנית של המכונה, IPV4_IPV6 (מחסנית כפולה) או IPV6_ONLY
    • ‫IPV6_ADDRESS: כתובת ה-IPv6 להקצאה למכונה. משתמשים בכתובת ה-IP החיצונית הסטטית השמורה, ולא בשם הכתובת.

Terraform

אתם יכולים להשתמש במשאב google_compute_instance כדי להקצות כתובת IP חיצונית.

resource "google_compute_instance" "default" {
  name         = "dns-proxy-nfs"
  machine_type = "n1-standard-1"
  zone         = "us-central1-a"

  boot_disk {
    initialize_params {
      image = "ubuntu-1404-trusty-v20160627"
    }
  }

  network_interface {
    network = "default"
    access_config {
      nat_ip = google_compute_address.default.address
    }
  }
}

כדי ללמוד איך להחיל הגדרות ב-Terraform או להסיר אותן, ראו פקודות בסיסיות ב-Terraform.

REST

  • כדי להקצות כתובת IPv4 חיצונית סטטית למכונה חדשה, מבצעים את הפעולות הבאות:

    בבקשה ליצירת מכונה חדשה, צריך לציין במפורש את המאפיין networkInterfaces[].accessConfigs[].natIP ואת כתובת ה-IPv4 החיצונית שרוצים להשתמש בה, לדוגמה:

    {
      "name": "INSTANCE_NAME",
      "machineType": "zones/ZONE/machineTypes/MACHINE_TYPE",
      "networkInterfaces": [{
          "accessConfigs": [{
            "type": "ONE_TO_ONE_NAT",
            "name": "External NAT",
            "natIP": "IPV4_ADDRESS"
          }],
          "network": "global/networks/default"
      }],
      "disks": [{
          "autoDelete": "true",
            "boot": "true",
            "type": "PERSISTENT",
            "initializeParams": {
                "sourceImage": "SOURCE_IMAGE"
             }
      }]
    }
    

    מחליפים את מה שכתוב בשדות הבאים:

    • ‫INSTANCE_NAME: השם של המכונה הווירטואלית
    • ‫ZONE: האזור שבו רוצים ליצור את המכונה
    • ‫MACHINE_TYPE: אופציונלי: כתובת URL מלאה או חלקית של משאב מסוג מכונה לשימוש כשיוצרים את המכונה, בפורמט: zones/ZONE/machineTypes/MACHINE_TYPE
    • ‫IPV4_ADDRESS: כתובת ה-IPv4 להקצאה למכונה. צריך להשתמש בכתובת ה-IP החיצונית הסטטית השמורה, ולא בשם הכתובת.
    • ‫SOURCE_IMAGE: גרסה ספציפית של תמונה ציבורית, כמו projects/debian-cloud/global/images/debian-10-buster-v20200309 או משפחה של תמונות, כמו projects/debian-cloud/global/images/family/debian-10
  • כדי להקצות כתובת IPv6 חיצונית סטטית למכונה חדשה, מבצעים את הפעולות הבאות:

    בבקשה ליצירת מכונה חדשה, מציינים במפורש את המאפיין networkInterfaces[].ipv6AccessConfigs[].externalIpv6 ואת כתובת ה-IPv6 החיצונית שבה רוצים להשתמש. לדוגמה:

    {
      "name": "INSTANCE_NAME",
      "machineType": "zones/ZONE/machineTypes/MACHINE_TYPE",
      "networkInterfaces": [{
              "ipv6AccessConfigs": [{
             "externalIpv6": "IPV6_ADDRESS",
             "externalIpv6PrefixLength": 96,
             "name": "external-ipv6-access-config",
             "networkTier": "PREMIUM",
             "type": "DIRECT_IPV6"
              }],
          "stackType": "STACK_TYPE",
          "subnetwork":"SUBNETWORK"
      }],
      "disks": [{
          "autoDelete": "true",
          "boot": "true",
          "mode": "READ_WRITE",
          "type": "PERSISTENT",
          "initializeParams": {
              "sourceImage": "SOURCE_IMAGE"
          },
      }],
    }
    

    מחליפים את מה שכתוב בשדות הבאים:

    • ‫INSTANCE_NAME: השם של המכונה הווירטואלית
    • ‫ZONE: האזור שבו רוצים ליצור את המכונה
    • ‫MACHINE_TYPE: אופציונלי: כתובת URL מלאה או חלקית של משאב מסוג מכונה לשימוש כשיוצרים את המכונה, בפורמט: zones/ZONE/machineTypes/MACHINE_TYPE
    • ‫IPV6_ADDRESS: כתובת ה-IPv6 להקצאה למכונה. משתמשים בכתובת ה-IP החיצונית הסטטית השמורה, ולא בשם הכתובת.
    • ‫STACK_TYPE: סוג המחסנית של המכונה, IPV4_IPV6 (שני פרוטוקולים) או IPV6_ONLY
    • ‫SUBNET: רשת משנה שמכילה כתובות IPv6 חיצוניות
    • ‫SOURCE_IMAGE: גרסה ספציפית של תמונה ציבורית, כמו "projects/debian-cloud/global/images/debian-10-buster-v20200309" או משפחה של תמונות, כמו "projects/debian-cloud/global/images/family/debian-10"

המשך


// assignStaticExternalToNewVM creates a new VM instance and assigns a static external IP address to it.
// NOTE: ip address is expected to exist and be located in the same region as new VM
func assignStaticExternalToNewVM(w io.Writer, projectID, zone, instanceName, ipAddress string) error {
	// projectID := "your_project_id"
	// zone := "europe-central2-b"
	// instanceName := "your_instance_name"
	// ipAddress := 301.222.11.123

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

	imagesClient, err := compute.NewImagesRESTClient(ctx)
	if err != nil {
		return fmt.Errorf("NewImagesRESTClient: %w", err)
	}
	defer imagesClient.Close()

	// List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details.
	newestDebianReq := &computepb.GetFromFamilyImageRequest{
		Project: "debian-cloud",
		Family:  "debian-12",
	}
	newestDebian, err := imagesClient.GetFromFamily(ctx, newestDebianReq)
	if err != nil {
		return fmt.Errorf("unable to get image from family: %w", err)
	}

	req := &computepb.InsertInstanceRequest{
		Project: projectID,
		Zone:    zone,
		InstanceResource: &computepb.Instance{
			Name: proto.String(instanceName),
			Disks: []*computepb.AttachedDisk{
				{
					InitializeParams: &computepb.AttachedDiskInitializeParams{
						DiskSizeGb:  proto.Int64(10),
						SourceImage: newestDebian.SelfLink,
						DiskType:    proto.String(fmt.Sprintf("zones/%s/diskTypes/pd-standard", zone)),
					},
					AutoDelete: proto.Bool(true),
					Boot:       proto.Bool(true),
					Type:       proto.String(computepb.AttachedDisk_PERSISTENT.String()),
				},
			},
			MachineType: proto.String(fmt.Sprintf("zones/%s/machineTypes/n1-standard-1", zone)),
			NetworkInterfaces: []*computepb.NetworkInterface{
				{
					AccessConfigs: []*computepb.AccessConfig{
						{
							Type:        proto.String(computepb.AccessConfig_ONE_TO_ONE_NAT.String()),
							Name:        proto.String("External NAT"),
							NetworkTier: proto.String(computepb.AccessConfig_PREMIUM.String()),
							NatIP:       proto.String(ipAddress),
						},
					},
				},
			},
		},
	}

	op, err := instancesClient.Insert(ctx, req)
	if err != nil {
		return fmt.Errorf("unable to create instance: %w", err)
	}

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

	fmt.Fprintf(w, "Static address %s assigned to new VM", ipAddress)

	return nil
}

Java


import com.google.cloud.compute.v1.AccessConfig;
import com.google.cloud.compute.v1.AccessConfig.Type;
import com.google.cloud.compute.v1.Address.NetworkTier;
import com.google.cloud.compute.v1.AttachedDisk;
import com.google.cloud.compute.v1.AttachedDiskInitializeParams;
import com.google.cloud.compute.v1.GetInstanceRequest;
import com.google.cloud.compute.v1.ImagesClient;
import com.google.cloud.compute.v1.InsertInstanceRequest;
import com.google.cloud.compute.v1.Instance;
import com.google.cloud.compute.v1.InstancesClient;
import com.google.cloud.compute.v1.NetworkInterface;
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 AssignStaticExternalNewVmAddress {

  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 Google Cloud project you want to use.
    String projectId = "your-project-id";
    // Instance ID of the Google Cloud project you want to use.
    String instanceId = "your-instance-id";
    // Name of the zone to create the instance in. For example: "us-west3-b"
    String zone = "your-zone-id";
    // machine type of the VM being created. This value uses the
    // following format: "zones/{zone}/machineTypes/{type_name}".
    // For example: "zones/europe-west3-c/machineTypes/f1-micro"
    String machineType = String.format("zones/%s/machineTypes/{your-machineType-id}", zone);
    // boolean flag indicating if the instance should have an external IPv4 address assigned.
    boolean externalAccess = true;
    // external IPv4 address to be assigned to this instance. If you specify
    // an external IP address, it must live in the same region as the zone of the instance.
    // This setting requires `external_access` to be set to True to work.
    String externalIpv4 = "your-externalIpv4-id";

    assignStaticExternalNewVmAddress(projectId, instanceId, zone,
            externalAccess, machineType, externalIpv4);
  }

  // Create a new VM instance with assigned static external IP address.
  public static Instance assignStaticExternalNewVmAddress(String projectId, String instanceName,
                                                          String zone, boolean externalAccess,
                                                          String machineType, String externalIpv4)
          throws IOException, ExecutionException, InterruptedException, TimeoutException {
    String sourceImage;
    // 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 (ImagesClient imagesClient = ImagesClient.create()) {
      sourceImage = imagesClient.getFromFamily("debian-cloud", "debian-13").getSelfLink();
    }
    AttachedDisk attachedDisk = buildAttachedDisk(sourceImage, zone);

    return createInstance(projectId, instanceName, zone,
            attachedDisk, machineType, externalAccess, externalIpv4);
  }

  private static AttachedDisk buildAttachedDisk(String sourceImage, String zone) {
    AttachedDiskInitializeParams initializeParams = AttachedDiskInitializeParams.newBuilder()
            .setSourceImage(sourceImage)
            .setDiskSizeGb(10)
            .setDiskType(String.format("zones/%s/diskTypes/pd-standard", zone))
            .build();

    return AttachedDisk.newBuilder()
            .setInitializeParams(initializeParams)
            // Remember to set auto_delete to True if you want the disk to be deleted
            // when you delete your VM instance.
            .setAutoDelete(true)
            .setBoot(true)
            .build();
  }

  // Send an instance creation request to the Compute Engine API and wait for it to complete.
  private static Instance createInstance(String projectId, String instanceName,
                                         String zone, AttachedDisk disks,
                                         String machineType, boolean externalAccess,
                                         String externalIpv4)
          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 (InstancesClient client = InstancesClient.create()) {
      Instance instanceResource =
              buildInstanceResource(instanceName, disks, machineType, externalAccess, externalIpv4);

      InsertInstanceRequest build = InsertInstanceRequest.newBuilder()
              .setProject(projectId)
              .setRequestId(UUID.randomUUID().toString())
              .setZone(zone)
              .setInstanceResource(instanceResource)
              .build();
      client.insertCallable().futureCall(build).get(60, TimeUnit.SECONDS);

      GetInstanceRequest getInstanceRequest = GetInstanceRequest.newBuilder()
              .setInstance(instanceName)
              .setProject(projectId)
              .setZone(zone)
              .build();

      return client.get(getInstanceRequest);
    }
  }

  private static Instance buildInstanceResource(String instanceName, AttachedDisk disk,
                                                String machineType, boolean externalAccess,
                                                String externalIpv4) {
    NetworkInterface networkInterface =
            networkInterface(externalAccess, externalIpv4);

    return Instance.newBuilder()
            .setName(instanceName)
            .addDisks(disk)
            .setMachineType(machineType)
            .addNetworkInterfaces(networkInterface)
            .build();
  }

  private static NetworkInterface networkInterface(boolean externalAccess, String externalIpv4) {
    NetworkInterface.Builder build = NetworkInterface.newBuilder()
            .setNetwork("global/networks/default");
    if (externalAccess) {
      AccessConfig.Builder accessConfig = AccessConfig.newBuilder()
              .setType(Type.ONE_TO_ONE_NAT.name())
              .setName("External NAT")
              .setNetworkTier(NetworkTier.PREMIUM.name());
      if (externalIpv4 != null) {
        accessConfig.setNatIP(externalIpv4);
      }
      build.addAccessConfigs(accessConfig.build());
    }

    return build.build();
  }
}

Python

from __future__ import annotations

import re
import sys
from typing import Any
import warnings

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


def get_image_from_family(project: str, family: str) -> compute_v1.Image:
    """
    Retrieve the newest image that is part of a given family in a project.

    Args:
        project: project ID or project number of the Cloud project you want to get image from.
        family: name of the image family you want to get image from.

    Returns:
        An Image object.
    """
    image_client = compute_v1.ImagesClient()
    # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details
    newest_image = image_client.get_from_family(project=project, family=family)
    return newest_image


def disk_from_image(
    disk_type: str,
    disk_size_gb: int,
    boot: bool,
    source_image: str,
    auto_delete: bool = True,
) -> compute_v1.AttachedDisk:
    """
    Create an AttachedDisk object to be used in VM instance creation. Uses an image as the
    source for the new disk.

    Args:
         disk_type: the type of disk you want to create. This value uses the following format:
            "zones/{zone}/diskTypes/(pd-standard|pd-ssd|pd-balanced|pd-extreme)".
            For example: "zones/us-west3-b/diskTypes/pd-ssd"
        disk_size_gb: size of the new disk in gigabytes
        boot: boolean flag indicating whether this disk should be used as a boot disk of an instance
        source_image: source image to use when creating this disk. You must have read access to this disk. This can be one
            of the publicly available images or an image from one of your projects.
            This value uses the following format: "projects/{project_name}/global/images/{image_name}"
        auto_delete: boolean flag indicating whether this disk should be deleted with the VM that uses it

    Returns:
        AttachedDisk object configured to be created using the specified image.
    """
    boot_disk = compute_v1.AttachedDisk()
    initialize_params = compute_v1.AttachedDiskInitializeParams()
    initialize_params.source_image = source_image
    initialize_params.disk_size_gb = disk_size_gb
    initialize_params.disk_type = disk_type
    boot_disk.initialize_params = initialize_params
    # Remember to set auto_delete to True if you want the disk to be deleted when you delete
    # your VM instance.
    boot_disk.auto_delete = auto_delete
    boot_disk.boot = boot
    return boot_disk


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_instance(
    project_id: str,
    zone: str,
    instance_name: str,
    disks: list[compute_v1.AttachedDisk],
    machine_type: str = "n1-standard-1",
    network_link: str = "global/networks/default",
    subnetwork_link: str = None,
    internal_ip: str = None,
    external_access: bool = False,
    external_ipv4: str = None,
    accelerators: list[compute_v1.AcceleratorConfig] = None,
    preemptible: bool = False,
    spot: bool = False,
    instance_termination_action: str = "STOP",
    custom_hostname: str = None,
    delete_protection: bool = False,
) -> compute_v1.Instance:
    """
    Send an instance creation request to the Compute Engine API and wait for it to complete.

    Args:
        project_id: project ID or project number of the Cloud project you want to use.
        zone: name of the zone to create the instance in. For example: "us-west3-b"
        instance_name: name of the new virtual machine (VM) instance.
        disks: a list of compute_v1.AttachedDisk objects describing the disks
            you want to attach to your new instance.
        machine_type: machine type of the VM being created. This value uses the
            following format: "zones/{zone}/machineTypes/{type_name}".
            For example: "zones/europe-west3-c/machineTypes/f1-micro"
        network_link: name of the network you want the new instance to use.
            For example: "global/networks/default" represents the network
            named "default", which is created automatically for each project.
        subnetwork_link: name of the subnetwork you want the new instance to use.
            This value uses the following format:
            "regions/{region}/subnetworks/{subnetwork_name}"
        internal_ip: internal IP address you want to assign to the new instance.
            By default, a free address from the pool of available internal IP addresses of
            used subnet will be used.
        external_access: boolean flag indicating if the instance should have an external IPv4
            address assigned.
        external_ipv4: external IPv4 address to be assigned to this instance. If you specify
            an external IP address, it must live in the same region as the zone of the instance.
            This setting requires `external_access` to be set to True to work.
        accelerators: a list of AcceleratorConfig objects describing the accelerators that will
            be attached to the new instance.
        preemptible: boolean value indicating if the new instance should be preemptible
            or not. Preemptible VMs have been deprecated and you should now use Spot VMs.
        spot: boolean value indicating if the new instance should be a Spot VM or not.
        instance_termination_action: What action should be taken once a Spot VM is terminated.
            Possible values: "STOP", "DELETE"
        custom_hostname: Custom hostname of the new VM instance.
            Custom hostnames must conform to RFC 1035 requirements for valid hostnames.
        delete_protection: boolean value indicating if the new virtual machine should be
            protected against deletion or not.
    Returns:
        Instance object.
    """
    instance_client = compute_v1.InstancesClient()

    # Use the network interface provided in the network_link argument.
    network_interface = compute_v1.NetworkInterface()
    network_interface.network = network_link
    if subnetwork_link:
        network_interface.subnetwork = subnetwork_link

    if internal_ip:
        network_interface.network_i_p = internal_ip

    if external_access:
        access = compute_v1.AccessConfig()
        access.type_ = compute_v1.AccessConfig.Type.ONE_TO_ONE_NAT.name
        access.name = "External NAT"
        access.network_tier = access.NetworkTier.PREMIUM.name
        if external_ipv4:
            access.nat_i_p = external_ipv4
        network_interface.access_configs = [access]

    # Collect information into the Instance object.
    instance = compute_v1.Instance()
    instance.network_interfaces = [network_interface]
    instance.name = instance_name
    instance.disks = disks
    if re.match(r"^zones/[a-z\d\-]+/machineTypes/[a-z\d\-]+$", machine_type):
        instance.machine_type = machine_type
    else:
        instance.machine_type = f"zones/{zone}/machineTypes/{machine_type}"

    instance.scheduling = compute_v1.Scheduling()
    if accelerators:
        instance.guest_accelerators = accelerators
        instance.scheduling.on_host_maintenance = (
            compute_v1.Scheduling.OnHostMaintenance.TERMINATE.name
        )

    if preemptible:
        # Set the preemptible setting
        warnings.warn(
            "Preemptible VMs are being replaced by Spot VMs.", DeprecationWarning
        )
        instance.scheduling = compute_v1.Scheduling()
        instance.scheduling.preemptible = True

    if spot:
        # Set the Spot VM setting
        instance.scheduling.provisioning_model = (
            compute_v1.Scheduling.ProvisioningModel.SPOT.name
        )
        instance.scheduling.instance_termination_action = instance_termination_action

    if custom_hostname is not None:
        # Set the custom hostname for the instance
        instance.hostname = custom_hostname

    if delete_protection:
        # Set the delete protection bit
        instance.deletion_protection = True

    # Prepare the request to insert an instance.
    request = compute_v1.InsertInstanceRequest()
    request.zone = zone
    request.project = project_id
    request.instance_resource = instance

    # Wait for the create operation to complete.
    print(f"Creating the {instance_name} instance in {zone}...")

    operation = instance_client.insert(request=request)

    wait_for_extended_operation(operation, "instance creation")

    print(f"Instance {instance_name} created.")
    return instance_client.get(project=project_id, zone=zone, instance=instance_name)


def assign_static_external_ip_to_new_vm(
    project_id: str, zone: str, instance_name: str, ip_address: str
) -> compute_v1.Instance:
    """
    Create a new VM instance with assigned static external IP address.

    Args:
        project_id (str): project ID or project number of the Cloud project you want to use.
        zone (str): name of the zone to create the instance in. For example: "us-west3-b"
        instance_name (str): name of the new virtual machine (VM) instance.
        ip_address(str): external address to be assigned to this instance. It must live in the same
        region as the zone of the instance and be precreated before function called.

    Returns:
        Instance object.
    """
    newest_debian = get_image_from_family(project="debian-cloud", family="debian-12")
    disk_type = f"zones/{zone}/diskTypes/pd-standard"
    disks = [disk_from_image(disk_type, 10, True, newest_debian.self_link, True)]
    instance = create_instance(
        project_id,
        zone,
        instance_name,
        disks,
        external_ipv4=ip_address,
        external_access=True,
    )
    return instance

שינוי או הקצאה של כתובת IP חיצונית למכונה קיימת

אתם יכולים לשנות או להקצות כתובת IP חיצונית, ארעית או סטטית, למכונה קיימת עם IPv4 בלבד או עם מחסנית כפולה. התהליך הזה לא נתמך במכונות עם IPv6 בלבד.

למופע של מחשוב יכולים להיות כמה ממשקים. לממשק עם מחסנית יחידה יכולה להיות כתובת IP חיצונית אחת. לממשק עם שני סוגי כתובות IP יכולה להיות כתובת IPv4 חיצונית אחת וכתובת IPv6 חיצונית אחת. אם למכונה כבר יש כתובת IP חיצונית, צריך קודם להסיר את הכתובת הזו. אחר כך תוכלו להקצות כתובת IP חיצונית חדשה למופע הקיים.

המסוף

  1. נכנסים לדף VM instances במסוף Google Cloud .

    כניסה לדף VM instances

  2. לוחצים על השם של המכונה שרוצים להקצות לה כתובת IP חיצונית. הדף Instance details מוצג.

  3. בדף Instance details (פרטי המופע), מבצעים את הפעולות הבאות:

    1. לוחצים על Edit.
    2. מרחיבים את Network interfaces (ממשקי רשת).
    3. בוחרים את כתובת ה-IP החיצונית שרוצים להקצות למופע. אם המכונה היא IPv4 בלבד ואתם רוצים להקצות לה כתובת IPv6, אתם צריכים קודם לשנות את סוג הערימה ל-dual-stack.
      1. בשביל External IPv4 address, בוחרים באפשרות Ephemeral או בכתובת IPv4 חיצונית סטטית.
      2. בשביל External IPv6 address, בוחרים באחת מהאפשרויות הבאות: Ephemeral (Automatic),‏ Ephemeral (Custom) או כתובת IPv6 חיצונית סטטית.
    4. לוחצים על סיום.
  4. לוחצים על Save.

gcloud

  1. אופציונלי: שומרים כתובת IP חיצונית סטטית.

    אם רוצים להקצות כתובת IP חיצונית סטטית, צריך לשמור כתובת ולוודא שהיא לא בשימוש של משאב אחר. אם צריך, פועלים לפי ההוראות לשמירת כתובת IP חיצונית סטטית חדשה או לביטול ההקצאה של כתובת IP חיצונית סטטית.

    אם אתם מתכוונים להשתמש בכתובת IP חיצונית ארעית, אתם יכולים לדלג על השלב הזה, ו-Compute Engine יקצה באופן אקראי כתובת IP חיצונית ארעית.

  2. מסירים את כל הקצאות כתובות ה-IP הקיימות, כמו שמתואר במאמר בנושא ביטול ההקצאה של כתובת IP חיצונית סטטית.

  3. מקצים את כתובת ה-IP החיצונית החדשה.

    • כדי להקצות כתובת IPv4, משתמשים בפקודת המשנה instances add-access-config:

      הערה: אל תחליפו את IP_ADDRESS בשם של כתובת ה-IP הסטטית. חובה להשתמש בכתובת ה-IP בפועל.
      gcloud compute instances add-access-config INSTANCE_NAME \
        --access-config-name="ACCESS_CONFIG_NAME" --address=IP_ADDRESS
      

      מחליפים את מה שכתוב בשדות הבאים:

      • ‫INSTANCE_NAME: השם של המכונה.
      • ‫ACCESS_CONFIG_NAME: השם שרוצים לתת להגדרת הגישה הזו. חשוב לכלול את השם המלא בין מרכאות.
      • ‫IP_ADDRESS: כתובת ה-IP שרוצים להוסיף.

      אם רוצים ש-Compute Engine יקצה כתובת IP חיצונית ארעית במקום להשתמש בכתובת IP חיצונית סטטית, משמיטים את המאפיין --address IP_ADDRESS:

      gcloud compute instances add-access-config INSTANCE_NAME \
        --access-config-name="ACCESS_CONFIG_NAME"
      
    • כדי לשנות מכונה למצב דואלי ולהקצות לה כתובת IPv6, משתמשים בפקודת המשנה instance network-interfaces update:

      gcloud compute instances network-interfaces update INSTANCE_NAME \
        --network-interface=NIC \
        --ipv6-network-tier=PREMIUM \
        --stack-type=STACK_TYPE \
        --external-ipv6-address=IPV6_ADDRESS \
        --external-ipv6-prefix-length=96 \
        --zone=ZONE
      

      מחליפים את מה שכתוב בשדות הבאים:

      • ‫INSTANCE_NAME: השם של המכונה.
      • ‫NIC: השם של ממשק הרשת.
      • ‫STACK_TYPE: סוג ה-stack של המופע, שחייב להיות IPV4_IPV6. אי אפשר לשנות את סוג המערך ל-IPV6_ONLY.
      • ‫IPV6_ADDRESS: כתובת ה-IPv6 שצריך להקצות למכונה. מציינים את כתובת ה-IPv6 הראשונה בטווח /96.
      • ‫ZONE: האזור של המכונה.

REST

כדי לשנות את כתובת ה-IPv4 או ה-IPv6 החיצונית של מכונה, צריך להוסיף הגדרת גישה חדשה למכונה הזו.

  1. מסירים את כל הקצאות כתובות ה-IP הקיימות, כמו שמתואר במאמר בנושא ביטול ההקצאה של כתובת IP חיצונית סטטית.

  2. שולחים בקשת POST אל ה-method‏ instances.deleteAccessConfig כדי למחוק את הגדרת הגישה הקיימת.

    POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/zones/ZONE/instances/INSTANCE_NAME/deleteAccessConfig
    
  3. כדי להוסיף הגדרת גישה חדשה לממשק הרשת של המכונה, שולחים בקשת POST אל ה-method‏ instances.addAccessConfig.

המשך

import (
	"context"
	"fmt"
	"io"

	"google.golang.org/protobuf/proto"

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

// assignStaticAddressToExistingVM assigns a static external IP address to an existing VM instance.
// Note: VM and assigned IP must be in the same region.
func assignStaticAddressToExistingVM(w io.Writer, projectID, zone, instanceName, IPAddress, networkInterfaceName string) error {
	// projectID := "your_project_id"
	// zone := "europe-central2-b"
	// instanceName := "your_instance_name"
	// IPAddress := "34.111.222.333"
	// networkInterfaceName := "nic0"

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

	reqGet := &computepb.GetInstanceRequest{
		Project:  projectID,
		Zone:     zone,
		Instance: instanceName,
	}

	instance, err := instancesClient.Get(ctx, reqGet)
	if err != nil {
		return fmt.Errorf("could not get instance: %w", err)
	}

	var networkInterface *computepb.NetworkInterface
	for _, ni := range instance.NetworkInterfaces {
		if *ni.Name == networkInterfaceName {
			networkInterface = ni
			break
		}
	}

	if networkInterface == nil {
		return fmt.Errorf("No network interface named '%s' found on instance %s", networkInterfaceName, instanceName)
	}

	var accessConfig *computepb.AccessConfig
	for _, ac := range networkInterface.AccessConfigs {
		if *ac.Type == computepb.AccessConfig_ONE_TO_ONE_NAT.String() {
			accessConfig = ac
			break
		}
	}

	if accessConfig != nil {
		// network interface is immutable - deletion stage is required in case of any assigned ip (static or ephemeral).
		reqDelete := &computepb.DeleteAccessConfigInstanceRequest{
			Project:          projectID,
			Zone:             zone,
			Instance:         instanceName,
			AccessConfig:     *accessConfig.Name,
			NetworkInterface: networkInterfaceName,
		}

		opDelete, err := instancesClient.DeleteAccessConfig(ctx, reqDelete)
		if err != nil {
			return fmt.Errorf("unable to delete access config: %w", err)
		}

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

	reqAdd := &computepb.AddAccessConfigInstanceRequest{
		Project:  projectID,
		Zone:     zone,
		Instance: instanceName,
		AccessConfigResource: &computepb.AccessConfig{
			NatIP: &IPAddress,
			Type:  proto.String(computepb.AccessConfig_ONE_TO_ONE_NAT.String()),
		},
		NetworkInterface: networkInterfaceName,
	}

	opAdd, err := instancesClient.AddAccessConfig(ctx, reqAdd)
	if err != nil {
		return fmt.Errorf("unable to add access config: %w", err)
	}

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

	fmt.Fprintf(w, "Static address %s assigned to the instance %s\n", IPAddress, instanceName)

	return nil
}

Java


import com.google.cloud.compute.v1.AccessConfig;
import com.google.cloud.compute.v1.AccessConfig.Type;
import com.google.cloud.compute.v1.Instance;
import com.google.cloud.compute.v1.InstancesClient;
import com.google.cloud.compute.v1.NetworkInterface;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class AssignStaticExistingVm {

  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 Google Cloud project you want to use.
    String projectId = "your-project-id";
    // Instance ID of the Google Cloud project you want to use.
    String instanceId = "your-instance-id";
    // Name of the zone to create the instance in. For example: "us-west3-b"
    String zone = "your-zone-id";
    // Name of the network interface to assign.
    String netInterfaceName = "your-netInterfaceName-id";

    assignStaticExistingVmAddress(projectId, instanceId, zone, netInterfaceName);
  }

  // Updates or creates an access configuration for a VM instance to assign a static external IP.
  // As network interface is immutable - deletion stage is required
  // in case of any assigned ip (static or ephemeral).
  // VM and ip address must be created before calling this function.
  // IMPORTANT: VM and assigned IP must be in the same region.
  public static Instance assignStaticExistingVmAddress(String projectId, String instanceId,
                                                       String zone, String netInterfaceName)
          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 (InstancesClient client = InstancesClient.create()) {
      Instance instance = client.get(projectId, zone, instanceId);

      NetworkInterface networkInterface = null;
      for (NetworkInterface netInterface : instance.getNetworkInterfacesList()) {
        if (netInterface.getName().equals(netInterfaceName)) {
          networkInterface = netInterface;
          break;
        }
      }

      if (networkInterface == null) {
        throw new IllegalArgumentException(
                String.format(
                        "No '{network_interface_name}' variable found on instance %s.",
                        instanceId)
        );
      }
      AccessConfig accessConfig = null;
      for (AccessConfig config : networkInterface.getAccessConfigsList()) {
        if (config.getType().equals(Type.ONE_TO_ONE_NAT.name())) {
          accessConfig = config;
          break;
        }
      }

      if (accessConfig != null) {
        // Delete the existing access configuration first
        client.deleteAccessConfigAsync(projectId, zone, instanceId,
                        accessConfig.getName(), netInterfaceName)
                .get(30, TimeUnit.SECONDS);
      }

      // Add a new access configuration with the new IP
      AccessConfig newAccessConfig = AccessConfig.newBuilder()
              // Leave this field undefined to use an IP from a shared ephemeral IP address pool
              // .setNatIP(ipAddress)
              .setType(Type.ONE_TO_ONE_NAT.name())
              .setName("external-nat")
              .build();

      client.addAccessConfigAsync(projectId, zone, instanceId, netInterfaceName, newAccessConfig)
              .get(30, TimeUnit.SECONDS);

      // return updated instance
      return client.get(projectId, zone, instanceId);
    }
  }
}

Python

import uuid

from google.cloud.compute_v1 import InstancesClient
from google.cloud.compute_v1.types import AccessConfig
from google.cloud.compute_v1.types import AddAccessConfigInstanceRequest
from google.cloud.compute_v1.types import DeleteAccessConfigInstanceRequest


def assign_static_ip_to_existing_vm(
    project_id: str,
    zone: str,
    instance_name: str,
    ip_address: str,
    network_interface_name: str = "nic0",
):
    """
    Updates or creates an access configuration for a VM instance to assign a static external IP.
    As network interface is immutable - deletion stage is required in case of any assigned ip (static or ephemeral).
    VM and ip address must be created before calling this function.
    IMPORTANT: VM and assigned IP must be in the same region.

    Args:
        project_id (str): Project ID.
        zone (str): Zone where the VM is located.
        instance_name (str): Name of the VM instance.
        ip_address (str): New static external IP address to assign to the VM.
        network_interface_name (str): Name of the network interface to assign.

    Returns:
        google.cloud.compute_v1.types.Instance: Updated instance object.
    """
    client = InstancesClient()
    instance = client.get(project=project_id, zone=zone, instance=instance_name)
    network_interface = next(
        (ni for ni in instance.network_interfaces if ni.name == network_interface_name),
        None,
    )

    if network_interface is None:
        raise ValueError(
            f"No network interface named '{network_interface_name}' found on instance {instance_name}."
        )

    access_config = next(
        (ac for ac in network_interface.access_configs if ac.type_ == "ONE_TO_ONE_NAT"),
        None,
    )

    if access_config:
        # Delete the existing access configuration first
        delete_request = DeleteAccessConfigInstanceRequest(
            project=project_id,
            zone=zone,
            instance=instance_name,
            access_config=access_config.name,
            network_interface=network_interface_name,
            request_id=str(uuid.uuid4()),
        )
        delete_operation = client.delete_access_config(delete_request)
        delete_operation.result()

    # Add a new access configuration with the new IP
    add_request = AddAccessConfigInstanceRequest(
        project=project_id,
        zone=zone,
        instance=instance_name,
        network_interface="nic0",
        access_config_resource=AccessConfig(
            nat_i_p=ip_address, type_="ONE_TO_ONE_NAT", name="external-nat"
        ),
        request_id=str(uuid.uuid4()),
    )
    add_operation = client.add_access_config(add_request)
    add_operation.result()

    updated_instance = client.get(project=project_id, zone=zone, instance=instance_name)
    return updated_instance

הגבלת כתובות IP חיצוניות למקרים ספציפיים

יכול להיות שיהיו לכם דרישות חיוניות לעומסי עבודה מסוימים, כולל הגבלות על אבטחה ורשת. לדוגמה, יכול להיות שתרצו להגביל כתובות IP חיצוניות כך שרק מופעים ספציפיים של Compute Engine יוכלו להשתמש בהן. האפשרות הזו יכולה לעזור למנוע זליגת נתונים או לשמור על בידוד הרשת.

באמצעות מדיניות הארגון, אתם יכולים להגביל את השימוש בכתובות IP חיצוניות למכונות וירטואליות ספציפיות באמצעות אילוצים, כדי לשלוט בשימוש בכתובות IP חיצוניות למכונות וירטואליות בארגון או בפרויקט.

האילוץ לשליטה בכתובת IP חיצונית במכונות הוא:

constraints/compute.vmExternalIpAccess

אם לא מציינים מדיניות ארגונית לכתובות IP חיצוניות, מותר להשתמש בכתובות IP חיצוניות בכל המקרים. כדי להשתמש באילוץ, צריך לציין מדיניות ארגון עם אחת מההגדרות הבאות:

  • מציינים רשימה ריקה allowedValues כדי שכל מופעי החישוב לא יוכלו לקבל כתובת IP חיצונית.
  • מציינים allowedValues רשימה של מופעי מחשוב שיכולים לקבל כתובות IP חיצוניות.
    • אפשר להקצות כתובת IP חיצונית, זמנית או סטטית, רק למכונות Compute שמופיעות ברשימה allowedValues.
    • כל שאר מופעי החישוב בארגון או בפרויקט שלא הוגדרו במפורש במדיניות, אסור להם להשתמש בכתובות IP חיצוניות.
  • אפשרות אחרת היא לציין את רשימת deniedValues כדי למנוע רק ממכונות וירטואליות ייעודיות לקבל כתובות IP חיצוניות. השתמשו בגישה הזו בזהירות, במיוחד אם אילוץ מדיניות הארגון חל על פרויקט שבו הוא מבטל אילוץ שחל על תיקיית הורה או על ארגון. מכיוון שרק למופעי ה-Compute שמצוינים ברשימה deniedValues נמנעת האפשרות להקצות כתובות IP חיצוניות, לכל מופעי ה-Compute החדשים שנוצרו בפרויקט יכולות להיות כתובות IP חיצוניות.

מופעים מזוהים ברשימות ההיתרים והחסימות באמצעות ה-URI של המופע:

projects/PROJECT_ID/zones/ZONE/instances/INSTANCE_NAME

הדרישות להגבלת כתובות IP חיצוניות

  • אפשר להחיל את compute.vmExternalIpAccess הגבלת הרשימה רק על מופעי מחשוב.
  • אי אפשר להחיל את ההגבלה רטרואקטיבית. כל מופעי החישוב שיש להם כתובות IP חיצוניות לפני שמפעילים את המדיניות שומרים על כתובות ה-IP החיצוניות שלהם.
  • ההגבלה הזו מקבלת רשימה של allowedValues או רשימה של deniedValues, אבל לא את שתי הרשימות באותה מדיניות.
  • אתם או אדמין עם ההרשאות הנדרשות צריכים לנהל ולתחזק את מחזור החיים והתקינות של המכונה הווירטואלית. האילוץ מאמת רק את ה-URI של המופע, והוא לא מונע שינוי, מחיקה או יצירה מחדש של המופעים ברשימת ההיתרים.

הנחיות להגבלת כתובות IP חיצוניות

כדי לאשר או לדחות כתובות IP חיצוניות למכונות Compute, פועלים לפי ההנחיות הבאות:

  • אם המטרה שלכם מבחינת אבטחה היא לאפשר יצירה של רק חלק ממכונות החישוב עם כתובות IP חיצוניות, אבל למנוע יצירה של מכונות אחרות עם כתובות IP חיצוניות, כדאי לזכור את הדברים הבאים כשמשתמשים ברשימת allowedValues או ברשימת deniedValues באילוץ של מדיניות הארגון constraints/compute.vmExternalIpAccess:

    • מוודאים שאילוץ מדיניות הארגון constraints/compute.vmExternalIpAccess לא מוחלף על ידי אילוץ מדיניות ארגון constraints/compute.vmExternalIpAccess שמוגדר במשאב צאצא.

    • מומלץ: משתמשים ברשימת allowedValues באילוץ של מדיניות הארגון constraints/compute.vmExternalIpAccess כדי לציין רק את מופעי ה-Compute שמורשים להשתמש בכתובות IP חיצוניות. כל המכונות החדשות שנוצרות בפרויקט מוחרגות באופן אוטומטי מכתובות IP חיצוניות, כי הן לא מופיעות ברשימה allowedValues באילוץ של מדיניות הארגון. לדוגמה, ראו הגדרת המדיניות ברמת הפרויקט.

  • אפשר להחריג פרויקטים ספציפיים בהיררכיית משאבים מהמגבלה constraints/compute.vmExternalIpAccess במדיניות הארגון באמצעות השיטה setOrgPolicy וציון restoreDefault.

  • כשמשתמשים ב-VPC משותף, החלת האילוץ constraints/compute.vmExternalIpAccess של מדיניות הארגון על הפרויקט המארח של ה-VPC המשותף חלה רק על מופעי מחשוב שנמצאים בפועל בפרויקט המארח עצמו. מכונות שנמצאות בפרויקטים של שירות לא מושפעות, אלא אם מחילים את האילוץ של מדיניות הארגון constraints/compute.vmExternalIpAccess על כל פרויקט שירות.

  • כדי לשלוט טוב יותר בסביבה שלכם, כדאי להשתמש במדיניות הארגון יחד עם תפקידי IAM. המדיניות הזו חלה רק על מופעי מחשוב. כדי לשלוט טוב יותר בכתובות ה-IP החיצוניות במכשירי הרשת ולהגביל אותן, אתם יכולים להקצות את התפקיד compute.networkAdmin רק לגורמים המתאימים.

שימוש במדיניות ארגונית של כתובות IP חיצוניות עם שירותים מנוהלים

constraints/compute.vmExternalIpAccess האילוץ של מדיניות הארגון חל על מופעי מחשוב שנוצרו לאחרונה וממוקמים בפרויקט שנמצא בהיקף של האילוץ של מדיניות הארגון. המקרים שמושפעים כוללים צמתים של Google Kubernetes Engine, מקרים של Dataflow ומקרים של Managed Service for Apache Spark אם הם נוצרו בפרויקט שלכם ואם הפרויקט שלכם נמצא בהיקף של ההגבלה הזו של מדיניות הארגון.

שירותים מנוהלים מבוססי-מכונה שמשתמשים בגישה לשירותים פרטיים מופעלים על ידי מכונות מחשוב שנמצאות בפרויקטים לשירות מנוהל, שהם נפרדים מהפרויקט שלכם. למופעי Compute בשירותים מנוהלים יש ממשקי רשת ברשת של בעלים של שירות מנוהל שעוברת קישור בין רשתות שכנות (peering) עם רשת ה-VPC שלכם. אם אילוץ מדיניות הארגון constraints/compute.vmExternalIpAccess חל על הפרויקט שלכם (הפרויקט שמכיל את רשת ה-VPC), לאילוץ מדיניות הארגון אין השפעה על מופעי ה-Compute של שירותים מנוהלים מחוץ לפרויקט.

חלק מהשירותים המנוהלים מציעים אילוצים משלהם על מדיניות הארגון, עם יכולות דומות. לדוגמה, ל-Cloud SQL יש את constraints/sql.restrictPublicIp.

ההרשאות שנדרשות להגבלת כתובות IP חיצוניות

כדי להגדיר אילוץ ברמת הפרויקט או ברמת הארגון, צריך לקבל את התפקיד orgpolicy.policyAdmin בארגון.

הגדרת אילוץ המדיניות ברמת הארגון

המסוף

  1. עוברים לדף מדיניות ארגונית.

    אל מדיניות הארגון

  2. אם צריך, בוחרים את הארגון הרצוי מהתפריט הנפתח של הפרויקט.
  3. בתפריט מסנן, מזינים את הטקסט Define allowed.

    בטבלה Policies (מדיניות) אמורות להופיע שתי שורות.

  4. לוחצים על שם המדיניות Define allowed external IPs for VM instances בעמודה Name בטבלה.

  5. בדף פרטי המדיניות, לוחצים על ניהול המדיניות כדי לערוך את מדיניות כתובות ה-IP החיצוניות. אם אין לכם גישה לקישור ניהול מדיניות, סימן שאין לכם את ההרשאות המתאימות.

  6. לוחצים על ניהול המדיניות.

    ייפתח הדף עריכת מדיניות.

  7. בקטע חל על, בוחרים באפשרות במקום המדיניות של המשאב הראשי.

  8. בקטע אכיפת מדיניות, בוחרים באפשרות מיזוג עם ההורה.

  9. לוחצים על Add a rule.

    1. בקטע ערכי מדיניות, בוחרים באפשרות בהתאמה אישית.

    2. בקטע סוג המדיניות, בוחרים אם מדיניות הארגון צריכה לאשר או לדחות את הערכים שצוינו.

    3. בשדה ערך מותאם אישית, מזינים URI של מופע. ה-URI צריך להיות בפורמט הבא:

      projects/PROJECT_ID/zones/ZONE/instances/INSTANCE_NAME
      
    4. כדי להוסיף עוד מופעי מחשוב, לוחצים על הוספת ערך ואז מזינים כתובות URI של מופעים נוספים.

  10. כדי לאכוף את המדיניות, לוחצים על הגדרת מדיניות.

gcloud

כדי להגדיר אילוץ לגישה לכתובת IP חיצונית, קודם צריך את מזהה הארגון. כדי למצוא את מזהה הארגון, מריצים את הפקודה organizations list ומחפשים את המזהה המספרי בתשובה:

gcloud organizations list

ה-CLI של gcloud מחזיר רשימה של ארגונים בפורמט הבא:

DISPLAY_NAME               ID
example-organization1      29252605212
example-organization2      1234567890

משתמשים בפקודה gcloud resource-manager org-policies set-policy כדי להגדיר את המדיניות. צריך לספק את המדיניות כקובץ JSON. יוצרים קובץ JSON בפורמט הבא:

{
"constraint": "constraints/compute.vmExternalIpAccess",
"listPolicy": {
  "allowedValues": [
     "projects/PROJECT_ID/zones/ZONE/instances/INSTANCE_NAME",
     "projects/PROJECT_ID/zones/ZONE/instances/INSTANCE_NAME",
     "projects/PROJECT_ID/zones/ZONE/instances/INSTANCE_NAME"
  ]
 }
}

מחליפים את מה שכתוב בשדות הבאים:

  • ‫PROJECT_ID: מזהה הפרויקט של הבקשה הזו, כמו example-project. שימו לב שזה שונה מהגדרת כללי מדיניות של הארגון, שדורשים את המזהה המספרי של הארגון.
  • ‫ZONE: האזור של המכונה
  • ‫INSTANCE_NAME: השם של המכונה

אפשר גם לציין deniedValues רשימה כדי לציין מכונות שרוצים למנוע מהן באופן מפורש לקבל כתובת IP חיצונית. כל מכונה שלא נמצאת ברשימה תורשה באופן משתמע לקבל כתובת IP חיצונית. אפשר לציין רק allowedValues או deniedValues, אבל לא את שניהם.

לאחר מכן, מעבירים את הקובץ עם הבקשה:

gcloud resource-manager org-policies set-policy MY_POLICY.JSON --organization=ORGANIZATION_ID

מחליפים את ORGANIZATION_ID במזהה המספרי של הארגון.

אם אתם לא רוצים שלמכונות תהיה גישה לכתובות IP חיצוניות, אתם יכולים להגדיר מדיניות שבה allValues מוגדר ל-DENY:

{
  "constraint": "constraints/compute.vmExternalIpAccess",
  "listPolicy": {
    "allValues": "DENY"
  }
}

REST

משתמשים ב-API של setOrgPolicy() כדי להגדיר את האילוץ. למכונות ברשימה allowedValues שציינתם מותרות כתובות IP חיצוניות. אפשר גם לציין רשימה של deniedValues כדי להחריג מכונות וירטואליות שאסור להן להחזיק כתובת IP חיצונית. כל מכונה שלא נמצאת ברשימה יכולה לקבל כתובת IP חיצונית באופן משתמע. אפשר לציין רק את allowedValues או את deniedValues, אבל לא את שניהם.

לדוגמה, הבקשה הבאה מחילה את האילוץ compute.vmExternalIpAccess על ארגון שבו למכונות מפרויקטים מסוימים בארגון מותר להשתמש בכתובות IP חיצוניות:

POST https://cloudresourcemanager.googleapis.com/v1/organizations/ORGANIZATION_ID:setOrgPolicy

‫ORGANIZATION_ID הוא המזהה המספרי של הארגון.

עכשיו, בגוף הבקשה, מציינים את המדיניות של האילוץ הזה:

{
  "policy": {
    "constraint": "constraints/compute.vmExternalIpAccess",
    "listPolicy": {
      "allowedValues": [
        "projects/PROJECT_ID/zones/ZONE/instances/INSTANCE_NAME",
        "projects/PROJECT_ID/zones/ZONE/instances/INSTANCE_NAME",
        "projects/PROJECT_ID/zones/ZONE/instances/INSTANCE_NAME"
        ]
      }
    }
 }

אם אתם לא רוצים שלמופעים תהיה גישה לכתובת IP חיצונית, אתם יכולים להגדיר מדיניות עם allValues שמוגדר ל-DENY:

{
  "policy": {
    "constraint": "constraints/compute.vmExternalIpAccess",
    "listPolicy": {
      "allValues": "DENY"
      }
    }
 }

הגדרת המדיניות ברמת הפרויקט

הגדרת מדיניות ברמת הפרויקט מבטלת את המדיניות ברמת הארגון. לדוגמה, אם ברמת הארגון יש example-vm-1 ברשימה allowedValues, אבל במדיניות ברמת הפרויקט יש את אותו מופע ברשימה deniedValues, המופע לא יוכל לקבל כתובת IP חיצונית.

המסוף

מבצעים את אותו תהליך שמתואר בקטע הגדרת אילוץ מדיניות ברמת הארגון, אבל בוחרים את הפרויקט מהבורר של הפרויקטים במקום את הארגון.

בורר הפרויקטים.

gcloud

משתמשים בפקודה gcloud resource-manager org-policies set-policy כדי להגדיר את המדיניות. צריך לספק את המדיניות כקובץ JSON. יוצרים קובץ JSON בפורמט הבא:

{
 "constraint": "constraints/compute.vmExternalIpAccess",
 "listPolicy": {
  "allowedValues": [
   "projects/PROJECT_ID/zones/ZONE/instances/INSTANCE_NAME"
  ]
 }
}

מחליפים את מה שכתוב בשדות הבאים:

  • ‫PROJECT_ID: מזהה הפרויקט של הבקשה הזו, למשל example-project. שימו לב: ההגדרה הזו שונה מהגדרה של מדיניות הארגון, שדורשת את המזהה המספרי של הארגון.
  • ‫ZONE: האזור של המכונה.
  • ‫INSTANCE_NAME: השם של המכונה.

אפשר גם לציין deniedValues רשימה של מכונות שרוצים לאסור עליהן באופן מפורש להחזיק כתובת IP חיצונית. כל מכונה שלא מופיעה ברשימה הזו תורשה באופן מרומז להקצות כתובת IP חיצונית. אפשר לציין רק את allowedValues או את deniedValues, אבל לא את שניהם.

לאחר מכן, מעבירים את הקובץ עם הבקשה:

gcloud resource-manager org-policies set-policy MY_POLICY.JSON --project=example-project

REST

משתמשים ב-API של setOrgPolicy כדי להגדיר את האילוץ. למכונות ברשימה allowedValues שציינתם יכולות להיות כתובות IP חיצוניות. אפשר גם לציין רשימה של deniedValues כדי להחריג מכונות וירטואליות שאסור להן להחזיק כתובת IP חיצונית. לכל מופע שלא מופיע ברשימה מותר באופן מרומז להקצות כתובת IP חיצונית. אפשר לציין רק allowedValues או deniedValues, אבל לא את שניהם.

לדוגמה, הבקשה הבאה מגדירה את האילוץ compute.vmExternalIpAccess בפרויקט, כדי לאפשר למכונות ספציפיות להשתמש בכתובות IP חיצוניות:

POST https://cloudresourcemanager.googleapis.com/v1/projects/PROJECT_ID:setOrgPolicy

מחליפים את PROJECT_ID במזהה הפרויקט של הבקשה הזו.

גוף הבקשה מכיל את המדיניות של המגבלה הזו:

{
  "policy": {
    "constraint": "constraints/compute.vmExternalIpAccess",
    "listPolicy": {
      "allowedValues": [
        "projects/PROJECT_ID/zones/ZONE/instances/INSTANCE_NAME"
      ]
    }
  }
}

ניהול כתובות IP חיצוניות סטטיות

בקטעים הבאים מוסבר איך לנהל כתובות IP חיצוניות סטטיות במכונות.

איך קובעים אם כתובת IP חיצונית היא ארעית או סטטית

כתובות IP חיצוניות סטטיות וכתובות IP חיצוניות זמניות מתנהגות ונראות אותו הדבר ברוב ההקשרים. לעומת זאת, בכתובות IP חיצוניות סטטיות, אתם יכולים להשתמש באותה כתובת IP לאותו משאב גם אם אתם מוחקים ויוצרים מחדש את המשאב.

באופן כללי, כתובת IP זמנית משוחררת אם מפסיקים או מוחקים את המשאב.

כדי לקבוע אם כתובת היא סטטית או זמנית, מבצעים את הפעולות הבאות:

  1. נכנסים לדף IP addresses במסוף Google Cloud .

    לדף IP addresses

  2. מוצאים את הכתובת ברשימה ובודקים את הסוג של כתובת ה-IP בעמודה Type.

ביטול ההקצאה של כתובת IP חיצונית סטטית

ביטול ההקצאה של כתובת IP מסיר אותה מהמשאב, אבל כתובת ה-IP נשארת שמורה. אחרי שמבטלים את ההקצאה של כתובת ה-IP, אפשר להקצות אותה מחדש למשאב אחר. התהליך הזה נתמך במופעים עם כתובות IPv4 ו-IPv6, אבל לא במופעים עם כתובות IPv6 בלבד.

אפשר גם לבטל את ההקצאה של כתובת IPv4 או IPv6 על ידי מחיקת המכונה.

המסוף

  1. נכנסים לדף IP addresses במסוף Google Cloud .

    מעבר אל כתובות IP

  2. לוחצים על External IP addresses (כתובות IP חיצוניות).

  3. בוחרים את כתובת ה-IP הסטטית שרוצים לבטל את ההקצאה שלה.

  4. לוחצים על הצגת הפעולות ובוחרים באפשרות הקצאה מחדש למשאב אחר.

  5. בתפריט הנפתח Attach to, בוחרים באפשרות None.

  6. לוחצים על OK.

gcloud

  1. כדי לבדוק אם כתובת IP סטטית נמצאת בשימוש, משתמשים בפקודה gcloud compute addresses list:

    gcloud compute addresses list
    

    הפלט אמור להיראות כך:

    NAME                      REGION    ADDRESS                  STATUS
    example-address-ipv4      REGION    198.51.100.1             RESERVED
    example-address-new-ipv4  REGION    203.0.113.1              IN_USE
    example-address-ipv6      REGION    2001:db8:1:1:1:1:1:1     RESERVED
    example-address-new-ipv6  REGION    2001:db8:4:4:4:4:4:4     IN_USE
    
    • אם כתובת ה-IP לא בשימוש, הסטטוס הוא RESERVED.
    • אם כתובת ה-IP נמצאת בשימוש, הסטטוס הוא IN_USE.
  2. מאחזרים את שם המכונה שמשתמשת בכתובת ה-IP:

    gcloud compute addresses describe ADDRESS_NAME \
      --region=REGION
    

    מחליפים את מה שכתוב בשדות הבאים:

    • ‫ADDRESS_NAME: השם של משאב כתובת ה-IPv6.
    • ‫REGION: האזור של משאב כתובת ה-IPv6.

    הפלט אמור להיראות כך:

    address: IP_ADDRESS
    addressType: EXTERNAL
    ...
    region: https://www.googleapis.com/compute/v1/projects/PROJECT/regions/REGION
    selfLink: https://www.googleapis.com/compute/v1/projects/PROJECT/regions/REGION/addresses/ADDRESS_NAME
    status: IN_USE
    subnetwork: https://www.googleapis.com/compute/v1/projects/PROJECT/regions/REGION/subnetworks/SUBNET
    users:
    - https://www.googleapis.com/compute/v1/projects/PROJECT/zones/ZONE/instances/INSTANCE_NAME
    

    בשדה users מוצג שם המכונה שמשתמשת בכתובת ה-IP.

  3. מבטלים את ההקצאה של כתובת ה-IP למכונה.

    • כדי לבטל את ההקצאה של כתובת IPv4, מוחקים את קובץ תצורת הגישה של המכונה:

      1. משיגים את השם של הגדרת הגישה שרוצים למחוק. כדי לקבל את השם, משתמשים בפקודה gcloud compute instances describe. מחליפים את INSTANCE_NAME בשם המכונה.

        gcloud compute instances describe INSTANCE_NAME
        

        הגדרת הגישה מופיעה בפורמט הבא:

        networkInterfaces:
          - accessConfigs:
            - kind: compute#accessConfig
              name: external-nat
              natIP: 203.0.113.1
              type: ONE_TO_ONE_NAT
        
      2. כדי למחוק את הגדרת הגישה, משתמשים בפקודה gcloud compute instances delete-access-config:

        gcloud compute instances delete-access-config INSTANCE_NAME \
          --access-config-name="ACCESS_CONFIG_NAME"
        

        מחליפים את מה שכתוב בשדות הבאים:

        • ‫INSTANCE_NAME: השם של המכונה.
        • ‫ACCESS_CONFIG_NAME: השם של הגדרות הגישה שרוצים למחוק. חשוב לכלול את השם המלא בין מירכאות.
    • כדי לבטל את ההקצאה של טווח כתובות IPv6, משתמשים בפקודה instance network-interfaces update:

      gcloud compute instances network-interfaces update INSTANCE_NAME \
        --network-interface=nic0 \
        --stack-type=IPV4_ONLY \
        --zone=ZONE
      

      מחליפים את מה שכתוב בשדות הבאים:

      • ‫INSTANCE_NAME: השם של המכונה שמשתמשת בכתובת ה-IP.
      • ‫ZONE: האזור של המכונה.
  4. בודקים שכתובת ה-IP החיצונית הסטטית זמינה עכשיו ומסומנת כ-RESERVED במקום כ-IN_USE.

    gcloud compute addresses list \
      --filter="ADDRESS_NAME AND region=REGION"
    

    מחליפים את מה שכתוב בשדות הבאים:

    • ‫ADDRESS_NAME: השם של משאב כתובת ה-IP.
    • ‫REGION: האזור של משאב כתובת ה-IP.

עכשיו, כשכתובת ה-IP החיצונית הסטטית זמינה, אתם יכולים להקצות אותה למופע אחר.

REST

כדי לבטל את ההקצאה של כתובת IPv4 או IPv6 חיצונית סטטית, מבצעים את השלבים הבאים:

  • במקרה של כתובות IPv4, מוחקים את הגדרת הגישה שמצורפת למכונה שמשתמשת בכתובת.

    1. כדי לבדוק את פרטי הגדרת הגישה של מכונה, שולחים בקשת GET אל ה-method‏ instances.get.

      GET https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/zones/ZONE/instances/INSTANCE_NAME
      
    2. כדי למחוק את הגדרת הגישה הקיימת, שולחים בקשת POST אל ה-method‏ instances.deleteAccessConfig.

      POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/zones/ZONE/instances/INSTANCE_NAME/deleteAccessConfig
      

      מחליפים את מה שכתוב בשדות הבאים:

      • ‫PROJECT_ID: מזהה הפרויקט של הבקשה הזו
      • ‫ZONE: האזור שבו נמצאת המכונה
      • ‫INSTANCE_NAME: השם של המכונה
  • לגבי כתובות IPv6, צריך לעדכן את סוג הערימה של ממשק הרשת של המכונה שאליה מצורפת כתובת ה-IPv6.

    1. שולחים בקשת PATCH ל-method‏ instances.updateNetworkInterface.

    2. בגוף הבקשה, מעדכנים את הערך של השדה stackType לערך IPV4_ONLY.

      לדוגמה:

      PATCH https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/zones/ZONE/instances/INSTANCE_NAME/updateNetworkInterface
      
      {
        "networkInterfaces": [{
          ...
          "stackType" : "IPV4_ONLY"
          ...
          }]
      }
      

Java


import com.google.cloud.compute.v1.AccessConfig;
import com.google.cloud.compute.v1.AccessConfig.Type;
import com.google.cloud.compute.v1.Instance;
import com.google.cloud.compute.v1.InstancesClient;
import com.google.cloud.compute.v1.NetworkInterface;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class UnassignStaticIpAddress {

  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 Google Cloud project you want to use.
    String projectId = "your-project-id";
    // Instance ID of the Google Cloud project you want to use.
    String instanceId = "your-instance-id";
    // Name of the zone to create the instance in. For example: "us-west3-b"
    String zone = "your-zone";
    // Name of the network interface to assign.
    String netInterfaceName = "your-netInterfaceName";

    unassignStaticIpAddress(projectId, instanceId, zone, netInterfaceName);
  }

  public static Instance unassignStaticIpAddress(String projectId, String instanceId,
                                                 String zone, String netInterfaceName)
          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 (InstancesClient client = InstancesClient.create()) {
      Instance instance = client.get(projectId, zone, instanceId);
      NetworkInterface networkInterface = null;
      for (NetworkInterface netIterface : instance.getNetworkInterfacesList()) {
        if (netIterface.getName().equals(netInterfaceName)) {
          networkInterface = netIterface;
          break;
        }
      }

      if (networkInterface == null) {
        throw new IllegalArgumentException(
                String.format(
                        "No '{network_interface_name}' variable found on instance %s.",
                        instanceId)
        );
      }

      AccessConfig accessConfig = null;
      for (AccessConfig config : networkInterface.getAccessConfigsList()) {
        if (config.getType().equals(Type.ONE_TO_ONE_NAT.name())) {
          accessConfig = config;
          break;
        }
      }

      if (accessConfig != null) {
        // Delete the existing access configuration first
        client.deleteAccessConfigAsync(projectId, zone, instanceId,
                        accessConfig.getName(), netInterfaceName).get(30, TimeUnit.SECONDS);
      }

      // return updated instance
      return client.get(projectId, zone, instanceId);
    }
  }
}

Python

import uuid

from google.cloud.compute_v1 import InstancesClient
from google.cloud.compute_v1.types import DeleteAccessConfigInstanceRequest


def unassign_static_ip_from_existing_vm(
    project_id: str,
    zone: str,
    instance_name: str,
    network_interface_name: str = "nic0",
):
    """
    Updates access configuration for a VM instance to unassign a static external IP.
    VM (and IP address in case of static IP assigned) must be created before calling this function.

    Args:
        project_id (str): Project ID.
        zone (str): Zone where the VM is located.
        instance_name (str): Name of the VM instance.
        network_interface_name (str): Name of the network interface to unassign.
    """
    client = InstancesClient()
    instance = client.get(project=project_id, zone=zone, instance=instance_name)
    network_interface = next(
        (ni for ni in instance.network_interfaces if ni.name == network_interface_name),
        None,
    )

    if network_interface is None:
        raise ValueError(
            f"No network interface named '{network_interface_name}' found on instance {instance_name}."
        )

    access_config = next(
        (ac for ac in network_interface.access_configs if ac.type_ == "ONE_TO_ONE_NAT"),
        None,
    )

    if access_config:
        # Delete the existing access configuration
        delete_request = DeleteAccessConfigInstanceRequest(
            project=project_id,
            zone=zone,
            instance=instance_name,
            access_config=access_config.name,
            network_interface=network_interface_name,
            request_id=str(uuid.uuid4()),
        )
        delete_operation = client.delete_access_config(delete_request)
        delete_operation.result()

    updated_instance = client.get(project=project_id, zone=zone, instance=instance_name)
    return updated_instance

שחרור כתובת IP חיצונית סטטית

אם כבר אין לכם צורך בכתובת IP חיצונית סטטית מסוג IPv4 או IPv6, אתם יכולים למחוק את משאב כתובת ה-IP כדי לבטל את ההקצאה של כתובת ה-IP. מחיקת מופע לא גורמת לשחרור אוטומטי של כתובת IP חיצונית סטטית. כשאין יותר צורך בכתובות IP חיצוניות סטטיות, צריך לבטל את ההקצאה שלהן באופן ידני.

כדי לשחרר כתובת IP חיצונית סטטית, קראו את המאמר שחרור כתובת IP חיצונית סטטית במסמכי התיעוד של VPC.

המאמרים הבאים