Rename gke-serverless to gke and add test for fast gke stage

This commit is contained in:
Julio Castillo
2022-09-12 09:56:25 +02:00
parent d817bc5700
commit 72da12e377
14 changed files with 103 additions and 8 deletions

12
blueprints/gke/README.md Normal file
View File

@@ -0,0 +1,12 @@
# GKE and Serverless blueprints
The blueprints in this folder show implement **end-to-end scenarios** for GKE or Serveless topologies that show how to automate common configurations or leverage specific products.
They are meant to be used as minimal but complete starting points to create actual infrastructure, and as playgrounds to experiment with Google Cloud features.
## Blueprints
### Multitenant GKE fleet
<a href="./multitenant-fleet/" title="GKE multitenant fleet"><img src="./multitenant-fleet/diagram.png" align="left" width="280px"></a> This [blueprint](./multitenant-fleet/) allows simple centralized management of similar sets of GKE clusters and their nodepools in a single project, and optional fleet management via GKE Hub templated configurations.
<br clear="left">

View File

@@ -0,0 +1,359 @@
# GKE Multitenant Blueprint
This blueprint presents an opinionated architecture to handle multiple homogeneous GKE clusters. The general idea behind this blueprint is to deploy a single project hosting multiple clusters leveraging several useful GKE features.
The pattern used in this design is useful, for blueprint, in cases where multiple clusters host/support the same workloads, such as in the case of a multi-regional deployment. Furthermore, combined with Anthos Config Sync and proper RBAC, this architecture can be used to host multiple tenants (e.g. teams, applications) sharing the clusters.
This blueprint is used as part of the [FAST GKE stage](../../../fast/stages/03-gke-multitenant/) but it can also be used independently if desired.
<p align="center">
<img src="diagram.png" alt="GKE multitenant">
</p>
The overall architecture is based on the following design decisions:
- All clusters are assumed to be [private](https://cloud.google.com/kubernetes-engine/docs/how-to/private-clusters), therefore only [VPC-native clusters](https://cloud.google.com/kubernetes-engine/docs/concepts/alias-ips) are supported.
- Logging and monitoring configured to use Cloud Operations for system components and user workloads.
- [GKE metering](https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-usage-metering) enabled by default and stored in a bigquery dataset created within the project.
- Optional [GKE Fleet](https://cloud.google.com/kubernetes-engine/docs/fleets-overview) support with the possibility to enable any of the following features:
- [Fleet workload identity](https://cloud.google.com/anthos/fleet-management/docs/use-workload-identity)
- [Anthos Config Management](https://cloud.google.com/anthos-config-management/docs/overview)
- [Anthos Service Mesh](https://cloud.google.com/service-mesh/docs/overview)
- [Anthos Identity Service](https://cloud.google.com/anthos/identity/setup/fleet)
- [Multi-cluster services](https://cloud.google.com/kubernetes-engine/docs/concepts/multi-cluster-services)
- [Multi-cluster ingress](https://cloud.google.com/kubernetes-engine/docs/concepts/multi-cluster-ingress).
- Support for [Config Sync](https://cloud.google.com/anthos-config-management/docs/config-sync-overview), [Hierarchy Controller](https://cloud.google.com/anthos-config-management/docs/concepts/hierarchy-controller), and [Policy Controller](https://cloud.google.com/anthos-config-management/docs/concepts/policy-controller) when using Anthos Config Management.
- [Groups for GKE](https://cloud.google.com/kubernetes-engine/docs/how-to/google-groups-rbac) can be enabled to facilitate the creation of flexible RBAC policies referencing group principals.
- Support for [application layer secret encryption](https://cloud.google.com/kubernetes-engine/docs/how-to/encrypting-secrets).
- Support to customize peering configuration of the control plane VPC (e.g. to import/export routes to the peered network)
- Some features are enabled by default in all clusters:
- [Intranode visibility](https://cloud.google.com/kubernetes-engine/docs/how-to/intranode-visibility)
- [Dataplane v2](https://cloud.google.com/kubernetes-engine/docs/concepts/dataplane-v2)
- [Shielded GKE nodes](https://cloud.google.com/kubernetes-engine/docs/how-to/shielded-gke-nodes)
- [Workload identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity)
- [Node local DNS cache](https://cloud.google.com/kubernetes-engine/docs/how-to/nodelocal-dns-cache)
- [Use of the GCE persistent disk CSI driver](https://cloud.google.com/kubernetes-engine/docs/how-to/persistent-volumes/gce-pd-csi-driver)
- Node [auto-upgrade](https://cloud.google.com/kubernetes-engine/docs/how-to/node-auto-upgrades) and [auto-repair](https://cloud.google.com/kubernetes-engine/docs/how-to/node-auto-repair) for all node pools
<!--
- [GKE subsetting for L4 internal load balancers](https://cloud.google.com/kubernetes-engine/docs/concepts/service-load-balancer#subsetting) enabled by default in all clusters
-->
## Basic usage
The following example shows how to deploy a single cluster and a single node pool
```hcl
module "gke" {
source = "./fabric/blueprints/gke-serverless/multitenant-fleet/"
project_id = var.project_id
billing_account_id = var.billing_account_id
folder_id = var.folder_id
prefix = "myprefix"
vpc_config = {
host_project_id = "my-host-project-id"
vpc_self_link = "projects/my-host-project-id/global/networks/my-network"
}
authenticator_security_group = "gke-rbac-base@example.com"
group_iam = {
"gke-admin@example.com" = [
"roles/container.admin"
]
}
iam = {
"roles/container.clusterAdmin" = [
"cicd@my-cicd-project.iam.gserviceaccount.com"
]
}
clusters = {
mycluster = {
cluster_autoscaling = null
description = "My cluster"
dns_domain = null
location = "europe-west1"
labels = {}
net = {
master_range = "172.17.16.0/28"
pods = "pods"
services = "services"
subnet = "projects/my-host-project-id/regions/europe-west1/subnetworks/mycluster-subnet"
}
overrides = null
}
}
nodepools = {
mycluster = {
mynodepool = {
initial_node_count = 1
node_count = 1
node_type = "n2-standard-4"
overrides = null
spot = false
}
}
}
}
# tftest modules=1 resources=0
```
## Creating Multiple Clusters
The following example shows how to deploy two clusters with different configurations.
The first cluster `cluster-euw1` defines the mandatory configuration parameters (description, location, network setup) and inherits the some defaults from the `cluster_defaults` and `nodepool_deaults` variables. These two variables are used whenever the `override` key of the `clusters` and `nodepools` variables are set to `null`.
On the other hand, the second cluster (`cluster-euw3`) defines its own configuration by providing a value to the `overrides` key.
```hcl
module "gke" {
source = "./fabric/blueprints/gke-serverless/multitenant-fleet/"
project_id = var.project_id
billing_account_id = var.billing_account_id
folder_id = var.folder_id
prefix = "myprefix"
vpc_config = {
host_project_id = "my-host-project-id"
vpc_self_link = "projects/my-host-project-id/global/networks/my-network"
}
clusters = {
cluster-euw1 = {
cluster_autoscaling = null
description = "Cluster for europ-west1"
dns_domain = null
location = "europe-west1"
labels = {}
net = {
master_range = "172.17.16.0/28"
pods = "pods"
services = "services"
subnet = "projects/my-host-project-id/regions/europe-west1/subnetworks/euw1-subnet"
}
overrides = null
}
cluster-euw3 = {
cluster_autoscaling = null
description = "Cluster for europe-west3"
dns_domain = null
location = "europe-west3"
labels = {}
net = {
master_range = "172.17.17.0/28"
pods = "pods"
services = "services"
subnet = "projects/my-host-project-id/regions/europe-west3/subnetworks/euw3-subnet"
}
overrides = {
cloudrun_config = false
database_encryption_key = null
gcp_filestore_csi_driver_config = true
master_authorized_ranges = {
rfc1918_1 = "10.0.0.0/8"
}
max_pods_per_node = 64
pod_security_policy = true
release_channel = "STABLE"
vertical_pod_autoscaling = false
}
}
}
nodepools = {
cluster-euw1 = {
pool-euw1 = {
initial_node_count = 1
node_count = 1
node_type = "n2-standard-4"
overrides = null
spot = false
}
}
cluster-euw3 = {
pool-euw3 = {
initial_node_count = 1
node_count = 1
node_type = "n2-standard-4"
overrides = {
image_type = "UBUNTU_CONTAINERD"
max_pods_per_node = 64
node_locations = []
node_tags = []
node_taints = []
}
spot = true
}
}
}
}
# tftest modules=1 resources=0
```
## Multiple clusters with GKE Fleet
This example deploys two clusters and configures several GKE Fleet features:
- Enables [multi-cluster ingress](https://cloud.google.com/kubernetes-engine/docs/concepts/multi-cluster-ingress) and sets the configuration cluster to be `cluster-eu1`.
- Enables [Multi-cluster services](https://cloud.google.com/kubernetes-engine/docs/concepts/multi-cluster-services) and assigns the [required roles](https://cloud.google.com/kubernetes-engine/docs/how-to/multi-cluster-services#authenticating) to its service accounts.
- A `default` Config Management template is created with binary authorization, config sync enabled with a git repository, hierarchy controller, and policy controller.
- The two clusters are configured to use the `default` Config Management template.
```hcl
module "gke" {
source = "./fabric/blueprints/gke-serverless/multitenant-fleet/"
project_id = var.project_id
billing_account_id = var.billing_account_id
folder_id = var.folder_id
prefix = "myprefix"
vpc_config = {
host_project_id = "my-host-project-id"
vpc_self_link = "projects/my-host-project-id/global/networks/my-network"
}
clusters = {
cluster-euw1 = {
cluster_autoscaling = null
description = "Cluster for europe-west1"
dns_domain = null
location = "europe-west1"
labels = {}
net = {
master_range = "172.17.16.0/28"
pods = "pods"
services = "services"
subnet = "projects/my-host-project-id/regions/europe-west1/subnetworks/euw1-subnet"
}
overrides = null
}
cluster-euw3 = {
cluster_autoscaling = null
description = "Cluster for europe-west3"
dns_domain = null
location = "europe-west3"
labels = {}
net = {
master_range = "172.17.17.0/28"
pods = "pods"
services = "services"
subnet = "projects/my-host-project-id/regions/europe-west3/subnetworks/euw3-subnet"
}
overrides = null
}
}
nodepools = {
cluster-euw1 = {
pool-euw1 = {
initial_node_count = 1
node_count = 1
node_type = "n2-standard-4"
overrides = null
spot = false
}
}
cluster-euw3 = {
pool-euw3 = {
initial_node_count = 1
node_count = 1
node_type = "n2-standard-4"
overrides = null
spot = true
}
}
}
fleet_features = {
appdevexperience = false
configmanagement = true
identityservice = true
multiclusteringress = "cluster-euw1"
multiclusterservicediscovery = true
servicemesh = true
}
fleet_workload_identity = true
fleet_configmanagement_templates = {
default = {
binauthz = true
config_sync = {
git = {
gcp_service_account_email = null
https_proxy = null
policy_dir = "configsync"
secret_type = "none"
source_format = "hierarchy"
sync_branch = "main"
sync_repo = "https://github.com/myorg/myrepo"
sync_rev = null
sync_wait_secs = null
}
prevent_drift = true
source_format = "hierarchy"
}
hierarchy_controller = {
enable_hierarchical_resource_quota = true
enable_pod_tree_labels = true
}
policy_controller = {
audit_interval_seconds = 30
exemptable_namespaces = ["kube-system"]
log_denies_enabled = true
referential_rules_enabled = true
template_library_installed = true
}
version = "1.10.2"
}
}
fleet_configmanagement_clusters = {
default = ["cluster-euw1", "cluster-euw3"]
}
}
# tftest modules=1 resources=0
```
<!-- TFDOC OPTS files:1 show_extra:1 -->
<!-- BEGIN TFDOC -->
## Files
| name | description | modules |
|---|---|---|
| [gke-clusters.tf](./gke-clusters.tf) | None | <code>gke-cluster</code> |
| [gke-hub.tf](./gke-hub.tf) | None | <code>gke-hub</code> |
| [gke-nodepools.tf](./gke-nodepools.tf) | None | <code>gke-nodepool</code> |
| [main.tf](./main.tf) | Module-level locals and resources. | <code>bigquery-dataset</code> · <code>project</code> |
| [outputs.tf](./outputs.tf) | Output variables. | |
| [variables.tf](./variables.tf) | Module variables. | |
## Variables
| name | description | type | required | default | producer |
|---|---|:---:|:---:|:---:|:---:|
| [billing_account_id](variables.tf#L23) | Billing account id. | <code>string</code> | ✓ | | |
| [clusters](variables.tf#L57) | | <code title="map&#40;object&#40;&#123;&#10; cluster_autoscaling &#61; object&#40;&#123;&#10; cpu_min &#61; number&#10; cpu_max &#61; number&#10; memory_min &#61; number&#10; memory_max &#61; number&#10; &#125;&#41;&#10; description &#61; string&#10; dns_domain &#61; string&#10; labels &#61; map&#40;string&#41;&#10; location &#61; string&#10; net &#61; object&#40;&#123;&#10; master_range &#61; string&#10; pods &#61; string&#10; services &#61; string&#10; subnet &#61; string&#10; &#125;&#41;&#10; overrides &#61; object&#40;&#123;&#10; cloudrun_config &#61; bool&#10; database_encryption_key &#61; string&#10; master_authorized_ranges &#61; map&#40;string&#41;&#10; max_pods_per_node &#61; number&#10; pod_security_policy &#61; bool&#10; release_channel &#61; string&#10; vertical_pod_autoscaling &#61; bool&#10; gcp_filestore_csi_driver_config &#61; bool&#10; &#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | ✓ | | |
| [folder_id](variables.tf#L158) | Folder used for the GKE project in folders/nnnnnnnnnnn format. | <code>string</code> | ✓ | | |
| [nodepools](variables.tf#L201) | | <code title="map&#40;map&#40;object&#40;&#123;&#10; node_count &#61; number&#10; node_type &#61; string&#10; initial_node_count &#61; number&#10; overrides &#61; object&#40;&#123;&#10; image_type &#61; string&#10; max_pods_per_node &#61; number&#10; node_locations &#61; list&#40;string&#41;&#10; node_tags &#61; list&#40;string&#41;&#10; node_taints &#61; list&#40;string&#41;&#10; &#125;&#41;&#10; spot &#61; bool&#10;&#125;&#41;&#41;&#41;">map&#40;map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;&#41;</code> | ✓ | | |
| [prefix](variables.tf#L231) | Prefix used for resources that need unique names. | <code>string</code> | ✓ | | |
| [project_id](variables.tf#L236) | ID of the project that will contain all the clusters. | <code>string</code> | ✓ | | |
| [vpc_config](variables.tf#L248) | Shared VPC project and VPC details. | <code title="object&#40;&#123;&#10; host_project_id &#61; string&#10; vpc_self_link &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | |
| [authenticator_security_group](variables.tf#L17) | Optional group used for Groups for GKE. | <code>string</code> | | <code>null</code> | |
| [cluster_defaults](variables.tf#L28) | Default values for optional cluster configurations. | <code title="object&#40;&#123;&#10; cloudrun_config &#61; bool&#10; database_encryption_key &#61; string&#10; master_authorized_ranges &#61; map&#40;string&#41;&#10; max_pods_per_node &#61; number&#10; pod_security_policy &#61; bool&#10; release_channel &#61; string&#10; vertical_pod_autoscaling &#61; bool&#10; gcp_filestore_csi_driver_config &#61; bool&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; cloudrun_config &#61; false&#10; database_encryption_key &#61; null&#10; master_authorized_ranges &#61; &#123;&#10; rfc1918_1 &#61; &#34;10.0.0.0&#47;8&#34;&#10; rfc1918_2 &#61; &#34;172.16.0.0&#47;12&#34;&#10; rfc1918_3 &#61; &#34;192.168.0.0&#47;16&#34;&#10; &#125;&#10; max_pods_per_node &#61; 110&#10; pod_security_policy &#61; false&#10; release_channel &#61; &#34;STABLE&#34;&#10; vertical_pod_autoscaling &#61; false&#10; gcp_filestore_csi_driver_config &#61; false&#10;&#125;">&#123;&#8230;&#125;</code> | |
| [dns_domain](variables.tf#L90) | Domain name used for clusters, prefixed by each cluster name. Leave null to disable Cloud DNS for GKE. | <code>string</code> | | <code>null</code> | |
| [fleet_configmanagement_clusters](variables.tf#L96) | Config management features enabled on specific sets of member clusters, in config name => [cluster name] format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | |
| [fleet_configmanagement_templates](variables.tf#L103) | Sets of config management configurations that can be applied to member clusters, in config name => {options} format. | <code title="map&#40;object&#40;&#123;&#10; binauthz &#61; bool&#10; config_sync &#61; object&#40;&#123;&#10; git &#61; object&#40;&#123;&#10; gcp_service_account_email &#61; string&#10; https_proxy &#61; string&#10; policy_dir &#61; string&#10; secret_type &#61; string&#10; sync_branch &#61; string&#10; sync_repo &#61; string&#10; sync_rev &#61; string&#10; sync_wait_secs &#61; number&#10; &#125;&#41;&#10; prevent_drift &#61; string&#10; source_format &#61; string&#10; &#125;&#41;&#10; hierarchy_controller &#61; object&#40;&#123;&#10; enable_hierarchical_resource_quota &#61; bool&#10; enable_pod_tree_labels &#61; bool&#10; &#125;&#41;&#10; policy_controller &#61; object&#40;&#123;&#10; audit_interval_seconds &#61; number&#10; exemptable_namespaces &#61; list&#40;string&#41;&#10; log_denies_enabled &#61; bool&#10; referential_rules_enabled &#61; bool&#10; template_library_installed &#61; bool&#10; &#125;&#41;&#10; version &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | |
| [fleet_features](variables.tf#L138) | Enable and configue fleet features. Set to null to disable GKE Hub if fleet workload identity is not used. | <code title="object&#40;&#123;&#10; appdevexperience &#61; bool&#10; configmanagement &#61; bool&#10; identityservice &#61; bool&#10; multiclusteringress &#61; string&#10; multiclusterservicediscovery &#61; bool&#10; servicemesh &#61; bool&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> | |
| [fleet_workload_identity](variables.tf#L151) | Use Fleet Workload Identity for clusters. Enables GKE Hub if set to true. | <code>bool</code> | | <code>false</code> | |
| [group_iam](variables.tf#L163) | Project-level IAM bindings for groups. Use group emails as keys, list of roles as values. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | |
| [iam](variables.tf#L170) | Project-level authoritative IAM bindings for users and service accounts in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | |
| [labels](variables.tf#L177) | Project-level labels. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> | |
| [nodepool_defaults](variables.tf#L183) | | <code title="object&#40;&#123;&#10; image_type &#61; string&#10; max_pods_per_node &#61; number&#10; node_locations &#61; list&#40;string&#41;&#10; node_tags &#61; list&#40;string&#41;&#10; node_taints &#61; list&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; image_type &#61; &#34;COS_CONTAINERD&#34;&#10; max_pods_per_node &#61; 110&#10; node_locations &#61; null&#10; node_tags &#61; null&#10; node_taints &#61; &#91;&#93;&#10;&#125;">&#123;&#8230;&#125;</code> | |
| [peering_config](variables.tf#L218) | Configure peering with the control plane VPC. Requires compute.networks.updatePeering. Set to null if you don't want to update the default peering configuration. | <code title="object&#40;&#123;&#10; export_routes &#61; bool&#10; import_routes &#61; bool&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; export_routes &#61; true&#10; &#47;&#47; TODO&#40;jccb&#41; is there any situation where the control plane VPC would export any routes&#63;&#10; import_routes &#61; false&#10;&#125;">&#123;&#8230;&#125;</code> | |
| [project_services](variables.tf#L241) | Additional project services to enable. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> | |
## Outputs
| name | description | sensitive | consumers |
|---|---|:---:|---|
| [cluster_ids](outputs.tf#L22) | Cluster ids. | | |
| [clusters](outputs.tf#L17) | Cluster resources. | | |
| [project_id](outputs.tf#L29) | GKE project id. | | |
<!-- END TFDOC -->

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -0,0 +1,116 @@
/**
* Copyright 2022 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.
*/
locals {
clusters = {
for name, config in var.clusters :
name => merge(config, {
overrides = coalesce(config.overrides, var.cluster_defaults)
})
}
}
module "gke-cluster" {
source = "../../../modules/gke-cluster"
for_each = local.clusters
name = each.key
project_id = module.gke-project-0.project_id
description = each.value.description
location = each.value.location
network = var.vpc_config.vpc_self_link
subnetwork = each.value.net.subnet
secondary_range_pods = each.value.net.pods
secondary_range_services = each.value.net.services
labels = each.value.labels
addons = {
cloudrun_config = each.value.overrides.cloudrun_config
dns_cache_config = true
http_load_balancing = true
gce_persistent_disk_csi_driver_config = true
horizontal_pod_autoscaling = true
config_connector_config = true
kalm_config = false
gcp_filestore_csi_driver_config = each.value.overrides.gcp_filestore_csi_driver_config
gke_backup_agent_config = false
# enable only if enable_dataplane_v2 is changed to false below
network_policy_config = false
istio_config = {
enabled = false
tls = false
}
}
# change these here for all clusters if absolutely needed
authenticator_security_group = var.authenticator_security_group
enable_dataplane_v2 = true
enable_l4_ilb_subsetting = false
enable_intranode_visibility = true
enable_shielded_nodes = true
workload_identity = true
private_cluster_config = {
enable_private_nodes = true
enable_private_endpoint = false
master_ipv4_cidr_block = each.value.net.master_range
master_global_access = true
}
dns_config = each.value.dns_domain == null ? null : {
cluster_dns = "CLOUD_DNS"
cluster_dns_scope = "VPC_SCOPE"
cluster_dns_domain = "${each.key}.${var.dns_domain}"
}
logging_config = ["SYSTEM_COMPONENTS", "WORKLOADS"]
monitoring_config = ["SYSTEM_COMPONENTS", "WORKLOADS"]
peering_config = var.peering_config == null ? null : {
export_routes = var.peering_config.export_routes
import_routes = var.peering_config.import_routes
project_id = var.vpc_config.host_project_id
}
resource_usage_export_config = {
enabled = true
dataset = module.gke-dataset-resource-usage.dataset_id
}
# TODO: the attributes below are "primed" from project-level defaults
# in locals, merge defaults with cluster-level stuff
# TODO(jccb): change fabric module
database_encryption = (
each.value.overrides.database_encryption_key == null
? {
enabled = false
state = null
key_name = null
}
: {
enabled = true
state = "ENCRYPTED"
key_name = each.value.overrides.database_encryption_key
}
)
default_max_pods_per_node = each.value.overrides.max_pods_per_node
master_authorized_ranges = each.value.overrides.master_authorized_ranges
pod_security_policy = each.value.overrides.pod_security_policy
release_channel = each.value.overrides.release_channel
vertical_pod_autoscaling = each.value.overrides.vertical_pod_autoscaling
# dynamic "cluster_autoscaling" {
# for_each = each.value.cluster_autoscaling == null ? {} : { 1 = 1 }
# content {
# enabled = true
# cpu_min = each.value.cluster_autoscaling.cpu_min
# cpu_max = each.value.cluster_autoscaling.cpu_max
# memory_min = each.value.cluster_autoscaling.memory_min
# memory_max = each.value.cluster_autoscaling.memory_max
# }
# }
}

View File

@@ -0,0 +1,44 @@
/**
* Copyright 2022 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.
*/
locals {
fleet_enabled = (
var.fleet_features != null || var.fleet_workload_identity
)
fleet_mcs_enabled = (
try(var.fleet_features.multiclusterservicediscovery, false) == true
)
}
module "gke-hub" {
source = "../../../modules/gke-hub"
count = local.fleet_enabled ? 1 : 0
project_id = module.gke-project-0.project_id
clusters = {
for cluster_id in keys(var.clusters) :
cluster_id => module.gke-cluster[cluster_id].id
}
features = var.fleet_features
configmanagement_templates = var.fleet_configmanagement_templates
configmanagement_clusters = var.fleet_configmanagement_clusters
workload_identity_clusters = (
var.fleet_workload_identity ? keys(var.clusters) : []
)
depends_on = [
module.gke-nodepool
]
}

View File

@@ -0,0 +1,66 @@
/**
* Copyright 2022 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.
*/
locals {
nodepools = merge([
for cluster, nodepools in var.nodepools : {
for nodepool, config in nodepools :
"${cluster}/${nodepool}" => merge(config, {
name = nodepool
cluster = cluster
overrides = coalesce(config.overrides, var.nodepool_defaults)
})
}
]...)
}
module "gke-nodepool" {
source = "../../../modules/gke-nodepool"
for_each = local.nodepools
name = each.value.name
project_id = module.gke-project-0.project_id
cluster_name = module.gke-cluster[each.value.cluster].name
location = module.gke-cluster[each.value.cluster].location
initial_node_count = each.value.initial_node_count
node_machine_type = each.value.node_type
node_spot = each.value.spot
node_count = each.value.node_count
# node_count = (
# each.value.autoscaling_config == null ? each.value.node_count : null
# )
# dynamic "autoscaling_config" {
# for_each = each.value.autoscaling_config == null ? {} : { 1 = 1 }
# content {
# min_node_count = each.value.autoscaling_config.min_node_count
# max_node_count = each.value.autoscaling_config.max_node_count
# }
# }
# overrides
node_locations = each.value.overrides.node_locations
max_pods_per_node = each.value.overrides.max_pods_per_node
node_image_type = each.value.overrides.image_type
node_tags = each.value.overrides.node_tags
node_taints = each.value.overrides.node_taints
management_config = {
auto_repair = true
auto_upgrade = true
}
node_service_account_create = true
}

View File

@@ -0,0 +1,82 @@
/**
* Copyright 2022 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.
*/
module "gke-project-0" {
source = "../../../modules/project"
billing_account = var.billing_account_id
name = var.project_id
parent = var.folder_id
prefix = var.prefix
group_iam = var.group_iam
labels = var.labels
iam = merge(var.iam, {
"roles/gkehub.serviceAgent" = [
"serviceAccount:${module.gke-project-0.service_accounts.robots.fleet}"
] }
)
services = concat(
[
"anthos.googleapis.com",
"anthosconfigmanagement.googleapis.com",
"cloudresourcemanager.googleapis.com",
"container.googleapis.com",
"dns.googleapis.com",
"gkeconnect.googleapis.com",
"gkehub.googleapis.com",
"iam.googleapis.com",
"multiclusteringress.googleapis.com",
"multiclusterservicediscovery.googleapis.com",
"stackdriver.googleapis.com",
"trafficdirector.googleapis.com"
],
var.project_services
)
shared_vpc_service_config = {
attach = true
host_project = var.vpc_config.host_project_id
service_identity_iam = merge({
"roles/compute.networkUser" = [
"cloudservices", "container-engine"
]
"roles/container.hostServiceAgentUser" = [
"container-engine"
]
},
!local.fleet_mcs_enabled ? {} : {
"roles/multiclusterservicediscovery.serviceAgent" = ["gke-mcs"]
"roles/compute.networkViewer" = ["gke-mcs-importer"]
})
}
# specify project-level org policies here if you need them
# policy_boolean = {
# "constraints/compute.disableGuestAttributesAccess" = true
# }
# policy_list = {
# "constraints/compute.trustedImageProjects" = {
# inherit_from_parent = null
# suggested_value = null
# status = true
# values = ["projects/fl01-prod-iac-core-0"]
# }
# }
}
module "gke-dataset-resource-usage" {
source = "../../../modules/bigquery-dataset"
project_id = module.gke-project-0.project_id
id = "gke_resource_usage"
friendly_name = "GKE resource usage."
}

View File

@@ -0,0 +1,32 @@
# Copyright 2022 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
#
# https://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.
# tfdoc:file:description Output variables.
output "clusters" {
description = "Cluster resources."
value = module.gke-cluster
}
output "cluster_ids" {
description = "Cluster ids."
value = {
for k, v in module.gke-cluster : k => v.id
}
}
output "project_id" {
description = "GKE project id."
value = module.gke-project-0.project_id
}

View File

@@ -0,0 +1,254 @@
/**
* Copyright 2022 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.
*/
variable "authenticator_security_group" {
description = "Optional group used for Groups for GKE."
type = string
default = null
}
variable "billing_account_id" {
description = "Billing account id."
type = string
}
variable "cluster_defaults" {
description = "Default values for optional cluster configurations."
type = object({
cloudrun_config = bool
database_encryption_key = string
master_authorized_ranges = map(string)
max_pods_per_node = number
pod_security_policy = bool
release_channel = string
vertical_pod_autoscaling = bool
gcp_filestore_csi_driver_config = bool
})
default = {
# TODO: review defaults
cloudrun_config = false
database_encryption_key = null
master_authorized_ranges = {
rfc1918_1 = "10.0.0.0/8"
rfc1918_2 = "172.16.0.0/12"
rfc1918_3 = "192.168.0.0/16"
}
max_pods_per_node = 110
pod_security_policy = false
release_channel = "STABLE"
vertical_pod_autoscaling = false
gcp_filestore_csi_driver_config = false
}
}
variable "clusters" {
description = ""
type = map(object({
cluster_autoscaling = object({
cpu_min = number
cpu_max = number
memory_min = number
memory_max = number
})
description = string
dns_domain = string
labels = map(string)
location = string
net = object({
master_range = string
pods = string
services = string
subnet = string
})
overrides = object({
cloudrun_config = bool
database_encryption_key = string
# binary_authorization = bool
master_authorized_ranges = map(string)
max_pods_per_node = number
pod_security_policy = bool
release_channel = string
vertical_pod_autoscaling = bool
gcp_filestore_csi_driver_config = bool
})
}))
}
variable "dns_domain" {
description = "Domain name used for clusters, prefixed by each cluster name. Leave null to disable Cloud DNS for GKE."
type = string
default = null
}
variable "fleet_configmanagement_clusters" {
description = "Config management features enabled on specific sets of member clusters, in config name => [cluster name] format."
type = map(list(string))
default = {}
nullable = false
}
variable "fleet_configmanagement_templates" {
description = "Sets of config management configurations that can be applied to member clusters, in config name => {options} format."
type = map(object({
binauthz = bool
config_sync = object({
git = object({
gcp_service_account_email = string
https_proxy = string
policy_dir = string
secret_type = string
sync_branch = string
sync_repo = string
sync_rev = string
sync_wait_secs = number
})
prevent_drift = string
source_format = string
})
hierarchy_controller = object({
enable_hierarchical_resource_quota = bool
enable_pod_tree_labels = bool
})
policy_controller = object({
audit_interval_seconds = number
exemptable_namespaces = list(string)
log_denies_enabled = bool
referential_rules_enabled = bool
template_library_installed = bool
})
version = string
}))
default = {}
nullable = false
}
variable "fleet_features" {
description = "Enable and configue fleet features. Set to null to disable GKE Hub if fleet workload identity is not used."
type = object({
appdevexperience = bool
configmanagement = bool
identityservice = bool
multiclusteringress = string
multiclusterservicediscovery = bool
servicemesh = bool
})
default = null
}
variable "fleet_workload_identity" {
description = "Use Fleet Workload Identity for clusters. Enables GKE Hub if set to true."
type = bool
default = false
nullable = false
}
variable "folder_id" {
description = "Folder used for the GKE project in folders/nnnnnnnnnnn format."
type = string
}
variable "group_iam" {
description = "Project-level IAM bindings for groups. Use group emails as keys, list of roles as values."
type = map(list(string))
default = {}
nullable = false
}
variable "iam" {
description = "Project-level authoritative IAM bindings for users and service accounts in {ROLE => [MEMBERS]} format."
type = map(list(string))
default = {}
nullable = false
}
variable "labels" {
description = "Project-level labels."
type = map(string)
default = {}
}
variable "nodepool_defaults" {
description = ""
type = object({
image_type = string
max_pods_per_node = number
node_locations = list(string)
node_tags = list(string)
node_taints = list(string)
})
default = {
image_type = "COS_CONTAINERD"
max_pods_per_node = 110
node_locations = null
node_tags = null
node_taints = []
}
}
variable "nodepools" {
description = ""
type = map(map(object({
node_count = number
node_type = string
initial_node_count = number
overrides = object({
image_type = string
max_pods_per_node = number
node_locations = list(string)
node_tags = list(string)
node_taints = list(string)
})
spot = bool
})))
}
variable "peering_config" {
description = "Configure peering with the control plane VPC. Requires compute.networks.updatePeering. Set to null if you don't want to update the default peering configuration."
type = object({
export_routes = bool
import_routes = bool
})
default = {
export_routes = true
// TODO(jccb) is there any situation where the control plane VPC would export any routes?
import_routes = false
}
}
variable "prefix" {
description = "Prefix used for resources that need unique names."
type = string
}
variable "project_id" {
description = "ID of the project that will contain all the clusters."
type = string
}
variable "project_services" {
description = "Additional project services to enable."
type = list(string)
default = []
nullable = false
}
variable "vpc_config" {
description = "Shared VPC project and VPC details."
type = object({
host_project_id = string
vpc_self_link = string
})
}