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 placement. This guide focuses on one capability: provisioning worker nodes at edge locations.
Node pools belong to an existing Distributed Cloud Edge cluster and reference physical 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 physical hardware at edge locations. Node pools define groups of worker nodes that join the cluster to provide compute capacity.
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 (
"fmt"
"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 identifies which edge cluster these nodes join. The nodeLocation property specifies the edge zone where physical machines reside (for example, us-central1-edge-customer-a). The machineFilter property uses AIP-160 filtering syntax to select which physical machines can join this pool; only machines matching the filter are allowed. The nodeCount property sets how many nodes to provision from the filtered machine set.
Beyond these examples
This snippet focuses on worker node provisioning at edge locations. It’s intentionally minimal rather than a full edge deployment.
The example references pre-existing infrastructure such as a Distributed Cloud Edge cluster, physical machines at edge sites, and edge zone configuration. It focuses on configuring the node pool rather than provisioning the underlying edge infrastructure.
To keep things focused, common node pool patterns are omitted, including:
- Node configuration (nodeConfig for CPU, memory, disk)
- Local disk encryption (localDiskEncryption with KMS keys)
- Labels for organization and filtering
- Machine selection filters beyond basic name matching
These omissions are intentional: the goal is to illustrate how the node pool resource is wired, not provide drop-in edge infrastructure 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 properties are immutable and cannot be changed after creation.us-central1-edge-customer-a.Labels & Metadata
labels field is non-authoritative and only manages labels present in your configuration. Use effectiveLabels to see all labels on the resource, including those set by other clients and services. The pulumiLabels field combines labels configured directly on the resource with default labels from the provider.Machine Selection
machineFilter property with AIP-160 filtering syntax, such as name=<name>. The filtering language is documented in AIP-160.Using a different cloud?
Explore containers guides for other cloud providers: