427 lines
22 KiB
Markdown
427 lines
22 KiB
Markdown
# GCE Managed Instance Group module
|
|
|
|
This module allows creating a managed instance group supporting one or more application versions via instance templates. Optionally, a health check and an autoscaler can be created, and the managed instance group can be configured to be stateful.
|
|
|
|
This module can be coupled with the [`compute-vm`](../compute-vm) module which can manage instance templates, and the [`net-lb-int`](../net-lb-int) module to assign the MIG to a backend wired to an Internal Load Balancer. The first use case is shown in the examples below.
|
|
|
|
Stateful disks can be created directly, as shown in the last example below.
|
|
|
|
<!-- BEGIN TOC -->
|
|
- [Examples](#examples)
|
|
- [Simple Example](#simple-example)
|
|
- [Multiple Versions](#multiple-versions)
|
|
- [Health Check and Autohealing Policies](#health-check-and-autohealing-policies)
|
|
- [Autoscaling](#autoscaling)
|
|
- [Update Policy](#update-policy)
|
|
- [Stateful MIGs - MIG Config](#stateful-migs-mig-config)
|
|
- [Stateful MIGs - Instance Config](#stateful-migs-instance-config)
|
|
- [Variables](#variables)
|
|
- [Outputs](#outputs)
|
|
<!-- END TOC -->
|
|
|
|
## Examples
|
|
|
|
### Simple Example
|
|
|
|
This example shows how to manage a simple MIG that leverages the `compute-vm` module to manage the underlying instance template. The following sub-examples will only show how to enable specific features of this module, and won't replicate the combined setup.
|
|
|
|
```hcl
|
|
module "cos-nginx" {
|
|
source = "./fabric/modules/cloud-config-container/nginx"
|
|
}
|
|
|
|
module "nginx-template" {
|
|
source = "./fabric/modules/compute-vm"
|
|
project_id = var.project_id
|
|
name = "nginx-template"
|
|
zone = "europe-west1-b"
|
|
tags = ["http-server", "ssh"]
|
|
network_interfaces = [{
|
|
network = var.vpc.self_link
|
|
subnetwork = var.subnet.self_link
|
|
nat = false
|
|
addresses = null
|
|
}]
|
|
boot_disk = {
|
|
initialize_params = {
|
|
image = "projects/cos-cloud/global/images/family/cos-stable"
|
|
}
|
|
}
|
|
create_template = true
|
|
metadata = {
|
|
user-data = module.cos-nginx.cloud_config
|
|
}
|
|
}
|
|
|
|
module "nginx-mig" {
|
|
source = "./fabric/modules/compute-mig"
|
|
project_id = "my-project"
|
|
location = "europe-west1-b"
|
|
name = "mig-test"
|
|
target_size = 2
|
|
instance_template = module.nginx-template.template.self_link
|
|
}
|
|
# tftest modules=2 resources=2 inventory=simple.yaml
|
|
```
|
|
|
|
### Multiple Versions
|
|
|
|
If multiple versions are desired, use more `compute-vm` instances for the additional templates used in each version (not shown here), and reference them like this:
|
|
|
|
```hcl
|
|
module "cos-nginx" {
|
|
source = "./fabric/modules/cloud-config-container/nginx"
|
|
}
|
|
|
|
module "nginx-template" {
|
|
source = "./fabric/modules/compute-vm"
|
|
project_id = var.project_id
|
|
name = "nginx-template"
|
|
zone = "europe-west1-b"
|
|
tags = ["http-server", "ssh"]
|
|
network_interfaces = [{
|
|
network = var.vpc.self_link
|
|
subnetwork = var.subnet.self_link
|
|
nat = false
|
|
addresses = null
|
|
}]
|
|
boot_disk = {
|
|
initialize_params = {
|
|
image = "projects/cos-cloud/global/images/family/cos-stable"
|
|
}
|
|
}
|
|
create_template = true
|
|
metadata = {
|
|
user-data = module.cos-nginx.cloud_config
|
|
}
|
|
}
|
|
|
|
module "nginx-mig" {
|
|
source = "./fabric/modules/compute-mig"
|
|
project_id = "my-project"
|
|
location = "europe-west1-b"
|
|
name = "mig-test"
|
|
target_size = 3
|
|
instance_template = module.nginx-template.template.self_link
|
|
versions = {
|
|
canary = {
|
|
instance_template = module.nginx-template.template.self_link
|
|
target_size = {
|
|
fixed = 1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
# tftest modules=2 resources=2
|
|
```
|
|
|
|
### Health Check and Autohealing Policies
|
|
|
|
Autohealing policies can use an externally defined health check, or have this module auto-create one:
|
|
|
|
```hcl
|
|
module "cos-nginx" {
|
|
source = "./fabric/modules/cloud-config-container/nginx"
|
|
}
|
|
|
|
module "nginx-template" {
|
|
source = "./fabric/modules/compute-vm"
|
|
project_id = var.project_id
|
|
name = "nginx-template"
|
|
zone = "europe-west1-b"
|
|
tags = ["http-server", "ssh"]
|
|
network_interfaces = [{
|
|
network = var.vpc.self_link,
|
|
subnetwork = var.subnet.self_link,
|
|
nat = false,
|
|
addresses = null
|
|
}]
|
|
boot_disk = {
|
|
initialize_params = {
|
|
image = "projects/cos-cloud/global/images/family/cos-stable"
|
|
}
|
|
}
|
|
create_template = true
|
|
metadata = {
|
|
user-data = module.cos-nginx.cloud_config
|
|
}
|
|
}
|
|
|
|
module "nginx-mig" {
|
|
source = "./fabric/modules/compute-mig"
|
|
project_id = "my-project"
|
|
location = "europe-west1-b"
|
|
name = "mig-test"
|
|
target_size = 3
|
|
instance_template = module.nginx-template.template.self_link
|
|
auto_healing_policies = {
|
|
initial_delay_sec = 30
|
|
}
|
|
health_check_config = {
|
|
enable_logging = true
|
|
http = {
|
|
port = 80
|
|
}
|
|
}
|
|
}
|
|
# tftest modules=2 resources=3 inventory=health-check.yaml
|
|
```
|
|
|
|
### Autoscaling
|
|
|
|
The module can create and manage an autoscaler associated with the MIG. When using autoscaling do not set the `target_size` variable or set it to `null`. Here we show a CPU utilization autoscaler, the other available modes are load balancing utilization and custom metric, like the underlying autoscaler resource.
|
|
|
|
```hcl
|
|
module "cos-nginx" {
|
|
source = "./fabric/modules/cloud-config-container/nginx"
|
|
}
|
|
|
|
module "nginx-template" {
|
|
source = "./fabric/modules/compute-vm"
|
|
project_id = var.project_id
|
|
name = "nginx-template"
|
|
zone = "europe-west1-b"
|
|
tags = ["http-server", "ssh"]
|
|
network_interfaces = [{
|
|
network = var.vpc.self_link
|
|
subnetwork = var.subnet.self_link
|
|
nat = false
|
|
addresses = null
|
|
}]
|
|
boot_disk = {
|
|
initialize_params = {
|
|
image = "projects/cos-cloud/global/images/family/cos-stable"
|
|
}
|
|
}
|
|
create_template = true
|
|
metadata = {
|
|
user-data = module.cos-nginx.cloud_config
|
|
}
|
|
}
|
|
|
|
module "nginx-mig" {
|
|
source = "./fabric/modules/compute-mig"
|
|
project_id = "my-project"
|
|
location = "europe-west1-b"
|
|
name = "mig-test"
|
|
target_size = 3
|
|
instance_template = module.nginx-template.template.self_link
|
|
autoscaler_config = {
|
|
max_replicas = 3
|
|
min_replicas = 1
|
|
cooldown_period = 30
|
|
scaling_signals = {
|
|
cpu_utilization = {
|
|
target = 0.65
|
|
}
|
|
}
|
|
}
|
|
}
|
|
# tftest modules=2 resources=3 inventory=autoscaling.yaml
|
|
```
|
|
|
|
### Update Policy
|
|
|
|
```hcl
|
|
module "cos-nginx" {
|
|
source = "./fabric/modules/cloud-config-container/nginx"
|
|
}
|
|
|
|
module "nginx-template" {
|
|
source = "./fabric/modules/compute-vm"
|
|
project_id = var.project_id
|
|
name = "nginx-template"
|
|
zone = "europe-west1-b"
|
|
tags = ["http-server", "ssh"]
|
|
network_interfaces = [{
|
|
network = var.vpc.self_link
|
|
subnetwork = var.subnet.self_link
|
|
nat = false
|
|
addresses = null
|
|
}]
|
|
boot_disk = {
|
|
initialize_params = {
|
|
image = "projects/cos-cloud/global/images/family/cos-stable"
|
|
}
|
|
}
|
|
create_template = true
|
|
metadata = {
|
|
user-data = module.cos-nginx.cloud_config
|
|
}
|
|
}
|
|
|
|
module "nginx-mig" {
|
|
source = "./fabric/modules/compute-mig"
|
|
project_id = "my-project"
|
|
location = "europe-west1-b"
|
|
name = "mig-test"
|
|
target_size = 3
|
|
instance_template = module.nginx-template.template.self_link
|
|
update_policy = {
|
|
minimal_action = "REPLACE"
|
|
type = "PROACTIVE"
|
|
min_ready_sec = 30
|
|
max_surge = {
|
|
fixed = 1
|
|
}
|
|
}
|
|
}
|
|
# tftest modules=2 resources=2
|
|
```
|
|
|
|
### Stateful MIGs - MIG Config
|
|
|
|
Stateful MIGs have some limitations documented [here](https://cloud.google.com/compute/docs/instance-groups/configuring-stateful-migs#limitations). Enforcement of these requirements is the responsibility of users of this module.
|
|
|
|
You can configure a disk defined in the instance template to be stateful for all instances in the MIG by configuring in the MIG's stateful policy, using the `stateful_disk_mig` variable. Alternatively, you can also configure stateful persistent disks individually per instance of the MIG by setting the `stateful_disk_instance` variable. A discussion on these scenarios can be found in the [docs](https://cloud.google.com/compute/docs/instance-groups/configuring-stateful-disks-in-migs).
|
|
|
|
An example using only the configuration at the MIG level can be seen below.
|
|
|
|
Note that when referencing the stateful disk, you use `device_name` and not `disk_name`. Specifying an existing disk in the template (and stateful config) only allows a single instance to be managed by the MIG, typically coupled with an autohealing policy (shown in the examples above).
|
|
|
|
```hcl
|
|
module "cos-nginx" {
|
|
source = "./fabric/modules/cloud-config-container/nginx"
|
|
}
|
|
|
|
module "nginx-template" {
|
|
source = "./fabric/modules/compute-vm"
|
|
project_id = "my-prj"
|
|
name = "nginx-template"
|
|
zone = "europe-west8-b"
|
|
tags = ["http-server", "ssh"]
|
|
instance_type = "e2-small"
|
|
network_interfaces = [{
|
|
network = var.vpc.self_link
|
|
subnetwork = var.subnet.self_link
|
|
}]
|
|
boot_disk = {
|
|
initialize_params = {
|
|
image = "projects/cos-cloud/global/images/family/cos-stable"
|
|
}
|
|
}
|
|
attached_disks = [{
|
|
source_type = "attach"
|
|
name = "data-1"
|
|
size = 10
|
|
source = "test-data-1"
|
|
}]
|
|
create_template = true
|
|
metadata = {
|
|
user-data = module.cos-nginx.cloud_config
|
|
}
|
|
}
|
|
|
|
module "nginx-mig" {
|
|
source = "./fabric/modules/compute-mig"
|
|
project_id = "my-prj"
|
|
location = "europe-west8-b"
|
|
name = "mig-test-2"
|
|
target_size = 1
|
|
instance_template = module.nginx-template.template.self_link
|
|
stateful_disks = {
|
|
data-1 = false
|
|
}
|
|
}
|
|
# tftest modules=2 resources=2
|
|
```
|
|
|
|
### Stateful MIGs - Instance Config
|
|
|
|
Here is an example defining the stateful config at the instance level. As in the example above, specifying an existing disk in the template (and stateful config) only allows a single instance to be managed by the MIG, typically coupled with an autohealing policy (shown in the examples above).
|
|
|
|
```hcl
|
|
module "cos-nginx" {
|
|
source = "./fabric/modules/cloud-config-container/nginx"
|
|
}
|
|
|
|
module "nginx-template" {
|
|
source = "./fabric/modules/compute-vm"
|
|
project_id = "my-prj"
|
|
name = "nginx-template"
|
|
zone = "europe-west8-b"
|
|
tags = ["http-server", "ssh"]
|
|
instance_type = "e2-small"
|
|
network_interfaces = [{
|
|
network = var.vpc.self_link
|
|
subnetwork = var.subnet.self_link
|
|
}]
|
|
boot_disk = {
|
|
initialize_params = {
|
|
image = "projects/cos-cloud/global/images/family/cos-stable"
|
|
}
|
|
}
|
|
attached_disks = [{
|
|
source_type = "attach"
|
|
name = "data-1"
|
|
size = 10
|
|
source = "test-data-1"
|
|
}]
|
|
create_template = true
|
|
metadata = {
|
|
user-data = module.cos-nginx.cloud_config
|
|
}
|
|
}
|
|
|
|
module "nginx-mig" {
|
|
source = "./fabric/modules/compute-mig"
|
|
project_id = "my-prj"
|
|
location = "europe-west8-b"
|
|
name = "mig-test"
|
|
instance_template = module.nginx-template.template.self_link
|
|
stateful_config = {
|
|
instance-1 = {
|
|
minimal_action = "NONE",
|
|
most_disruptive_allowed_action = "REPLACE"
|
|
preserved_state = {
|
|
disks = {
|
|
data-1 = {
|
|
source = "projects/my-prj/zones/europe-west8-b/disks/test-data-1"
|
|
}
|
|
}
|
|
metadata = {
|
|
foo = "bar"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
# tftest modules=2 resources=3 inventory=stateful.yaml
|
|
```
|
|
<!-- BEGIN TFDOC -->
|
|
|
|
## Variables
|
|
|
|
| name | description | type | required | default |
|
|
|---|---|:---:|:---:|:---:|
|
|
| [instance_template](variables.tf#L177) | Instance template for the default version. | <code>string</code> | ✓ | |
|
|
| [location](variables.tf#L182) | Compute zone or region. | <code>string</code> | ✓ | |
|
|
| [name](variables.tf#L187) | Managed group name. | <code>string</code> | ✓ | |
|
|
| [project_id](variables.tf#L198) | Project id. | <code>string</code> | ✓ | |
|
|
| [all_instances_config](variables.tf#L17) | Metadata and labels set to all instances in the group. | <code title="object({ labels = optional(map(string)) metadata = optional(map(string)) })">object({…})</code> | | <code>null</code> |
|
|
| [auto_healing_policies](variables.tf#L26) | Auto-healing policies for this group. | <code title="object({ health_check = optional(string) initial_delay_sec = number })">object({…})</code> | | <code>null</code> |
|
|
| [autoscaler_config](variables.tf#L35) | Optional autoscaler configuration. | <code title="object({ max_replicas = number min_replicas = number cooldown_period = optional(number) mode = optional(string) # OFF, ONLY_UP, ON scaling_control = optional(object({ down = optional(object({ max_replicas_fixed = optional(number) max_replicas_percent = optional(number) time_window_sec = optional(number) })) in = optional(object({ max_replicas_fixed = optional(number) max_replicas_percent = optional(number) time_window_sec = optional(number) })) }), {}) scaling_signals = optional(object({ cpu_utilization = optional(object({ target = number optimize_availability = optional(bool) })) load_balancing_utilization = optional(object({ target = number })) metrics = optional(list(object({ name = string type = string # GAUGE, DELTA_PER_SECOND, DELTA_PER_MINUTE target_value = number single_instance_assignment = optional(number) time_series_filter = optional(string) }))) schedules = optional(list(object({ duration_sec = number name = string min_required_replicas = number cron_schedule = string description = optional(bool) timezone = optional(string) disabled = optional(bool) }))) }), {}) })">object({…})</code> | | <code>null</code> |
|
|
| [default_version_name](variables.tf#L83) | Name used for the default version. | <code>string</code> | | <code>"default"</code> |
|
|
| [description](variables.tf#L89) | Optional description used for all resources managed by this module. | <code>string</code> | | <code>"Terraform managed."</code> |
|
|
| [distribution_policy](variables.tf#L95) | DIstribution policy for regional MIG. | <code title="object({ target_shape = optional(string) zones = optional(list(string)) })">object({…})</code> | | <code>null</code> |
|
|
| [health_check_config](variables.tf#L104) | Optional auto-created health check configuration, use the output self-link to set it in the auto healing policy. Refer to examples for usage. | <code title="object({ check_interval_sec = optional(number) description = optional(string, "Terraform managed.") enable_logging = optional(bool, false) healthy_threshold = optional(number) timeout_sec = optional(number) unhealthy_threshold = optional(number) grpc = optional(object({ port = optional(number) port_name = optional(string) port_specification = optional(string) # USE_FIXED_PORT USE_NAMED_PORT USE_SERVING_PORT service_name = optional(string) })) http = optional(object({ host = optional(string) port = optional(number) port_name = optional(string) port_specification = optional(string) # USE_FIXED_PORT USE_NAMED_PORT USE_SERVING_PORT proxy_header = optional(string) request_path = optional(string) response = optional(string) })) http2 = optional(object({ host = optional(string) port = optional(number) port_name = optional(string) port_specification = optional(string) # USE_FIXED_PORT USE_NAMED_PORT USE_SERVING_PORT proxy_header = optional(string) request_path = optional(string) response = optional(string) })) https = optional(object({ host = optional(string) port = optional(number) port_name = optional(string) port_specification = optional(string) # USE_FIXED_PORT USE_NAMED_PORT USE_SERVING_PORT proxy_header = optional(string) request_path = optional(string) response = optional(string) })) tcp = optional(object({ port = optional(number) port_name = optional(string) port_specification = optional(string) # USE_FIXED_PORT USE_NAMED_PORT USE_SERVING_PORT proxy_header = optional(string) request = optional(string) response = optional(string) })) ssl = optional(object({ port = optional(number) port_name = optional(string) port_specification = optional(string) # USE_FIXED_PORT USE_NAMED_PORT USE_SERVING_PORT proxy_header = optional(string) request = optional(string) response = optional(string) })) })">object({…})</code> | | <code>null</code> |
|
|
| [named_ports](variables.tf#L192) | Named ports. | <code>map(number)</code> | | <code>null</code> |
|
|
| [stateful_config](variables.tf#L203) | Stateful configuration for individual instances. | <code title="map(object({ minimal_action = optional(string) most_disruptive_action = optional(string) remove_state_on_destroy = optional(bool) preserved_state = optional(object({ disks = optional(map(object({ source = string delete_on_instance_deletion = optional(bool) read_only = optional(bool) }))) metadata = optional(map(string)) })) }))">map(object({…}))</code> | | <code>{}</code> |
|
|
| [stateful_disks](variables.tf#L222) | Stateful disk configuration applied at the MIG level to all instances, in device name => on permanent instance delete rule as boolean. | <code>map(bool)</code> | | <code>{}</code> |
|
|
| [target_pools](variables.tf#L229) | Optional list of URLs for target pools to which new instances in the group are added. | <code>list(string)</code> | | <code>[]</code> |
|
|
| [target_size](variables.tf#L235) | Group target size, leave null when using an autoscaler. | <code>number</code> | | <code>null</code> |
|
|
| [update_policy](variables.tf#L241) | Update policy. Minimal action and type are required. | <code title="object({ minimal_action = string type = string max_surge = optional(object({ fixed = optional(number) percent = optional(number) })) max_unavailable = optional(object({ fixed = optional(number) percent = optional(number) })) min_ready_sec = optional(number) most_disruptive_action = optional(string) regional_redistribution_type = optional(string) replacement_method = optional(string) })">object({…})</code> | | <code>null</code> |
|
|
| [versions](variables.tf#L262) | Additional application versions, target_size is optional. | <code title="map(object({ instance_template = string target_size = optional(object({ fixed = optional(number) percent = optional(number) })) }))">map(object({…}))</code> | | <code>{}</code> |
|
|
| [wait_for_instances](variables.tf#L275) | Wait for all instances to be created/updated before returning. | <code title="object({ enabled = bool status = optional(string) })">object({…})</code> | | <code>null</code> |
|
|
|
|
## Outputs
|
|
|
|
| name | description | sensitive |
|
|
|---|---|:---:|
|
|
| [autoscaler](outputs.tf#L17) | Auto-created autoscaler resource. | |
|
|
| [group_manager](outputs.tf#L26) | Instance group resource. | |
|
|
| [health_check](outputs.tf#L35) | Auto-created health-check resource. | |
|
|
| [id](outputs.tf#L44) | Fully qualified group manager id. | |
|
|
|
|
<!-- END TFDOC -->
|