diff --git a/modules/compute-vm-cos-coredns/README.md b/modules/compute-vm-cos-coredns/README.md deleted file mode 100644 index 430bcf4733..0000000000 --- a/modules/compute-vm-cos-coredns/README.md +++ /dev/null @@ -1,79 +0,0 @@ -# Container Optimized OS CoreDNS module - -This module allows creating instances (or an instance template) runnning a containerized DNS server using CoreDNS. A service account will be created if none is set. - -## Example - -```hcl -module "onprem-dns" { - source = "./modules/compute-vm-cos-coredns" - project_id = var.project_id - region = var.region - zone = var.zone - name = "coredns" - network_interfaces = [{ - network = var.vpc_self_link - subnetwork = var.subnet_self_link - nat = false, - addresses = null - }] - coredns_corefile = < -## Variables - -| name | description | type | required | default | -|---|---|:---: |:---:|:---:| -| name | Instances base name. | string | ✓ | | -| network_interfaces | Network interfaces configuration. Use self links for Shared VPC, set addresses to null if not needed. | list(object({...})) | ✓ | | -| project_id | Project id. | string | ✓ | | -| region | Compute region. | string | ✓ | | -| zone | Compute zone. | string | ✓ | | -| *boot_disk* | Boot disk properties. | object({...}) | | ... | -| *coredns_corefile* | CoreDNS Corefile content, defaults to sample configuration. | string | | null | -| *coredns_image* | CoreDNS container image. | string | | coredns/coredns | -| *coredns_log_driver* | CoreDNS container log driver (local, gcplogs, etc.). | string | | gcplogs | -| *cos_config* | Configure COS logging and monitoring. | object({...}) | | ... | -| *files* | Map of files to create on the instances, path as key. Attributes default to 'root' and '0644', set to null if not needed. | map(object({...})) | | {} | -| *hostname* | Instance FQDN name. | string | | null | -| *instance_count* | Number of instances to create (only for non-template usage). | number | | 1 | -| *instance_type* | Instance type. | string | | f1-micro | -| *labels* | Instance labels. | map(string) | | {} | -| *metadata* | Instance metadata. | map(string) | | {} | -| *min_cpu_platform* | Minimum CPU platform. | string | | null | -| *options* | Instance options. | object({...}) | | ... | -| *service_account* | Service account email (leave empty to auto-create). | string | | | -| *tags* | Instance tags. | list(string) | | ["dns", "ssh"] | -| *use_instance_template* | Create instance template instead of instances. | bool | | false | - -## Outputs - -| name | description | sensitive | -|---|---|:---:| -| external_ips | Instance main interface external IP addresses. | | -| instances | Instance resources. | | -| internal_ips | Instance main interface internal IP addresses. | | -| names | Instance names. | | -| self_links | Instance self links. | | -| template | Template resource. | | -| template_name | Template name. | | - diff --git a/modules/compute-vm-cos-coredns/main.tf b/modules/compute-vm-cos-coredns/main.tf deleted file mode 100644 index 36c5bbe010..0000000000 --- a/modules/compute-vm-cos-coredns/main.tf +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright 2020 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 "cos-coredns" { - source = "../compute-vm-cos" - project_id = var.project_id - region = var.region - zone = var.zone - name = var.name - boot_disk = var.boot_disk - hostname = var.hostname - instance_count = var.instance_count - instance_type = var.instance_type - labels = var.labels - metadata = merge(var.metadata, { - google-logging-enabled = var.cos_config.logging - google-monitoring-enabled = var.cos_config.monitoring - }) - min_cpu_platform = var.min_cpu_platform - network_interfaces = var.network_interfaces - options = var.options - service_account = var.service_account - tags = var.tags - log_driver = var.coredns_log_driver - use_instance_template = var.use_instance_template - cos_config = var.cos_config - image = var.coredns_image - files = { - "/etc/systemd/resolved.conf" : { - content = <<-EOT - [Resolve] - LLMNR=no - DNSStubListener=no - EOT - attributes = null - } - "/etc/coredns/Corefile" : { - content = (var.coredns_corefile == null - ? file("${path.module}/Corefile") - : var.coredns_corefile - ) - attributes = null - } - } - volumes = { - "/etc/coredns" : "/etc/coredns" - } - pre_runcmds = [ - "systemctl restart systemd-resolved.service" - ] - extra_args = "-conf /etc/coredns/Corefile" - exposed_ports = { - tcp = [53] - udp = [53] - } -} diff --git a/modules/compute-vm-cos-coredns/outputs.tf b/modules/compute-vm-cos-coredns/outputs.tf deleted file mode 100644 index 4d2154e5a7..0000000000 --- a/modules/compute-vm-cos-coredns/outputs.tf +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright 2020 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. - */ - -output "instances" { - description = "Instance resources." - value = module.cos-coredns.instances -} - -output "names" { - description = "Instance names." - value = module.cos-coredns.names -} - -output "self_links" { - description = "Instance self links." - value = module.cos-coredns.self_links -} - -output "internal_ips" { - description = "Instance main interface internal IP addresses." - value = module.cos-coredns.internal_ips -} - -output "external_ips" { - description = "Instance main interface external IP addresses." - value = module.cos-coredns.external_ips -} - -output "template" { - description = "Template resource." - value = module.cos-coredns.template -} - -output "template_name" { - description = "Template name." - value = module.cos-coredns.template_name -} diff --git a/modules/compute-vm-cos-coredns/variables.tf b/modules/compute-vm-cos-coredns/variables.tf deleted file mode 100644 index fd18ff8e1e..0000000000 --- a/modules/compute-vm-cos-coredns/variables.tf +++ /dev/null @@ -1,174 +0,0 @@ -/** - * Copyright 2020 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 "boot_disk" { - description = "Boot disk properties." - type = object({ - image = string - size = number - type = string - }) - default = { - image = "projects/cos-cloud/global/images/family/cos-stable" - type = "pd-ssd" - size = 10 - } -} - -variable "coredns_corefile" { - description = "CoreDNS Corefile content, defaults to sample configuration." - type = string - default = null -} - -variable "coredns_image" { - description = "CoreDNS container image." - type = string - default = "coredns/coredns" -} - -variable "coredns_log_driver" { - description = "CoreDNS container log driver (local, gcplogs, etc.)." - type = string - default = "gcplogs" -} - -variable "cos_config" { - description = "Configure COS logging and monitoring." - type = object({ - logging = bool - monitoring = bool - }) - default = { - logging = false - monitoring = true - } -} - -variable "files" { - description = "Map of files to create on the instances, path as key. Attributes default to 'root' and '0644', set to null if not needed." - type = map(object({ - content = string - attributes = object({ - owner = string - permissions = string - }) - })) - default = {} -} - -variable "hostname" { - description = "Instance FQDN name." - type = string - default = null -} - -variable "instance_count" { - description = "Number of instances to create (only for non-template usage)." - type = number - default = 1 -} - -variable "instance_type" { - description = "Instance type." - type = string - default = "f1-micro" -} - -variable "labels" { - description = "Instance labels." - type = map(string) - default = {} -} - -variable "metadata" { - description = "Instance metadata." - type = map(string) - default = {} -} - -variable "min_cpu_platform" { - description = "Minimum CPU platform." - type = string - default = null -} - -variable "name" { - description = "Instances base name." - type = string -} - -variable "network_interfaces" { - description = "Network interfaces configuration. Use self links for Shared VPC, set addresses to null if not needed." - type = list(object({ - nat = bool - network = string - subnetwork = string - addresses = object({ - internal = list(string) - external = list(string) - }) - })) -} - -variable "options" { - description = "Instance options." - type = object({ - allow_stopping_for_update = bool - can_ip_forward = bool - deletion_protection = bool - preemptible = bool - }) - default = { - allow_stopping_for_update = true - can_ip_forward = false - deletion_protection = false - preemptible = false - } -} - -variable "project_id" { - description = "Project id." - type = string -} - -variable "region" { - description = "Compute region." - type = string -} - -variable "service_account" { - description = "Service account email (leave empty to auto-create)." - type = string - default = "" -} - -variable "tags" { - description = "Instance tags." - type = list(string) - default = ["dns", "ssh"] -} - -variable "use_instance_template" { - description = "Create instance template instead of instances." - type = bool - default = false -} - -variable "zone" { - description = "Compute zone." - type = string -} diff --git a/modules/compute-vm-cos/README.md b/modules/compute-vm-cos/README.md deleted file mode 100644 index 498b3ca2c5..0000000000 --- a/modules/compute-vm-cos/README.md +++ /dev/null @@ -1,155 +0,0 @@ -# Container Optimized OS module - -This module allows creating instances (or an instance template) runnning a containerized application using COS. A service account will be created if none is set. - -This module can be used with a custom cloud-config template or with one of the provided preset configurations. - -## Examples - -### CoreDNS preset - -This preset creates CoreDNS instances. Use `preset:coredns.yaml` as the value for `cloud_config.template_path` and you must specify the following variables: - -| name | description | type | required | -|-----------|-------------------------------------------------------------------------------------------------------------------------------------|:----------------------------:|:--------:| -| corefile | CoreDNS Corefile content, use `"default"` to use sample configuration. | string | ✓ | -| logdriver | CoreDNS container log driver (local, gcplogs, etc.). | string | ✓ | -| files | Map of files to create on the instances, path as key, value must be an `object({content=string, owner=string, permissions=string})` | object | ✓ | - -```hcl -module "coredns" { - source = "./modules/compute-vm-cos" - project_id = var.project_id - region = var.region - zone = var.zone - name = "coredns" - network_interfaces = [{ - network = var.vpc_self_link - subnetwork = var.subnet_self_link - nat = false, - addresses = null - }] - - cloud_config = { - template_path = "preset:coredns.yaml" - variables = { - corefile = "default" - log_driver = "gcplogs" - files = {} - } - } -} -``` - -### Generic preset - -This preset creates a COS instance and runs the specfied container image. Use `preset:generic.yaml` as the value for `cloud_config.template_path` and you must specify the following variables: - -| name | description | type | required | -|---------------|-------------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------:|:--------:| -| image | Container image to run | string | ✓ | -| extra_args | Extra arguments to pass to the container | string | ✓ | -| logdriver | Container log driver (local, gcplogs, etc.). | string | ✓ | -| files | Map of files to create on the instances, path as key, value must be an `object({content=string, owner=string, permissions=string})` | object | ✓ | -| volumes | Map volumes to mount in the container. Key is the host path and value is the container path | map(string) | | -| pre_runcmds | List of commands to run before starting the container | list(string) | | -| post_runcmds | List of commands to run after starting the container | list(string) | | -| exposed_ports | List of ports to expose in the host. | object({tcp = list(string), udp=list(string)}) | | - - -```hcl -module "nginx" { - source = "./modules/compute-vm-cos" - project_id = var.project_id - region = var.region - zone = var.zone - name = "nginx" - network_interfaces = [{ - network = var.vpc_self_link - subnetwork = var.subnet_self_link - nat = false, - addresses = null - }] - cloud_config = { - template_path = "preset:generic.yaml" - variables = { - image = "nginx:1.17" - files = { - "/etc/nginx/htdocs/index.html" : { - content = "hello world" - } - } - exposed_ports = { - tcp = [80] - } - volumes = { - "/etc/nginx/htdocs" : "/usr/share/nginx/html" - } - } - } -} -``` - -### User-defined configuration - -```hcl -module "nginx" { - source = "./modules/compute-vm-cos" - project_id = var.project_id - region = var.region - zone = var.zone - name = "nginx" - network_interfaces = [{ - network = var.vpc_self_link - subnetwork = var.subnet_self_link - nat = false, - addresses = null - }] - cloud_config = { - template_path = "${module.path}/mytemplate.yaml" - variables = { - var1 = "value1" - var2 = "value2" - } - } -} -``` - - - -## Variables - -| name | description | type | required | default | -|---|---|:---: |:---:|:---:| -| cloud_config | Configuration for rendering the cloud-config string for the instance. Must be a map with two keys: template_path and variables | | ✓ | | -| name | Instances base name. | string | ✓ | | -| network_interfaces | Network interfaces configuration. Use self links for Shared VPC, set addresses to null if not needed. | list(object({...})) | ✓ | | -| project_id | Project id. | string | ✓ | | -| region | Compute region. | string | ✓ | | -| zone | Compute zone. | string | ✓ | | -| *boot_disk* | Boot disk properties. | object({...}) | | ... | -| *cos_config* | Configure COS logging and monitoring. | object({...}) | | ... | -| *files* | Map of files to create on the instances, path as key. Attributes default to 'root' and '0644', set to null if not needed. | map(object({...})) | | {} | -| *hostname* | Instance FQDN name. | string | | null | -| *instance_count* | Number of instances to create (only for non-template usage). | number | | 1 | -| *instance_type* | Instance type. | string | | f1-micro | -| *labels* | Instance labels. | map(string) | | {} | -| *metadata* | Instance metadata. | map(string) | | {} | -| *min_cpu_platform* | Minimum CPU platform. | string | | null | -| *options* | Instance options. | object({...}) | | ... | -| *service_account* | Service account email (leave empty to auto-create). | string | | | -| *tags* | Instance tags. | list(string) | | ["dns", "ssh"] | -| *use_instance_template* | Create instance template instead of instances. | bool | | false | - -## Outputs - -| name | description | sensitive | -|---|---|:---:| -| external_ips | Instance main interface external IP addresses. | | -| instances | Instance resources. | | -| internal_ips | Instance main interface internal IP addresses. | | -| names | Instance names. | | -| self_links | Instance self links. | | -| template | Template resource. | | -| template_name | Template name. | | - diff --git a/modules/compute-vm-cos/cloud-config/coredns.yaml b/modules/compute-vm-cos/cloud-config/coredns.yaml deleted file mode 100644 index 2734868c41..0000000000 --- a/modules/compute-vm-cos/cloud-config/coredns.yaml +++ /dev/null @@ -1,87 +0,0 @@ -#cloud-config - -# Copyright 2020 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. - -# https://hub.docker.com/r/coredns/coredns/ -# https://coredns.io/manual/toc/#installation - -# TODO: switch to the gcplogs logging driver, and set driver labels - -write_files: -- path: /var/lib/docker/daemon.json - permissions: 0644 - owner: root - content: | - { - "live-restore": true, - "storage-driver": "overlay2", - "log-opts": { - "max-size": "1024m" - } - } - -# disable systemd-resolved to free port 53 on the loopback interface -- path: /etc/systemd/resolved.conf - permissions: 0644 - owner: root - content: | - [Resolve] - LLMNR=no - DNSStubListener=no - -- path: /etc/coredns/Corefile - permissions: 0644 - owner: root - content: | -%{ if corefile == "default" ~} - . { - forward . /etc/resolv.conf - log - errors - } -%{ else ~} - ${indent(4, corefile)} -%{ endif ~} - -# coredns container service -- path: /etc/systemd/system/coredns.service - permissions: 0644 - owner: root - content: | - [Unit] - Description=Start CoreDNS container - After=gcr-online.target docker.socket - Wants=gcr-online.target docker.socket docker-events-collector.service - [Service] - ExecStart=/usr/bin/docker run --rm --name=coredns \ - --log-driver=${log_driver} --network host \ - -v /etc/coredns:/etc/coredns \ - coredns/coredns -conf /etc/coredns/Corefile - ExecStop=/usr/bin/docker stop coredns - -%{ for path, data in files } -- path: ${path} - owner: ${lookup(data, "owner", "root")} - permissions: ${lookup(data, "permissions", "0644")} - content: | - ${indent(4, data.content)} -%{ endfor } - -runcmd: -- iptables -I INPUT 1 -p tcp -m tcp --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT -- iptables -I INPUT 1 -p udp -m udp --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT -- systemctl daemon-reload -- systemctl restart systemd-resolved.service -- systemctl start coredns diff --git a/modules/compute-vm-cos/cloud-config/generic.yaml b/modules/compute-vm-cos/cloud-config/generic.yaml deleted file mode 100644 index 588a7d385d..0000000000 --- a/modules/compute-vm-cos/cloud-config/generic.yaml +++ /dev/null @@ -1,80 +0,0 @@ -#cloud-config - -# Copyright 2020 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. - -# TODO: switch to the gcplogs logging driver, and set driver labels - -# create a system user, otherwise docker-credential-gcr fails as root -users: -- name: cosuser - uid: 2000 - groups: docker - -write_files: -- path: /var/lib/docker/daemon.json - permissions: 0644 - owner: root - content: | - { - "live-restore": true, - "storage-driver": "overlay2", - "log-opts": { - "max-size": "1024m" - } - } - -%{ for path, data in files } -- path: ${path} - owner: ${lookup(data, "owner", "root")} - permissions: ${lookup(data, "permissions", "0644")} - content: | - ${indent(4, data.content)} -%{ endfor } - -# container service -- path: /etc/systemd/system/cosapp.service - permissions: 0644 - owner: root - content: | - [Unit] - Description=Start Application container - After=gcr-online.target docker.socket - Wants=gcr-online.target docker.socket docker-events-collector.service - [Service] - User=cosuser - ExecStartPre=/usr/bin/docker-credential-gcr configure-docker - ExecStart=/usr/bin/docker run --rm --name=cosapp \ - --log-driver=${log_driver} --network host \ - %{~ for host_path, mount_path in volumes ~} - -v ${host_path}:${mount_path} \ - %{~ endfor ~} - ${image} ${extra_args} - ExecStop=/usr/bin/docker stop cosapp - ExecStopPost=/usr/bin/docker rm cosapp - -runcmd: -- systemctl daemon-reload -%{ for proto, ports in fw_runcmds ~} - %{~ for port in ports ~} -- iptables -I INPUT 1 -p ${proto} -m ${proto} --dport ${port} -m state --state NEW,ESTABLISHED -j ACCEPT - %{~ endfor ~} -%{ endfor ~} -%{ for cmd in pre_runcmds ~} -- ${cmd} -%{ endfor ~} -- systemctl start cosapp -%{ for cmd in pre_runcmds ~} -- ${cmd} -%{ endfor ~} diff --git a/modules/compute-vm-cos/main.tf b/modules/compute-vm-cos/main.tf deleted file mode 100644 index 433440f876..0000000000 --- a/modules/compute-vm-cos/main.tf +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright 2020 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 { - cc = var.cloud_config - ccvars = var.cloud_config.variables - - use_generic_template = local.cc.template_path == "preset:generic.yaml" - template_path = replace(local.cc.template_path, "/preset:/", "${path.module}/cloud-config/") - - generic_config_vars = { - image = lookup(local.ccvars, "image", "") - extra_args = lookup(local.ccvars, "extra_args", "") - log_driver = lookup(local.ccvars, "log_driver", "gcplogs") - volumes = lookup(local.ccvars, "volumes", {}) - pre_runcmds = lookup(local.ccvars, "pre_runcmds", []) - post_runcmds = lookup(local.ccvars, "post_runcmds", []) - fw_runcmds = lookup(local.ccvars, "exposed_ports", []) - files = lookup(local.ccvars, "files", {}) - } - - cloud_config_content = ( - local.use_generic_template - ? templatefile(local.template_path, local.generic_config_vars) - : templatefile(local.template_path, var.cloud_config.variables) - ) -} - -module "vm" { - source = "../compute-vm" - project_id = var.project_id - region = var.region - zone = var.zone - name = var.name - boot_disk = var.boot_disk - hostname = var.hostname - instance_count = var.instance_count - instance_type = var.instance_type - labels = var.labels - metadata = merge(var.metadata, { - google-logging-enabled = var.cos_config.logging - google-monitoring-enabled = var.cos_config.monitoring - user-data = local.cloud_config_content - }) - min_cpu_platform = var.min_cpu_platform - network_interfaces = var.network_interfaces - options = var.options - service_account = var.service_account - tags = var.tags - use_instance_template = var.use_instance_template -} diff --git a/modules/compute-vm-cos/outputs.tf b/modules/compute-vm-cos/outputs.tf deleted file mode 100644 index c70585e697..0000000000 --- a/modules/compute-vm-cos/outputs.tf +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright 2020 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. - */ - -output "instances" { - description = "Instance resources." - value = module.vm.instances -} - -output "names" { - description = "Instance names." - value = module.vm.names -} - -output "self_links" { - description = "Instance self links." - value = module.vm.self_links -} - -output "internal_ips" { - description = "Instance main interface internal IP addresses." - value = module.vm.internal_ips -} - -output "external_ips" { - description = "Instance main interface external IP addresses." - value = module.vm.external_ips -} - -output "template" { - description = "Template resource." - value = module.vm.template -} - -output "template_name" { - description = "Template name." - value = module.vm.template_name -} diff --git a/modules/compute-vm-cos/variables.tf b/modules/compute-vm-cos/variables.tf deleted file mode 100644 index 15775fd2ab..0000000000 --- a/modules/compute-vm-cos/variables.tf +++ /dev/null @@ -1,164 +0,0 @@ -/** - * Copyright 2020 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 "boot_disk" { - description = "Boot disk properties." - type = object({ - image = string - size = number - type = string - }) - default = { - image = "projects/cos-cloud/global/images/family/cos-stable" - type = "pd-ssd" - size = 10 - } -} - -variable "cos_config" { - description = "Configure COS logging and monitoring." - type = object({ - logging = bool - monitoring = bool - }) - default = { - logging = false - monitoring = true - } -} - -variable "files" { - description = "Map of files to create on the instances, path as key. Attributes default to 'root' and '0644', set to null if not needed." - type = map(object({ - content = string - attributes = object({ - owner = string - permissions = string - }) - })) - default = {} -} - -variable "hostname" { - description = "Instance FQDN name." - type = string - default = null -} - -variable "instance_count" { - description = "Number of instances to create (only for non-template usage)." - type = number - default = 1 -} - -variable "instance_type" { - description = "Instance type." - type = string - default = "f1-micro" -} - -variable "labels" { - description = "Instance labels." - type = map(string) - default = {} -} - -variable "metadata" { - description = "Instance metadata." - type = map(string) - default = {} -} - -variable "min_cpu_platform" { - description = "Minimum CPU platform." - type = string - default = null -} - -variable "name" { - description = "Instances base name." - type = string -} - -variable "network_interfaces" { - description = "Network interfaces configuration. Use self links for Shared VPC, set addresses to null if not needed." - type = list(object({ - nat = bool - network = string - subnetwork = string - addresses = object({ - internal = list(string) - external = list(string) - }) - })) -} - -variable "options" { - description = "Instance options." - type = object({ - allow_stopping_for_update = bool - can_ip_forward = bool - deletion_protection = bool - preemptible = bool - }) - default = { - allow_stopping_for_update = true - can_ip_forward = false - deletion_protection = false - preemptible = false - } -} - -variable "project_id" { - description = "Project id." - type = string -} - -variable "region" { - description = "Compute region." - type = string -} - -variable "service_account" { - description = "Service account email (leave empty to auto-create)." - type = string - default = "" -} - -variable "tags" { - description = "Instance tags." - type = list(string) - default = ["dns", "ssh"] -} - -variable "use_instance_template" { - description = "Create instance template instead of instances." - type = bool - default = false -} - -variable "zone" { - description = "Compute zone." - type = string -} - -variable "cloud_config" { - description = "Configuration for rendering the cloud-config string for the instance. Must be a map with two keys: template_path and variables" - # type = object({ - # template_path = string - # variables = map(any) - # }) -} diff --git a/modules/compute-vm/variables.tf b/modules/compute-vm/variables.tf index a914ab7da7..018e16d108 100644 --- a/modules/compute-vm/variables.tf +++ b/modules/compute-vm/variables.tf @@ -46,6 +46,20 @@ variable "attached_disk_defaults" { } } +variable "boot_disk" { + description = "Boot disk properties." + type = object({ + image = string + size = number + type = string + }) + default = { + image = "projects/debian-cloud/global/images/family/debian-10" + type = "pd-ssd" + size = 10 + } +} + variable "group" { description = "Instance group (for instance use)." type = object({ diff --git a/modules/cos-container/README.md b/modules/cos-container/README.md new file mode 100644 index 0000000000..e882286251 --- /dev/null +++ b/modules/cos-container/README.md @@ -0,0 +1,76 @@ +# Container Optimized OS modules + +This set of modules creates specialized [cloud-config](https://cloud.google.com/container-optimized-os/docs/how-to/run-container-instance#starting_a_docker_container_via_cloud-config) configurations for [Container Optimized OS](https://cloud.google.com/container-optimized-os/docs), that are used to quickly spin up containerized services for DNS, HTTP, or databases. + +It's meant to fullfill different use cases: + +- when designing, to quickly prototype specialized services (eg MySQL access or HTTP serving) +- when planning migrations, to emulate production services for core infrastructure or perfomance testing +- in production, to easily add glue components for services like DNS (eg to work around inbound/outbound forwarding limitations) +- as a basis to implement cloud-native production deployments that leverage cloud-init for configuration management + +## Using the test instance + +- [ ] what it is and how to use it +- [ ] how to remove it when forking modules + +## Updating cloud-config on running instances + +- [ ] describe `/usr/share/cloud/rerun-cloudinit.sh` +- [ ] describe the need to restart + +## Combining with the compute-vm module + +- [ ] describe and add example + +## Available modules + +### CoreDNS + +- [ ] test module +- [ ] add description and examples here + +### MySQL + +- [ ] test module +- [ ] add description and examples here + +### Nginx + +- [ ] write module +- [ ] add description and examples here + +### PostgreSQL + +- [ ] write module +- [ ] add description and examples here + +### Squid forward proxy + +- [ ] find a good image or build and deploy one +- [ ] write module +- [ ] add description and examples here + +### Multiple files or directories + +- [ ] find the right example (GCS? git?) +- [ ] write module +- [ ] add description and examples here + +### Two-containers example + +- [ ] find the right example (nginx + git sync of static http docs) +- [ ] write module +- [ ] add description and examples here + +### Docker compose example + +- [ ] find the right example +- [ ] write module +- [ ] add description and examples here + +### Containerized app + +- [ ] find the right example (gitlab?) +- [ ] write module +- [ ] add description and examples here diff --git a/modules/compute-vm-cos-coredns/Corefile b/modules/cos-container/coredns/Corefile similarity index 81% rename from modules/compute-vm-cos-coredns/Corefile rename to modules/cos-container/coredns/Corefile index f7309f221f..e5a7674faa 100644 --- a/modules/compute-vm-cos-coredns/Corefile +++ b/modules/cos-container/coredns/Corefile @@ -1,5 +1,6 @@ . { forward . /etc/resolv.conf + reload log errors -} +} \ No newline at end of file diff --git a/modules/cos-container/coredns/Corefile-hosts b/modules/cos-container/coredns/Corefile-hosts new file mode 100644 index 0000000000..1baa581a66 --- /dev/null +++ b/modules/cos-container/coredns/Corefile-hosts @@ -0,0 +1,9 @@ +. { + hosts /etc/coredns/example.hosts example.org { + 127.0.0.1 localhost.example.org localhost + } + forward . /etc/resolv.conf + reload + log + errors +} diff --git a/modules/cos-container/coredns/README.md b/modules/cos-container/coredns/README.md new file mode 100644 index 0000000000..eb6c531ab1 --- /dev/null +++ b/modules/cos-container/coredns/README.md @@ -0,0 +1,85 @@ +# Containerized CoreDNS on Container Optimized OS + +This module creates a cloud-config configuration, used to configure and start a containerized [CoreDNS](https://coredns.io/) service on Container Optimized OS, using the [official image](https://hub.docker.com/r/coredns/coredns/). + +The CoreDNS configuration and additional files (used for zone or hosts files) can be set via variables. Rules are added to iptables to allow DNS on TCP and UDP, and HTTP for health checks configurable via the CoreDNS [health plugin](https://coredns.io/plugins/health/). + +Logging and monitoring are enabled via the [Google Cloud Logging driver](https://docs.docker.com/config/containers/logging/gcplogs/) configured for the CoreDNS container, and the [Node Problem Detector](https://cloud.google.com/container-optimized-os/docs/how-to/monitoring) service started by default on boot. + +The module outputs the rendered cloud config to be set in the `user-data` metadata of instances or instance templates. For convenience in test or development setups, a simple instance can be created and managed via the `test_instance` variable. Refer to the [top-level README](../README.md) for details on the instance configuration. + +## Examples + +### Default CoreDNS configuration + +This example will create a cloud-config that uses the module's defaults. No variables are needed, the cloud-config is available from the module's outputs. + +```hcl +module "cos-coredns" { + source = "./modules/cos-container/coredns" +} + +# use it as metadata in a compute instance or template +resource "google_compute_instance" "default" { + metadata = { + user-data = module.cos-coredns.cloud_config + } +``` + +### Custom CoreDNS configuration + +This example will create a cloud-config that changes the CoreDNS configuration to use the [CoreDNS hosts plugin](), and adds a simple hosts-format file. Again, the cloud-config is available from the module's outputs. + +```hcl +module "cos-coredns" { + source = "./modules/cos-container/coredns" + coredns_config = "./modules/cos-container/coredns/Corefile-hosts" + files = { + "/etc/coredns/example.hosts" = { + content = "127.0.0.2 foo.example.org foo" + owner = null + permissions = "0644" + } +} +``` + +### Create the test instance + +To create the test instance, simply set the appropriate values in the `test_instance` variable. An instance and a custom service account with logging and monitoring write permissions will be created. + +```hcl +module "cos-coredns" { + source = "./modules/cos-container/coredns" + test_instance = { + project_id = "my-project" + zone = "europe-west1-b" + name = "cos-coredns" + type = "f1-micro" + tags = ["ssh"] + metadata = {} + network = "default" + subnetwork = "https://www.googleapis.com/compute/v1/projects/my-project/regions/europe-west1/subnetworks/my-subnet" + disks = [] + } +} +``` + + +## Variables + +| name | description | type | required | default | +|---|---|:---: |:---:|:---:| +| *cloud_config* | Cloud config template path. If null default will be used. | string | | null | +| *config_variables* | Additional variables used to render the cloud-config template. | map(any) | | {} | +| *coredns_config* | CoreDNS configuration file content, if null default will be used. | string | | null | +| *file_defaults* | Default owner and permissions for files. | object({...}) | | ... | +| *files* | Map of extra files to create on the instance, path as key. Owner and permissions will use defaults if null. | map(object({...})) | | {} | +| *test_instance* | Test/development instance attributes, leave null to skip creation. | object({...}) | | null | + +## Outputs + +| name | description | sensitive | +|---|---|:---:| +| cloud_config | Rendered cloud-config file to be passed as user-data instance metadata. | | +| test_instance | Optional test instance name and address | | + \ No newline at end of file diff --git a/modules/cos-container/coredns/cloud-config.yaml b/modules/cos-container/coredns/cloud-config.yaml new file mode 100644 index 0000000000..b8796c5271 --- /dev/null +++ b/modules/cos-container/coredns/cloud-config.yaml @@ -0,0 +1,83 @@ +#cloud-config + +# Copyright 2020 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. + +# https://hub.docker.com/r/coredns/coredns/ +# https://coredns.io/manual/toc/#installation + +# TODO: switch to the gcplogs logging driver, and set driver labels + +write_files: + - path: /var/lib/docker/daemon.json + permissions: 0644 + owner: root + content: | + { + "live-restore": true, + "storage-driver": "overlay2", + "log-opts": { + "max-size": "1024m" + } + } + + # disable systemd-resolved to free port 53 on the loopback interface + - path: /etc/systemd/resolved.conf + permissions: 0644 + owner: root + content: | + [Resolve] + LLMNR=no + DNSStubListener=no + + - path: /etc/coredns/Corefile + permissions: 0644 + owner: root + content: | + ${indent(6, corefile)} + + # coredns container service + - path: /etc/systemd/system/coredns.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=Start CoreDNS container + After=gcr-online.target docker.socket + Wants=gcr-online.target docker.socket docker-events-collector.service + [Service] + ExecStart=/usr/bin/docker run --rm --name=coredns \ + --log-driver=gcplogs --network host \ + -v /etc/coredns:/etc/coredns \ + coredns/coredns -conf /etc/coredns/Corefile + ExecStop=/usr/bin/docker stop coredns + + %{ for path, data in files } + - path: ${path} + owner: ${lookup(data, "owner", "root")} + permissions: ${lookup(data, "permissions", "0644")} + content: | + ${indent(4, data.content)} + %{ endfor } + +bootcmd: + - systemctl start node-problem-detector + +runcmd: + - iptables -I INPUT 1 -p tcp -m tcp --dport 8080 -m state --state NEW,ESTABLISHED -j ACCEPT + - iptables -I INPUT 1 -p tcp -m tcp --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT + - iptables -I INPUT 1 -p udp -m udp --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT + - systemctl daemon-reload + - systemctl restart systemd-resolved.service + - systemctl start coredns \ No newline at end of file diff --git a/modules/cos-container/coredns/instance.tf b/modules/cos-container/coredns/instance.tf new file mode 120000 index 0000000000..bdef596b6d --- /dev/null +++ b/modules/cos-container/coredns/instance.tf @@ -0,0 +1 @@ +../instance.tf \ No newline at end of file diff --git a/modules/cos-container/coredns/main.tf b/modules/cos-container/coredns/main.tf new file mode 100644 index 0000000000..c793557718 --- /dev/null +++ b/modules/cos-container/coredns/main.tf @@ -0,0 +1,41 @@ +/** + * Copyright 2019 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 { + cloud_config = templatefile(local.template, merge(var.config_variables, { + corefile = local.corefile + files = local.files + })) + corefile = file( + var.coredns_config == null ? "${path.module}/Corefile" : var.coredns_config + ) + files = { + for path, attrs in var.files : path => { + content = attrs.content, + owner = attrs.owner == null ? var.file_defaults.owner : attrs.owner, + permissions = ( + attrs.permissions == null + ? var.file_defaults.permissions + : attrs.permissions + ) + } + } + template = ( + var.cloud_config == null + ? "${path.module}/cloud-config.yaml" + : var.cloud_config + ) +} diff --git a/modules/cos-container/coredns/outputs-instance.tf b/modules/cos-container/coredns/outputs-instance.tf new file mode 120000 index 0000000000..ea9e240458 --- /dev/null +++ b/modules/cos-container/coredns/outputs-instance.tf @@ -0,0 +1 @@ +../outputs-instance.tf \ No newline at end of file diff --git a/modules/cos-container/coredns/outputs.tf b/modules/cos-container/coredns/outputs.tf new file mode 100644 index 0000000000..205a557165 --- /dev/null +++ b/modules/cos-container/coredns/outputs.tf @@ -0,0 +1,20 @@ +/** + * Copyright 2019 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. + */ + +output "cloud_config" { + description = "Rendered cloud-config file to be passed as user-data instance metadata." + value = local.cloud_config +} diff --git a/modules/cos-container/coredns/variables-instance.tf b/modules/cos-container/coredns/variables-instance.tf new file mode 120000 index 0000000000..94af61e4dd --- /dev/null +++ b/modules/cos-container/coredns/variables-instance.tf @@ -0,0 +1 @@ +../variables-instance.tf \ No newline at end of file diff --git a/modules/cos-container/coredns/variables.tf b/modules/cos-container/coredns/variables.tf new file mode 100644 index 0000000000..f50d85826a --- /dev/null +++ b/modules/cos-container/coredns/variables.tf @@ -0,0 +1,55 @@ +/** + * Copyright 2019 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 "cloud_config" { + description = "Cloud config template path. If null default will be used." + type = string + default = null +} + +variable "config_variables" { + description = "Additional variables used to render the cloud-config template." + type = map(any) + default = {} +} + +variable "coredns_config" { + description = "CoreDNS configuration path, if null default will be used." + type = string + default = null +} + +variable "file_defaults" { + description = "Default owner and permissions for files." + type = object({ + owner = string + permissions = string + }) + default = { + owner = "root" + permissions = "0644" + } +} + +variable "files" { + description = "Map of extra files to create on the instance, path as key. Owner and permissions will use defaults if null." + type = map(object({ + content = string + owner = string + permissions = string + })) + default = {} +} diff --git a/modules/cos-container/instance.tf b/modules/cos-container/instance.tf new file mode 100644 index 0000000000..b66cdc75d7 --- /dev/null +++ b/modules/cos-container/instance.tf @@ -0,0 +1,77 @@ +/** + * Copyright 2020 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 { + sa_roles = ["roles/logging.logWriter", "roles/monitoring.metricWriter"] +} + +resource "google_service_account" "default" { + count = var.test_instance == null ? 0 : 1 + project = var.test_instance.project_id + account_id = "cos-test-${var.test_instance.name}" + display_name = "Managed by the cos Terraform module." +} + +resource "google_project_iam_member" "default" { + for_each = var.test_instance == null ? toset([]) : toset(local.sa_roles) + project = var.test_instance.project_id + role = each.value + member = "serviceAccount:${google_service_account.default[0].email}" +} + +resource "google_compute_instance" "default" { + count = var.test_instance == null ? 0 : 1 + project = var.test_instance.project_id + zone = var.test_instance.zone + name = var.test_instance.name + description = "Managed by the cos Terraform module." + tags = var.test_instance.tags + machine_type = ( + var.test_instance.type == null ? "f1-micro" : var.test_instance.type + ) + metadata = merge(var.test_instance.metadata, { + user-data = local.cloud_config + }) + + dynamic attached_disk { + for_each = var.test_instance.disks + iterator = disk + content { + device_name = disk.value.name + mode = disk.value.mode + source = disk.value.source + } + } + + boot_disk { + initialize_params { + type = "pd-ssd" + image = "projects/cos-cloud/global/images/family/cos-stable" + size = 10 + } + } + + network_interface { + network = var.test_instance.network + subnetwork = var.test_instance.subnetwork + } + + service_account { + email = google_service_account.default[0].email + scopes = ["https://www.googleapis.com/auth/cloud-platform"] + } + +} diff --git a/modules/cos-container/mysql/README.md b/modules/cos-container/mysql/README.md new file mode 100644 index 0000000000..46ff0f498d --- /dev/null +++ b/modules/cos-container/mysql/README.md @@ -0,0 +1,26 @@ +# Containerized MySQL on Container Optimized OS + +- [ ] test module +- [ ] add description and examples + + +## Variables + +| name | description | type | required | default | +|---|---|:---: |:---:|:---:| +| mysql_password | MySQL root password. If an encrypted password is set, use the kms_config variable to specify KMS configuration. | string | ✓ | | +| *attached_disks* | Map of attached disks, key is the device path (eg /dev/disk/by-id/google-foo). Mount name is relative to /mnt/disks. Filesystem defaults to ext4 if null. | map(object({...})) | | {} | +| *cloud_config* | Cloud config template path. If null default will be used. | string | | null | +| *config_variables* | Additional variables used to render the cloud-config template. | map(any) | | {} | +| *image* | MySQL container image. | string | | mysql:5.7 | +| *kms_config* | Optional KMS configuration to decrypt passed-in password. Leave null if a plaintext password is used. | object({...}) | | null | +| *mysql_config* | MySQL configuration file content, if null default will be used. | string | | null | +| *test_instance* | Test/development instance attributes, leave null to skip creation. | object({...}) | | null | + +## Outputs + +| name | description | sensitive | +|---|---|:---:| +| cloud_config | Rendered cloud-config file to be passed as user-data instance metadata. | | +| test_instance | Optional test instance name and address | | + \ No newline at end of file diff --git a/modules/cos-container/mysql/cloud-config.yaml b/modules/cos-container/mysql/cloud-config.yaml new file mode 100644 index 0000000000..17c291a0d2 --- /dev/null +++ b/modules/cos-container/mysql/cloud-config.yaml @@ -0,0 +1,122 @@ +#cloud-config + +# Copyright 2019 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. + +users: + - name: mysql + uid: 2000 + +%{ if length(attached_disks) > 0 } +fs_setup: + %{ for device, attrs in attached_disks } + - label: None + filesystem: ${attrs.filesystem} + device: ${device} + partition: auto + overwrite: False + %{ endfor } + +mounts: + %{ for device, attrs in attached_disks } + - [ ${device}, /mnt/disks/${attrs.mount_name}] + %{ endfor } + +%{ endif } + +write_files: + - path: /var/lib/docker/daemon.json + permissions: 0644 + owner: root + content: | + { + "live-restore": true, + "storage-driver": "overlay2", + "log-opts": { + "max-size": "1024m" + } + } + - path: /run/secrets/mysql-passwd-orig.txt + permissions: 0600 + owner: root + content: | + ${password} + - path: /run/mysql-passwd.sh + permissions: 0700 + owner: root + content: | + #!/bin/bash + %{ if kms_config != null } + base64 -d /run/secrets/mysql-passwd-orig.txt | docker run \ + --rm -i -v /run/secrets/:/data google/cloud-sdk:alpine \ + gcloud kms decrypt --ciphertext-file - \ + --plaintext-file /data/mysql-passwd.txt \ + --keyring ${kms_config.keyring} \ + --key ${kms_config.key} \ + --project ${kms_config.project_id} \ + --location ${kms_config.location} + %{ else } + cp /run/secrets/mysql-passwd-orig.txt /run/secrets/mysql-passwd.txt + %{ endif } + cp /run/secrets/mysql-passwd.txt /run/mysql/root-passwd.txt + chown 2000 /run/mysql/root-passwd.txt + - path: /run/mysql/conf.d/my.cnf + permissions: 0644 + owner: mysql + content: | + ${indent(6, mysql_config)} + - path: /etc/systemd/system/mysql-data.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=MySQL data disk + ConditionPathExists=/dev/disk/by-id/google-mysql-data + Before=mysql.service + [Service] + Type=oneshot + ExecStart=/bin/mkdir -p /run/mysql + ExecStart=/bin/chown -R 2000 /run/mysql + %{ for device, attrs in attached_disks } + ExecStart=/bin/chown 2000 /mnt/disks/${attrs.mount_name} + %{ endfor } + RemainAfterExit=true + - path: /etc/systemd/system/mysql.service + permissions: 0644 + owner: root + content: | + [Unit] + Description=MySQL service + After=mysql-data.service gcr-online.target docker.socket docker-events-collector.service + Wants=mysql-data.service gcr-online.target docker.socket + [Service] + ExecStartPre=/run/mysql-passwd.sh + ExecStart=/usr/bin/docker run --rm --name=mysql \ + --user 2000:2000 \ + --log-driver=gcplogs \ + --network host \ + -e MYSQL_ROOT_PASSWORD_FILE=/etc/mysql/root-passwd.txt \ + -v /mnt/disks/mysql-data:/var/lib/mysql \ + -v /run/mysql/:/etc/mysql \ + ${image} \ + --ignore-db-dir=lost+found + ExecStop=/usr/bin/docker stop mysql + +bootcmd: + - systemctl start node-problem-detector + +runcmd: + - iptables -I INPUT 1 -p tcp -m tcp --dport 3306 -m state --state NEW,ESTABLISHED -j ACCEPT + - systemctl daemon-reload + - systemctl start mysql \ No newline at end of file diff --git a/modules/cos-container/mysql/instance.tf b/modules/cos-container/mysql/instance.tf new file mode 120000 index 0000000000..bdef596b6d --- /dev/null +++ b/modules/cos-container/mysql/instance.tf @@ -0,0 +1 @@ +../instance.tf \ No newline at end of file diff --git a/modules/cos-container/mysql/main.tf b/modules/cos-container/mysql/main.tf new file mode 100644 index 0000000000..dc2c2ace6f --- /dev/null +++ b/modules/cos-container/mysql/main.tf @@ -0,0 +1,41 @@ +/** + * Copyright 2019 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 { + attached_disks = { + for device, attrs in var.attached_disks : device => { + mount_name = attrs.mount_name + filesystem = attrs.filesystem == null ? "ext4" : attrs.filesystem + } + } + cloud_config = templatefile(local.template, merge(var.config_variables, { + attached_disks = local.attached_disks + image = var.image + kms_config = var.kms_config + mysql_config = local.mysql_config + password = var.mysql_password + })) + mysql_config = ( + var.mysql_config == null + ? file("${path.module}/my.cnf") + : var.mysql_config + ) + template = ( + var.cloud_config == null + ? "${path.module}/cloud-config.yaml" + : var.cloud_config + ) +} diff --git a/modules/cos-container/mysql/my.cnf b/modules/cos-container/mysql/my.cnf new file mode 100644 index 0000000000..a1d44f05ac --- /dev/null +++ b/modules/cos-container/mysql/my.cnf @@ -0,0 +1,31 @@ +[mysqld] +default-storage-engine = InnoDB + +# SAFETY # +max-allowed-packet = 16M +max-connect-errors = 1000000 + +# CACHES AND LIMITS # +tmp-table-size = 32M +max-heap-table-size = 32M +query-cache-type = 0 +query-cache-size = 0 +max-connections = 10000 +thread-cache-size = 50 +open-files-limit = 65535 +table-definition-cache = 1024 +table-open-cache = 2048 + +# INNODB # +innodb-flush-method = O_DIRECT +innodb-log-files-in-group = 2 +innodb-log-file-size = 512M +innodb-flush-log-at-trx-commit = 1 +innodb-file-per-table = 1 + +# LOGGING # +log-error = /var/lib/mysql/mysql-error.log +slow-query-log = 1 +slow-query-log-file = /var/lib/mysql/mysql-slow.log +#read-only = 1 +long-query-time = 10 \ No newline at end of file diff --git a/modules/cos-container/mysql/outputs-instance.tf b/modules/cos-container/mysql/outputs-instance.tf new file mode 120000 index 0000000000..ea9e240458 --- /dev/null +++ b/modules/cos-container/mysql/outputs-instance.tf @@ -0,0 +1 @@ +../outputs-instance.tf \ No newline at end of file diff --git a/modules/cos-container/mysql/outputs.tf b/modules/cos-container/mysql/outputs.tf new file mode 100644 index 0000000000..205a557165 --- /dev/null +++ b/modules/cos-container/mysql/outputs.tf @@ -0,0 +1,20 @@ +/** + * Copyright 2019 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. + */ + +output "cloud_config" { + description = "Rendered cloud-config file to be passed as user-data instance metadata." + value = local.cloud_config +} diff --git a/modules/cos-container/mysql/variables-instance.tf b/modules/cos-container/mysql/variables-instance.tf new file mode 120000 index 0000000000..94af61e4dd --- /dev/null +++ b/modules/cos-container/mysql/variables-instance.tf @@ -0,0 +1 @@ +../variables-instance.tf \ No newline at end of file diff --git a/modules/cos-container/mysql/variables.tf b/modules/cos-container/mysql/variables.tf new file mode 100644 index 0000000000..252e53b5f1 --- /dev/null +++ b/modules/cos-container/mysql/variables.tf @@ -0,0 +1,64 @@ +/** + * Copyright 2019 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 "attached_disks" { + description = "Map of attached disks, key is the device path (eg /dev/disk/by-id/google-foo). Mount name is relative to /mnt/disks. Filesystem defaults to ext4 if null." + type = map(object({ + mount_name = string + filesystem = string + })) + default = {} +} + +variable "cloud_config" { + description = "Cloud config template path. If null default will be used." + type = string + default = null +} + +variable "config_variables" { + description = "Additional variables used to render the cloud-config template." + type = map(any) + default = {} +} + +variable "image" { + description = "MySQL container image." + type = string + default = "mysql:5.7" +} + +variable "kms_config" { + description = "Optional KMS configuration to decrypt passed-in password. Leave null if a plaintext password is used." + type = object({ + project_id = string + keyring = string + location = string + key = string + }) + default = null +} + +variable "mysql_config" { + description = "MySQL configuration file content, if null default will be used." + type = string + default = null +} + +variable "mysql_password" { + description = "MySQL root password. If an encrypted password is set, use the kms_config variable to specify KMS configuration." + type = string +} diff --git a/modules/cos-container/outputs-instance.tf b/modules/cos-container/outputs-instance.tf new file mode 100644 index 0000000000..0524baac2e --- /dev/null +++ b/modules/cos-container/outputs-instance.tf @@ -0,0 +1,24 @@ +/** + * Copyright 2020 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. + */ + +output "test_instance" { + description = "Optional test instance name and address" + value = (var.test_instance == null ? {} : { + address = google_compute_instance.default[0].network_interface.0.network_ip + name = google_compute_instance.default[0].name + service_account = google_service_account.default[0].email + }) +} diff --git a/modules/cos-container/variables-instance.tf b/modules/cos-container/variables-instance.tf new file mode 100644 index 0000000000..afd5cddcff --- /dev/null +++ b/modules/cos-container/variables-instance.tf @@ -0,0 +1,35 @@ +/** + * Copyright 2020 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 "test_instance" { + description = "Test/development instance attributes, leave null to skip creation." + type = object({ + project_id = string + zone = string + name = string + type = string + tags = list(string) + metadata = map(string) + network = string + subnetwork = string + disks = list(object({ + device_name = string + mode = string + source = string + })) + }) + default = null +} diff --git a/tests/conftest.py b/tests/conftest.py index 1bfedb180b..63e9716036 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -38,3 +38,19 @@ def run_plan(fixture_path, **tf_vars): ) return run_plan + + +@pytest.fixture(scope='session') +def apply_runner(): + "Returns a function to run Terraform apply on a fixture." + + def run_apply(fixture_path, **tf_vars): + "Runs Terraform apply and returns parsed output" + tf = tftest.TerraformTest(fixture_path, BASEDIR, + os.environ.get('TERRAFORM', 'terraform')) + tf.setup() + apply = tf.apply(tf_vars=tf_vars) + output = tf.output(json_format=True) + return (apply, output) + + return run_apply diff --git a/tests/modules/cos_container_coredns/__init__.py b/tests/modules/cos_container_coredns/__init__.py new file mode 100644 index 0000000000..6913f02e36 --- /dev/null +++ b/tests/modules/cos_container_coredns/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2020 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. diff --git a/tests/modules/cos_container_coredns/fixture/main.tf b/tests/modules/cos_container_coredns/fixture/main.tf new file mode 100644 index 0000000000..82f14f8b8d --- /dev/null +++ b/tests/modules/cos_container_coredns/fixture/main.tf @@ -0,0 +1,24 @@ +/** + * Copyright 2020 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 "test" { + source = "../../../../modules/cos-container/coredns" + cloud_config = var.cloud_config + config_variables = var.config_variables + coredns_config = var.coredns_config + file_defaults = var.file_defaults + files = var.files +} diff --git a/modules/compute-vm/variables-noncos.tf b/tests/modules/cos_container_coredns/fixture/outputs.tf similarity index 69% rename from modules/compute-vm/variables-noncos.tf rename to tests/modules/cos_container_coredns/fixture/outputs.tf index 248545cd58..3354b14a15 100644 --- a/modules/compute-vm/variables-noncos.tf +++ b/tests/modules/cos_container_coredns/fixture/outputs.tf @@ -14,16 +14,6 @@ * limitations under the License. */ -variable "boot_disk" { - description = "Boot disk properties." - type = object({ - image = string - size = number - type = string - }) - default = { - image = "projects/debian-cloud/global/images/family/debian-10" - type = "pd-ssd" - size = 10 - } +output "cloud_config" { + value = module.test.cloud_config } diff --git a/tests/modules/cos_container_coredns/fixture/variables.tf b/tests/modules/cos_container_coredns/fixture/variables.tf new file mode 100644 index 0000000000..d291be3aa7 --- /dev/null +++ b/tests/modules/cos_container_coredns/fixture/variables.tf @@ -0,0 +1,50 @@ +/** + * Copyright 2019 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 "cloud_config" { + type = string + default = null +} + +variable "config_variables" { + type = map(any) + default = {} +} + +variable "coredns_config" { + type = string + default = null +} + +variable "file_defaults" { + type = object({ + owner = string + permissions = string + }) + default = { + owner = "root" + permissions = "0644" + } +} + +variable "files" { + type = map(object({ + content = string + owner = string + permissions = string + })) + default = {} +} diff --git a/tests/modules/cos_container_coredns/test_apply.py b/tests/modules/cos_container_coredns/test_apply.py new file mode 100644 index 0000000000..b36ff1b875 --- /dev/null +++ b/tests/modules/cos_container_coredns/test_apply.py @@ -0,0 +1,32 @@ +# Copyright 2020 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. + + +import os +import pytest +import re + + +FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture') + + +def test_defaults(apply_runner): + "Test defalt configuration." + _, output = apply_runner(FIXTURES_DIR) + cloud_config = output['cloud_config'] + assert cloud_config.startswith('#cloud-config') + assert re.findall(r'(?m)^\s+\-\s*path:\s*(\S+)', cloud_config) == [ + '/var/lib/docker/daemon.json', '/etc/systemd/resolved.conf', + '/etc/coredns/Corefile', '/etc/systemd/system/coredns.service' + ] diff --git a/tools/tfdoc/tfdoc.py b/tools/tfdoc/tfdoc.py index b6466c4102..1e3fbf2c82 100755 --- a/tools/tfdoc/tfdoc.py +++ b/tools/tfdoc/tfdoc.py @@ -244,12 +244,14 @@ def main(module=None, replace=True): try: variables = [] for path in glob.glob(os.path.join(module, 'variables*tf')): - with open(os.path.join(module, path)) as file: + with open(path) as file: variables += [v for v in parse_items( file.read(), RE_VARIABLES, VariableToken, Variable, VariableData)] - with open(os.path.join(module, 'outputs.tf')) as file: - outputs = [o for o in parse_items( - file.read(), RE_OUTPUTS, OutputToken, Output, OutputData)] + outputs = [] + for path in glob.glob(os.path.join(module, 'outputs*tf')): + with open(path) as file: + outputs += [o for o in parse_items( + file.read(), RE_OUTPUTS, OutputToken, Output, OutputData)] except (IOError, OSError) as e: raise SystemExit(e) doc = get_doc(variables, outputs)