The gcp:edgecontainer/nodePool:NodePool resource, part of the Pulumi GCP provider, defines a group of Kubernetes worker nodes in a Distributed Cloud Edge cluster with shared configuration and edge location placement. This guide focuses on one capability: worker node provisioning at edge locations.
Node pools belong to an existing Distributed Cloud Edge cluster and run on machines at specific edge zones. The example is intentionally small. Combine it with your own cluster, edge infrastructure, and node configuration.
Add worker nodes to an edge cluster
Distributed Cloud Edge clusters run Kubernetes workloads on machines at edge locations. Node pools group worker nodes with shared placement and configuration.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const project = gcp.organizations.getProject({});
const _default = new gcp.edgecontainer.Cluster("default", {
name: "default",
location: "us-central1",
authorization: {
adminUsers: {
username: "admin@hashicorptest.com",
},
},
networking: {
clusterIpv4CidrBlocks: ["10.0.0.0/16"],
servicesIpv4CidrBlocks: ["10.1.0.0/16"],
},
fleet: {
project: project.then(project => `projects/${project.number}`),
},
externalLoadBalancerIpv4AddressPools: ["10.100.0.0-10.100.0.10"],
controlPlane: {
local: {
nodeLocation: "us-central1-edge-example-edgesite",
nodeCount: 1,
machineFilter: "machine-name",
sharedDeploymentPolicy: "ALLOWED",
},
},
});
const defaultNodePool = new gcp.edgecontainer.NodePool("default", {
name: "nodepool-1",
cluster: cluster.name,
location: "us-central1",
nodeLocation: "us-central1-edge-example-edgesite",
nodeCount: 3,
});
import pulumi
import pulumi_gcp as gcp
project = gcp.organizations.get_project()
default = gcp.edgecontainer.Cluster("default",
name="default",
location="us-central1",
authorization={
"admin_users": {
"username": "admin@hashicorptest.com",
},
},
networking={
"cluster_ipv4_cidr_blocks": ["10.0.0.0/16"],
"services_ipv4_cidr_blocks": ["10.1.0.0/16"],
},
fleet={
"project": f"projects/{project.number}",
},
external_load_balancer_ipv4_address_pools=["10.100.0.0-10.100.0.10"],
control_plane={
"local": {
"node_location": "us-central1-edge-example-edgesite",
"node_count": 1,
"machine_filter": "machine-name",
"shared_deployment_policy": "ALLOWED",
},
})
default_node_pool = gcp.edgecontainer.NodePool("default",
name="nodepool-1",
cluster=cluster["name"],
location="us-central1",
node_location="us-central1-edge-example-edgesite",
node_count=3)
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/edgecontainer"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
project, err := organizations.LookupProject(ctx, &organizations.LookupProjectArgs{}, nil)
if err != nil {
return err
}
_, err = edgecontainer.NewCluster(ctx, "default", &edgecontainer.ClusterArgs{
Name: pulumi.String("default"),
Location: pulumi.String("us-central1"),
Authorization: &edgecontainer.ClusterAuthorizationArgs{
AdminUsers: &edgecontainer.ClusterAuthorizationAdminUsersArgs{
Username: pulumi.String("admin@hashicorptest.com"),
},
},
Networking: &edgecontainer.ClusterNetworkingArgs{
ClusterIpv4CidrBlocks: pulumi.StringArray{
pulumi.String("10.0.0.0/16"),
},
ServicesIpv4CidrBlocks: pulumi.StringArray{
pulumi.String("10.1.0.0/16"),
},
},
Fleet: &edgecontainer.ClusterFleetArgs{
Project: pulumi.Sprintf("projects/%v", project.Number),
},
ExternalLoadBalancerIpv4AddressPools: pulumi.StringArray{
pulumi.String("10.100.0.0-10.100.0.10"),
},
ControlPlane: &edgecontainer.ClusterControlPlaneArgs{
Local: &edgecontainer.ClusterControlPlaneLocalArgs{
NodeLocation: pulumi.String("us-central1-edge-example-edgesite"),
NodeCount: pulumi.Int(1),
MachineFilter: pulumi.String("machine-name"),
SharedDeploymentPolicy: pulumi.String("ALLOWED"),
},
},
})
if err != nil {
return err
}
_, err = edgecontainer.NewNodePool(ctx, "default", &edgecontainer.NodePoolArgs{
Name: pulumi.String("nodepool-1"),
Cluster: pulumi.Any(cluster.Name),
Location: pulumi.String("us-central1"),
NodeLocation: pulumi.String("us-central1-edge-example-edgesite"),
NodeCount: pulumi.Int(3),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var project = Gcp.Organizations.GetProject.Invoke();
var @default = new Gcp.EdgeContainer.Cluster("default", new()
{
Name = "default",
Location = "us-central1",
Authorization = new Gcp.EdgeContainer.Inputs.ClusterAuthorizationArgs
{
AdminUsers = new Gcp.EdgeContainer.Inputs.ClusterAuthorizationAdminUsersArgs
{
Username = "admin@hashicorptest.com",
},
},
Networking = new Gcp.EdgeContainer.Inputs.ClusterNetworkingArgs
{
ClusterIpv4CidrBlocks = new[]
{
"10.0.0.0/16",
},
ServicesIpv4CidrBlocks = new[]
{
"10.1.0.0/16",
},
},
Fleet = new Gcp.EdgeContainer.Inputs.ClusterFleetArgs
{
Project = $"projects/{project.Apply(getProjectResult => getProjectResult.Number)}",
},
ExternalLoadBalancerIpv4AddressPools = new[]
{
"10.100.0.0-10.100.0.10",
},
ControlPlane = new Gcp.EdgeContainer.Inputs.ClusterControlPlaneArgs
{
Local = new Gcp.EdgeContainer.Inputs.ClusterControlPlaneLocalArgs
{
NodeLocation = "us-central1-edge-example-edgesite",
NodeCount = 1,
MachineFilter = "machine-name",
SharedDeploymentPolicy = "ALLOWED",
},
},
});
var defaultNodePool = new Gcp.EdgeContainer.NodePool("default", new()
{
Name = "nodepool-1",
Cluster = cluster.Name,
Location = "us-central1",
NodeLocation = "us-central1-edge-example-edgesite",
NodeCount = 3,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetProjectArgs;
import com.pulumi.gcp.edgecontainer.Cluster;
import com.pulumi.gcp.edgecontainer.ClusterArgs;
import com.pulumi.gcp.edgecontainer.inputs.ClusterAuthorizationArgs;
import com.pulumi.gcp.edgecontainer.inputs.ClusterAuthorizationAdminUsersArgs;
import com.pulumi.gcp.edgecontainer.inputs.ClusterNetworkingArgs;
import com.pulumi.gcp.edgecontainer.inputs.ClusterFleetArgs;
import com.pulumi.gcp.edgecontainer.inputs.ClusterControlPlaneArgs;
import com.pulumi.gcp.edgecontainer.inputs.ClusterControlPlaneLocalArgs;
import com.pulumi.gcp.edgecontainer.NodePool;
import com.pulumi.gcp.edgecontainer.NodePoolArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
final var project = OrganizationsFunctions.getProject(GetProjectArgs.builder()
.build());
var default_ = new Cluster("default", ClusterArgs.builder()
.name("default")
.location("us-central1")
.authorization(ClusterAuthorizationArgs.builder()
.adminUsers(ClusterAuthorizationAdminUsersArgs.builder()
.username("admin@hashicorptest.com")
.build())
.build())
.networking(ClusterNetworkingArgs.builder()
.clusterIpv4CidrBlocks("10.0.0.0/16")
.servicesIpv4CidrBlocks("10.1.0.0/16")
.build())
.fleet(ClusterFleetArgs.builder()
.project(String.format("projects/%s", project.number()))
.build())
.externalLoadBalancerIpv4AddressPools("10.100.0.0-10.100.0.10")
.controlPlane(ClusterControlPlaneArgs.builder()
.local(ClusterControlPlaneLocalArgs.builder()
.nodeLocation("us-central1-edge-example-edgesite")
.nodeCount(1)
.machineFilter("machine-name")
.sharedDeploymentPolicy("ALLOWED")
.build())
.build())
.build());
var defaultNodePool = new NodePool("defaultNodePool", NodePoolArgs.builder()
.name("nodepool-1")
.cluster(cluster.name())
.location("us-central1")
.nodeLocation("us-central1-edge-example-edgesite")
.nodeCount(3)
.build());
}
}
resources:
default:
type: gcp:edgecontainer:Cluster
properties:
name: default
location: us-central1
authorization:
adminUsers:
username: admin@hashicorptest.com
networking:
clusterIpv4CidrBlocks:
- 10.0.0.0/16
servicesIpv4CidrBlocks:
- 10.1.0.0/16
fleet:
project: projects/${project.number}
externalLoadBalancerIpv4AddressPools:
- 10.100.0.0-10.100.0.10
controlPlane:
local:
nodeLocation: us-central1-edge-example-edgesite
nodeCount: 1
machineFilter: machine-name
sharedDeploymentPolicy: ALLOWED
defaultNodePool:
type: gcp:edgecontainer:NodePool
name: default
properties:
name: nodepool-1
cluster: ${cluster.name}
location: us-central1
nodeLocation: us-central1-edge-example-edgesite
nodeCount: 3
variables:
project:
fn::invoke:
function: gcp:organizations:getProject
arguments: {}
The cluster property references the parent edge cluster by name. The nodeLocation property specifies which edge zone hosts these nodes (e.g., us-central1-edge-example-edgesite). The machineFilter property controls which physical machines can join this pool using AIP-160 filter syntax. The nodeCount property sets how many nodes to provision.
Beyond these examples
This snippet focuses on worker node provisioning at edge locations. It’s intentionally minimal rather than a complete edge deployment.
The example references pre-existing infrastructure such as a Distributed Cloud Edge cluster and an edge zone with available machines. It focuses on configuring the node pool rather than provisioning the cluster or edge infrastructure.
To keep things focused, common node pool patterns are omitted, including:
- Node configuration (nodeConfig for labels, resources)
- Local disk encryption (localDiskEncryption with KMS keys)
- Node pool labels for organization
These omissions are intentional: the goal is to illustrate how the node pool resource is wired, not provide drop-in edge modules. See the EdgeContainer NodePool resource reference for all available configuration options.
Let's configure GCP Edge Container Node Pools
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Configuration & Immutability
cluster, location, name, nodeLocation, and project. Changing any of these requires recreating the node pool.us-central1-edge-customer-a or us-central1-edge-example-edgesite.name=<name> and follows the AIP-160 specification. Only machines matching this filter can join the node pool.Labels & Metadata
labels field is non-authoritative and only manages labels in your configuration. Use effectiveLabels to see all labels present on the resource in GCP, including those set by other clients and services.Import & Migration
projects/{{project}}/locations/{{location}}/clusters/{{cluster}}/nodePools/{{name}}, {{project}}/{{location}}/{{cluster}}/{{name}}, or {{location}}/{{cluster}}/{{name}}.Using a different cloud?
Explore containers guides for other cloud providers: