README.md
June 24, 2026 ยท View on GitHub
Description
This module simplifies the following functionality:
- Applying Kubernetes manifests to GKE clusters: It provides flexible options for specifying manifests, allowing you to either directly embed them as strings content or reference them from URLs, files, templates, or entire .yaml and .tftpl files in directories.
- Deploying commonly used infrastructure like Kueue,Jobset, NCCL gIB plugin or
asapd-litedaemonset.
Note: Kueue can work with a variety of frameworks out of the box, find them here
Explanation
- Manifest:
-
Raw String: Specify manifests directly within the module configuration using the
content: manifest_bodyformat. -
File/Template/Directory Reference: Set
sourceto the path to:- A single URL to a manifest file. Ex.:
https://github.com/.../myrepo/manifest.yaml.
Note: Applying from a URL has important limitations. Please review the Considerations & Callouts for Applying from URLs section below.
- A single local YAML manifest file (
.yamlor.yml). Ex.:./manifest.yaml. - A template file (
.tftpl) to generate a manifest. Ex.:./template.yaml.tftpl. You can pass the variables to format the template file intemplate_vars. - A directory containing multiple YAML or template files. Ex:
./manifests/or./manifests. The module correctly identifies directories even if the trailing slash is omitted. For security and stability, the module only processes files with.yaml,.yml, or.tftplextensions. Other files in the directory (likeREADME.mdetc. ) are automatically ignored.
- A single URL to a manifest file. Ex.:
-
Manifest Example
- id: existing-gke-cluster
source: modules/scheduler/pre-existing-gke-cluster
settings:
project_id: $(vars.project_id)
cluster_name: my-gke-cluster
region: us-central1
- id: kubectl-apply
source: modules/management/kubectl-apply
use: [existing-gke-cluster]
settings:
- content: |
apiVersion: v1
kind: Namespace
metadata:
name: my-namespace
- source: "https://github.com/kubernetes-sigs/jobset/releases/download/v0.6.0/manifests.yaml"
- source: $(ghpc_stage("manifests/configmap1.yaml"))
- source: $(ghpc_stage("manifests/configmap2.yaml.tftpl"))
template_vars: {name: "dev-config", public: "false"}
- source: $(ghpc_stage("manifests"))/
template_vars: {name: "dev-config", public: "false"}
Pre-build infrastructure Example
- id: workload_component_install
source: modules/management/kubectl-apply
use: [gke_cluster]
settings:
kueue:
install: true
config_path: $(ghpc_stage("manifests/user-provided-kueue-config.yaml"))
jobset:
install: true
The config_path field in kueue installation accepts a template file, too. You will need to provide variables for the template using config_template_vars field.
- id: workload_component_install
source: modules/management/kubectl-apply
use: [gke_cluster]
settings:
kueue:
install: true
config_path: $(ghpc_stage("manifests/user-provided-kueue-config.yaml.tftpl"))
config_template_vars: {name: "dev-config", public: "false"}
jobset:
install: true
TPU Flavor Quotas Override (Pathways active)
When Pathways is active, the TPU worker pods request both TPU and CPU/Memory resources. To prevent Kueue from blocking these pods, the default configuration uses high "unlimited" defaults (999999 and 999999T) for CPU and Memory quotas on the TPU flavor.
If you want to enforce strict capacity sharing on the TPU pool, you can override these defaults by specifying tpu_flavor_cpu_quota and tpu_flavor_memory_quota inside config_template_vars:
- id: workload_component_install
source: modules/management/kubectl-apply
use: [gke_cluster]
settings:
kueue:
install: true
config_template_vars:
tpu_flavor_cpu_quota: 1024
tpu_flavor_memory_quota: "4096G"
You can specify a particular kueue version that you would like to use using the version flag. By default, we recommend customers to use v0.17.1. You can find the list of supported kueue versions here.
- id: workload_component_install
source: modules/management/kubectl-apply
use: [gke_cluster]
settings:
kueue:
install: true
version: 0.17.1
config_path: $(ghpc_stage("manifests/user-provided-kueue-config.yaml.tftpl"))
config_template_vars: {name: "dev-config", public: "false"}
jobset:
install: true
You can also install the gib plugin by setting the gib input variable.
The path field accepts a template file. You will need to provide variables for the template using template_vars field and can also specify a particular gib version that you would like to use using the version flag. You can find the list of supported machine types for the gib plugin here.
- id: workload_component_install
source: modules/management/kubectl-apply
use: [gke_cluster]
settings:
gib:
install: true
path: $(ghpc_stage("manifests/daemonset-gib.yaml.tftpl"))
template_vars:
version: v1.1.0
accelerator_count: 2
You can install the asapd-lite daemonset for A4X-Max Bare Metal (gke-a4x-max-bm) by setting the asapd_lite input variable and providing the path to the installer manifest using the config_path field.
- id: workload_component_install
source: modules/management/kubectl-apply
use: [gke_cluster]
settings:
asapd_lite:
install: true
config_path: $(ghpc_stage("manifests/asapd-lite-installer.yaml"))
NOTE:
The
project_idandregionsettings would be inferred from the deployment variables of the same name, but they are included here for clarity.Terraform may apply resources in parallel, leading to potential dependency issues. If a resource's dependencies aren't ready, it will be applied again up to 15 times.
Callouts
Helm-based Manifest Application
1. Large Manifests and CRDs
Helm stores the entire release state (including the generated manifests) as a standard Kubernetes Secret in the release namespace. Before storing the state, Helm runs the YAML through GZIP compression and base64 encoding. This effectively raises the limit to ~1MB or more, allowing for the deployment of very large manifests and complex CRDs without requiring Server-Side Apply (SSA). This behaviour is guaranteed because the Terraform Helm Provider directly imports the official Helm Go SDK.
2. Helm-Release Suffixes
To make releases more identifiable, the module generates deterministic Helm release names based on the following precedence hierarchy:
- If you provide a
namefield in theapply_manifestslist object, it will be used directly. Explicit names must be unique across the list. - If applying from a local file or URL, it extracts the file basename and removes common extensions like
.yaml,.yml, and.tftpl(including combined extensions like.yaml.tftpl). - For raw content without a source or name, it falls back to using the module ID and a short hash:
${module_id}-raw-${hash}.The result is truncated to 30 characters, and a short 7-character hash of the manifest configuration is appended to ensure uniqueness. This ensures the total length does not exceed Helm's 53-character limit.
3. Re-deployment Conflicts
If a deployment fails, the atomic = true setting ensures that Helm automatically rolls back the release, preventing the cluster from being left in a "half-applied" state. If you encounter persistent conflicts during re-deployment due to immutable fields, you may need to manually delete the resource or the Helm release before re-applying.
Applying Manifests from URLs: Considerations & Callouts
While this module supports applying manifests directly from remote http:// or https:// URLs, this method introduces complexities not present when using local files. For production environments, we recommend sourcing manifests from local paths or a version-controlled Git repository. Moreover, this method will be deprecated soon. Hence we recommend to use other methods to source manifests.
If you choose to use the URL method, be aware of the following potential issues and their solutions.
1. Apply Order and Race Conditions
The module applies manifests from the apply_manifests list in parallel. This can create a race condition if one manifest depends on another. The most common example is applying a manifest with custom resources (like a ClusterQueue) at the same time as the manifest that defines it (the CustomResourceDefinition or CRD).
There is no guarantee that the CRD will be applied before the resource that uses it. This can lead to non-deterministic deployment failures with errors like:
Error: resource [kueue.x-k8s.io/v1beta2/ClusterQueue] isn't valid for cluster
Recommended Workaround: Two-Stage Apply
To ensure a reliable deployment, you must manually enforce the correct order of operations.
-
Initial Deployment: In your blueprint, include only the manifest(s) containing the
CustomResourceDefinition(CRD) resources in theapply_manifestslist.Example
settingsfor the first run:settings: apply_manifests: # This manifest contains the CRDs for Kueue - source: "https://raw.githubusercontent.com/GoogleCloudPlatform/cluster-toolkit/refs/heads/develop/modules/management/kubectl-apply/manifests/kueue-v0.11.4.yaml" -
Run the deployment (
gcluster deployorterraform apply). -
Second Deployment: Once the first apply is successful, add the manifests containing your custom resources (like
ClusterQueue,LocalQueue) to the list.Example
settingsfor the second run:settings: apply_manifests: # The CRD manifest is still present - source: "https://raw.githubusercontent.com/GoogleCloudPlatform/cluster-toolkit/refs/heads/develop/modules/management/kubectl-apply/manifests/kueue-v0.11.4.yaml" # Now, add your configuration manifest - source: "https://gist.githubusercontent.com/YourUser/..." # Your configuration URL -
Run the deployment command again. Since the CRDs are now guaranteed to exist in the cluster, this second apply will succeed reliably.
2. Terraform Template Files (.tftpl)
- Limitation: This module cannot render a template file (
.tftpl) when sourced from a remote URL. - Workaround: You must render the template into a pure YAML file locally, host that rendered file at a URL, and provide the URL of the rendered file in your blueprint.
License
Copyright 2026 Google LLC
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
Requirements
| Name | Version |
|---|---|
| terraform | >= 1.12.2 |
| >= 7.2 | |
| helm | ~> 2.17 |
| http | ~> 3.0 |
| kubernetes | >= 2.10.0 |
| time | ~> 0.13 |
Providers
| Name | Version |
|---|---|
| >= 7.2 | |
| http | ~> 3.0 |
| kubernetes | >= 2.10.0 |
| terraform | n/a |
| time | ~> 0.13 |
Modules
| Name | Source | Version |
|---|---|---|
| configure_kueue | ./helm_install | n/a |
| install_asapd_lite | ./helm_install | n/a |
| install_cert_manager | ./helm_install | n/a |
| install_gib | ./helm_install | n/a |
| install_gpu_operator | ./helm_install | n/a |
| install_jobset | ./helm_install | n/a |
| install_kueue | ./helm_install | n/a |
| install_nvidia_dra_driver | ./helm_install | n/a |
| install_slice_controller | ./helm_install | n/a |
| kubectl_apply_manifests | ./helm_install | n/a |
Resources
| Name | Type |
|---|---|
| kubernetes_annotations.sa_patch | resource |
| terraform_data.gib_validations | resource |
| terraform_data.initial_gib_version | resource |
| terraform_data.jobset_validations | resource |
| terraform_data.kueue_validations | resource |
| time_sleep.wait_for_webhook | resource |
| google_client_config.default | data source |
| google_container_cluster.gke_cluster | data source |
| http_http.manifest_from_url | data source |
Inputs
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| access_token | The access token for Kubernetes/Helm providers. | string | null | no |
| apply_manifests | A list of manifests to apply to the GKE cluster using helm_install. For more details on the underlying deployment mechanism, see the helm_install module. The enable input acts as a FF to apply a manifest or not. By default it is always set to true. | list(object({ | [] | no |
| asapd_lite | Install the asapd-lite daemonset for A4X-Max Bare Metal. | object({ | {} | no |
| cert_manager | Install cert-manager which manages TLS certificates for Kubernetes. | object({ | {} | no |
| cluster_ca_certificate | The base64 encoded CA certificate of the GKE cluster. Must be base64 encoded; the module internally decodes this value using base64decode(...) before passing it to the providers. | string | null | no |
| cluster_endpoint | The endpoint of the GKE cluster. | string | null | no |
| cluster_id | An identifier for the gke cluster resource with format projects/<project_id>/locations/ | string | n/a | yes |
| enable_pathways_for_tpus | Enable Pathways for TPUs. This is automatically wired from gke-cluster module if used. | bool | false | no |
| gib | Install the NCCL gIB plugin | object({ | { | no |
| gke_cluster_exists | A static flag that signals to downstream modules that a cluster has been created. | bool | false | no |
| gpu_operator | Install GPU Operator which uses the Kubernetes operator to automate the management of all NVIDIA software components needed to provision GPU. | object({ | {} | no |
| jobset | Install Jobset which manages a group of K8s jobs as a unit. | object({ | {} | no |
| kueue | Install and configure Kueue workload scheduler. A configuration yaml/template file can be provided with config_path to be applied right after kueue installation. If a template file provided, its variables can be set to config_template_vars. | object({ | {} | no |
| module_id | The ID of the module as defined in the blueprint. Injected by ghpc. | string | "kubectl-apply" | no |
| nvidia_dra_driver | Installs Nvidia DRA driver which supports Dynamic Resource Allocation for NVIDIA GPUs in Kubernetes | object({ | {} | no |
| project_id | The project ID that hosts the gke cluster. | string | n/a | yes |
| service_account_annotations | Optional map of service accounts and workload identity emails to patch natively via HCL. | map(object({ | {} | no |
| system_node_pool_id | The ID of the system node pool. Used to ensure the node pool remains active during Kueue uninstallation. | string | null | no |
| target_architecture | The target architecture for the GKE nodes and gIB plugin (e.g., 'x86_64' or 'arm64'). | string | "x86_64" | no |
Outputs
| Name | Description |
|---|---|
| k8s_prerequisites_ready | Ensures sequential ordering with other Helm chart modules to avoid race conditions or deployment conflicts. |