Merge branch 'master' into maunope/network-dashboards-updates
This commit is contained in:
commit
8d39ded6d6
|
@ -0,0 +1,28 @@
|
|||
# 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.
|
||||
FROM marketplace.gcr.io/google/debian11
|
||||
|
||||
RUN apt-get update && apt-get dist-upgrade -y && apt-get install -y curl gnupg2
|
||||
RUN curl -sSO https://dl.google.com/cloudagents/add-google-cloud-ops-agent-repo.sh
|
||||
RUN bash add-google-cloud-ops-agent-repo.sh --also-install
|
||||
RUN rm -f add-google-cloud-ops-agent-repo.sh
|
||||
|
||||
RUN echo '#!/bin/bash' > /entrypoint.sh
|
||||
RUN echo 'cd /tmp' >> /entrypoint.sh
|
||||
RUN echo '/opt/google-cloud-ops-agent/libexec/google_cloud_ops_agent_engine -service=otel -in /etc/google-cloud-ops-agent/config.yaml' >> /entrypoint.sh
|
||||
RUN echo '/opt/google-cloud-ops-agent/subagents/opentelemetry-collector/otelopscol --config=/tmp/otel.yaml --feature-gates=exporter.googlecloud.OTLPDirect' >> /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
ENTRYPOINT /entrypoint.sh
|
||||
CMD []
|
|
@ -0,0 +1,45 @@
|
|||
# Nginx-based reverse proxy cluster
|
||||
|
||||
This blueprint shows how to deploy an autoscaling reverse proxy cluster using Nginx, based on regional
|
||||
Managed Instance Groups.
|
||||
|
||||
![High-level diagram](reverse-proxy.png "High-level diagram")
|
||||
|
||||
The autoscaling is driven by Nginx current connections metric, sent by Cloud Ops Agent.
|
||||
|
||||
The example is for Nginx, but it could be easily adapted to any other reverse proxy software (eg.
|
||||
Squid, Varnish, etc).
|
||||
|
||||
## Ops Agent image
|
||||
|
||||
There is a simple [`Dockerfile`](Dockerfile) available for building Ops Agent to be run
|
||||
inside the ContainerOS instance. Build the container, push it to your Container/Artifact
|
||||
Repository and set the `ops_agent_image` to point to the image you built.
|
||||
<!-- BEGIN TFDOC -->
|
||||
|
||||
## Variables
|
||||
|
||||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [autoscaling_metric](variables.tf#L31) | | <code title="object({ name = string single_instance_assignment = number target = number type = string # GAUGE, DELTA_PER_SECOND, DELTA_PER_MINUTE filter = string }) default = { name = "workload.googleapis.com/nginx.connections_current" single_instance_assignment = null target = 10 # Target 10 connections per instance, just for demonstration purposes type = "GAUGE" filter = null }">object({…}</code> | ✓ | |
|
||||
| [project_name](variables.tf#L106) | Name of an existing project or of the new project | <code>string</code> | ✓ | |
|
||||
| [autoscaling](variables.tf#L17) | Autoscaling configuration for the instance group. | <code title="object({ min_replicas = number max_replicas = number cooldown_period = number })">object({…})</code> | | <code title="{ min_replicas = 1 max_replicas = 10 cooldown_period = 30 }">{…}</code> |
|
||||
| [backends](variables.tf#L49) | Nginx locations configurations to proxy traffic to. | <code>string</code> | | <code title=""<<-EOT location / { proxy_pass http://10.0.16.13:80; } EOT"">"<<-EOT…EOT"</code> |
|
||||
| [cidrs](variables.tf#L59) | Subnet IP CIDR ranges. | <code>map(string)</code> | | <code title="{ gce = "10.0.16.0/24" }">{…}</code> |
|
||||
| [network](variables.tf#L67) | Network name. | <code>string</code> | | <code>"reverse-proxy-vpc"</code> |
|
||||
| [network_create](variables.tf#L73) | Create network or use existing one. | <code>bool</code> | | <code>true</code> |
|
||||
| [nginx_image](variables.tf#L79) | Nginx container image to use. | <code>string</code> | | <code>"gcr.io/cloud-marketplace/google/nginx1:latest"</code> |
|
||||
| [ops_agent_image](variables.tf#L85) | Google Cloud Ops Agent container image to use. | <code>string</code> | | <code>"gcr.io/sfans-hub-project-d647/ops-agent:latest"</code> |
|
||||
| [prefix](variables.tf#L91) | Prefix used for resources that need unique names. | <code>string</code> | | <code>""</code> |
|
||||
| [project_create](variables.tf#L97) | Parameters for the creation of the new project | <code title="object({ billing_account_id = string parent = string })">object({…})</code> | | <code>null</code> |
|
||||
| [region](variables.tf#L111) | Default region for resources. | <code>string</code> | | <code>"europe-west4"</code> |
|
||||
| [subnetwork](variables.tf#L117) | Subnetwork name. | <code>string</code> | | <code>"gce"</code> |
|
||||
| [tls](variables.tf#L123) | Also offer reverse proxying with TLS (self-signed certificate). | <code>bool</code> | | <code>false</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
| name | description | sensitive |
|
||||
|---|---|:---:|
|
||||
| [load_balancer_url](outputs.tf#L17) | Load balancer for the reverse proxy instance group. | |
|
||||
|
||||
<!-- END TFDOC -->
|
|
@ -0,0 +1,403 @@
|
|||
/**
|
||||
* 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 {
|
||||
monitoring_agent_unit = <<-EOT
|
||||
[Unit]
|
||||
Description=Start monitoring agent container
|
||||
After=gcr-online.target docker.socket
|
||||
Wants=gcr-online.target docker.socket docker-events-collector.service
|
||||
|
||||
[Service]
|
||||
Environment="HOME=/home/opsagent"
|
||||
ExecStartPre=/usr/bin/docker-credential-gcr configure-docker
|
||||
ExecStart=/usr/bin/docker run --rm --name=monitoring-agent \
|
||||
--log-driver=gcplogs \
|
||||
--network host \
|
||||
-v /etc/google-cloud-ops-agent/config.yaml:/etc/google-cloud-ops-agent/config.yaml \
|
||||
${var.ops_agent_image}
|
||||
ExecStop=/usr/bin/docker stop monitoring-agent
|
||||
EOT
|
||||
monitoring_agent_config = <<-EOT
|
||||
logging:
|
||||
service:
|
||||
pipelines:
|
||||
default_pipeline:
|
||||
receivers: []
|
||||
metrics:
|
||||
receivers:
|
||||
hostmetrics:
|
||||
type: hostmetrics
|
||||
nginx:
|
||||
type: nginx
|
||||
collection_interval: 10s
|
||||
stub_status_url: http://localhost/healthz
|
||||
service:
|
||||
pipelines:
|
||||
default_pipeline:
|
||||
receivers:
|
||||
- hostmetrics
|
||||
- nginx
|
||||
EOT
|
||||
nginx_config = <<-EOT
|
||||
server {
|
||||
listen 80;
|
||||
server_name HOSTNAME localhost;
|
||||
%{if var.tls}
|
||||
listen 443 ssl;
|
||||
ssl_certificate /etc/ssl/self-signed.crt;
|
||||
ssl_certificate_key /etc/ssl/self-signed.key;
|
||||
%{endif}
|
||||
|
||||
keepalive_timeout 650s;
|
||||
keepalive_requests 10000;
|
||||
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_read_timeout 5m;
|
||||
proxy_send_timeout 5m;
|
||||
|
||||
error_log stderr;
|
||||
access_log /dev/stdout combined;
|
||||
|
||||
set_real_ip_from ${module.xlb.ip_address}/32;
|
||||
set_real_ip_from 35.191.0.0/16;
|
||||
set_real_ip_from 130.211.0.0/22;
|
||||
real_ip_header X-Forwarded-For;
|
||||
real_ip_recursive off;
|
||||
|
||||
location /healthz {
|
||||
stub_status on;
|
||||
access_log off;
|
||||
allow 127.0.0.1;
|
||||
allow 35.191.0.0/16;
|
||||
allow 130.211.0.0/22;
|
||||
deny all;
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
|
||||
${var.backends}
|
||||
}
|
||||
EOT
|
||||
nginx_files = {
|
||||
"/etc/systemd/system/monitoring-agent.service" = {
|
||||
content = local.monitoring_agent_unit
|
||||
owner = "root"
|
||||
permissions = "0644"
|
||||
}
|
||||
"/etc/nginx/conf.d/default.conf" = {
|
||||
content = local.nginx_config
|
||||
owner = "root"
|
||||
permissions = "0644"
|
||||
}
|
||||
"/etc/google-cloud-ops-agent/config.yaml" = {
|
||||
content = local.monitoring_agent_config
|
||||
owner = "root"
|
||||
permissions = "0644"
|
||||
}
|
||||
}
|
||||
users = [
|
||||
{
|
||||
username = "opsagent"
|
||||
uid = 2001
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
module "project" {
|
||||
source = "../../../modules/project"
|
||||
billing_account = (var.project_create != null
|
||||
? var.project_create.billing_account_id
|
||||
: null
|
||||
)
|
||||
name = var.project_name
|
||||
parent = (var.project_create != null
|
||||
? var.project_create.parent
|
||||
: null
|
||||
)
|
||||
|
||||
services = [
|
||||
"cloudresourcemanager.googleapis.com",
|
||||
"compute.googleapis.com",
|
||||
"iam.googleapis.com",
|
||||
"logging.googleapis.com",
|
||||
"monitoring.googleapis.com",
|
||||
]
|
||||
|
||||
project_create = var.project_create != null
|
||||
}
|
||||
|
||||
module "vpc" {
|
||||
source = "../../../modules/net-vpc"
|
||||
project_id = module.project.project_id
|
||||
name = var.network
|
||||
subnets = [
|
||||
{
|
||||
name = var.subnetwork
|
||||
ip_cidr_range = var.cidrs[var.subnetwork]
|
||||
region = var.region
|
||||
secondary_ip_range = null
|
||||
},
|
||||
]
|
||||
|
||||
vpc_create = var.network_create
|
||||
}
|
||||
|
||||
module "firewall" {
|
||||
source = "../../../modules/net-vpc-firewall"
|
||||
project_id = module.project.project_id
|
||||
network = module.vpc.name
|
||||
custom_rules = {
|
||||
format("%sallow-http-to-proxy-cluster", var.prefix) = {
|
||||
description = "Allow Nginx HTTP(S) ingress traffic"
|
||||
direction = "INGRESS"
|
||||
action = "allow"
|
||||
sources = []
|
||||
ranges = [var.cidrs[var.subnetwork], "35.191.0.0/16", "130.211.0.0/22"]
|
||||
targets = [module.service-account-proxy.email]
|
||||
use_service_accounts = true
|
||||
rules = [{ protocol = "tcp", ports = [80, 443] }]
|
||||
extra_attributes = {}
|
||||
}
|
||||
format("%sallow-iap-ssh", var.prefix) = {
|
||||
description = "Allow Nginx SSH traffic from IAP"
|
||||
direction = "INGRESS"
|
||||
action = "allow"
|
||||
sources = []
|
||||
ranges = ["35.235.240.0/20"]
|
||||
targets = [module.service-account-proxy.email]
|
||||
use_service_accounts = true
|
||||
rules = [{ protocol = "tcp", ports = [22] }]
|
||||
extra_attributes = {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module "nat" {
|
||||
source = "../../../modules/net-cloudnat"
|
||||
project_id = module.project.project_id
|
||||
region = var.region
|
||||
name = format("%snat", var.prefix)
|
||||
router_network = module.vpc.name
|
||||
config_source_subnets = "LIST_OF_SUBNETWORKS"
|
||||
|
||||
logging_filter = "ALL"
|
||||
|
||||
config_min_ports_per_vm = 4000
|
||||
subnetworks = [
|
||||
{
|
||||
self_link = module.vpc.subnet_self_links[format("%s/%s", var.region, var.subnetwork)]
|
||||
config_source_ranges = ["ALL_IP_RANGES"]
|
||||
secondary_ranges = null
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Proxy resources #
|
||||
###############################################################################
|
||||
|
||||
module "service-account-proxy" {
|
||||
source = "../../../modules/iam-service-account"
|
||||
project_id = module.project.project_id
|
||||
name = format("%sreverse-proxy", var.prefix)
|
||||
iam_project_roles = {
|
||||
(module.project.project_id) = [
|
||||
"roles/logging.logWriter",
|
||||
"roles/monitoring.metricWriter",
|
||||
"roles/storage.objectViewer", // For pulling the Ops Agent image
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
module "cos-nginx" {
|
||||
count = !var.tls ? 1 : 0
|
||||
source = "../../../modules/cloud-config-container/nginx"
|
||||
|
||||
image = var.nginx_image
|
||||
files = local.nginx_files
|
||||
users = local.users
|
||||
|
||||
runcmd_pre = ["sed -i \"s/HOSTNAME/$${HOSTNAME}/\" /etc/nginx/conf.d/default.conf"]
|
||||
runcmd_post = ["systemctl start monitoring-agent"]
|
||||
}
|
||||
|
||||
module "cos-nginx-tls" {
|
||||
count = var.tls ? 1 : 0
|
||||
source = "../../../modules/cloud-config-container/nginx-tls"
|
||||
|
||||
nginx_image = var.nginx_image
|
||||
files = local.nginx_files
|
||||
users = local.users
|
||||
|
||||
runcmd_post = ["systemctl start monitoring-agent"]
|
||||
}
|
||||
|
||||
module "mig-proxy" {
|
||||
source = "../../../modules/compute-mig"
|
||||
project_id = module.project.project_id
|
||||
|
||||
location = var.region
|
||||
regional = true
|
||||
|
||||
name = format("%sproxy-cluster", var.prefix)
|
||||
|
||||
named_ports = {
|
||||
http = "80"
|
||||
https = "443"
|
||||
}
|
||||
|
||||
autoscaler_config = var.autoscaling == null ? null : {
|
||||
min_replicas = var.autoscaling.min_replicas
|
||||
max_replicas = var.autoscaling.max_replicas
|
||||
cooldown_period = var.autoscaling.cooldown_period
|
||||
cpu_utilization_target = null
|
||||
load_balancing_utilization_target = null
|
||||
metric = var.autoscaling_metric
|
||||
}
|
||||
|
||||
update_policy = {
|
||||
type = "PROACTIVE"
|
||||
minimal_action = "REPLACE"
|
||||
min_ready_sec = 60
|
||||
max_surge_type = "fixed"
|
||||
max_surge = 3
|
||||
max_unavailable_type = null
|
||||
max_unavailable = null
|
||||
}
|
||||
|
||||
default_version = {
|
||||
instance_template = module.proxy-vm.template.self_link
|
||||
name = "proxy-vm"
|
||||
}
|
||||
|
||||
health_check_config = {
|
||||
type = "http"
|
||||
check = {
|
||||
port = 80
|
||||
request_path = "/healthz"
|
||||
}
|
||||
config = {
|
||||
check_interval_sec = 10
|
||||
healthy_threshold = 1
|
||||
unhealthy_threshold = 1
|
||||
timeout_sec = 10
|
||||
}
|
||||
logging = true
|
||||
}
|
||||
auto_healing_policies = {
|
||||
health_check = module.mig-proxy.health_check.self_link
|
||||
initial_delay_sec = 60
|
||||
}
|
||||
}
|
||||
|
||||
module "proxy-vm" {
|
||||
source = "../../../modules/compute-vm"
|
||||
|
||||
project_id = module.project.project_id
|
||||
|
||||
zone = format("%s-c", var.region)
|
||||
name = "nginx-test-vm"
|
||||
|
||||
instance_type = "e2-standard-2"
|
||||
|
||||
tags = ["proxy-cluster"]
|
||||
network_interfaces = [{
|
||||
network = module.vpc.self_link
|
||||
subnetwork = module.vpc.subnet_self_links[format("%s/%s", var.region, var.subnetwork)]
|
||||
nat = false
|
||||
addresses = null
|
||||
}]
|
||||
|
||||
boot_disk = {
|
||||
image = "projects/cos-cloud/global/images/family/cos-stable"
|
||||
type = "pd-ssd"
|
||||
size = 10
|
||||
}
|
||||
|
||||
create_template = true
|
||||
metadata = {
|
||||
user-data = !var.tls ? module.cos-nginx.0.cloud_config : module.cos-nginx-tls.0.cloud_config
|
||||
}
|
||||
|
||||
service_account = module.service-account-proxy.email
|
||||
service_account_create = false
|
||||
}
|
||||
|
||||
module "xlb" {
|
||||
source = "../../../modules/net-glb"
|
||||
name = format("%sreverse-proxy-xlb", var.prefix)
|
||||
project_id = module.project.project_id
|
||||
|
||||
reserve_ip_address = true
|
||||
|
||||
health_checks_config = {
|
||||
format("%sreverse-proxy-hc", var.prefix) = {
|
||||
type = "http"
|
||||
logging = false
|
||||
options = {
|
||||
check_interval_sec = 10
|
||||
healthy_threshold = 1
|
||||
unhealthy_threshold = 1
|
||||
timeout_sec = 10
|
||||
}
|
||||
check = {
|
||||
port_specification = "USE_NAMED_PORT"
|
||||
port_name = "http"
|
||||
request_path = "/healthz"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
backend_services_config = {
|
||||
format("%sreverse-proxy-backend", var.prefix) = {
|
||||
bucket_config = null
|
||||
enable_cdn = false
|
||||
cdn_config = null
|
||||
|
||||
group_config = {
|
||||
backends = [
|
||||
{
|
||||
group = module.mig-proxy.group_manager.instance_group
|
||||
options = null
|
||||
}
|
||||
]
|
||||
|
||||
health_checks = [format("%sreverse-proxy-hc", var.prefix)]
|
||||
log_config = null
|
||||
options = {
|
||||
affinity_cookie_ttl_sec = null
|
||||
custom_request_headers = null
|
||||
custom_response_headers = null
|
||||
connection_draining_timeout_sec = null
|
||||
load_balancing_scheme = null
|
||||
locality_lb_policy = null
|
||||
port_name = !var.tls ? "http" : "https"
|
||||
protocol = !var.tls ? "HTTP" : "HTTPS"
|
||||
security_policy = null
|
||||
session_affinity = null
|
||||
timeout_sec = null
|
||||
circuits_breakers = null
|
||||
consistent_hash = null
|
||||
iap = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
output "load_balancer_url" {
|
||||
description = "Load balancer for the reverse proxy instance group."
|
||||
value = !var.tls ? format("http://%s/", module.xlb.ip_address) : format("https://%s/", module.xlb.ip_address)
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 105 KiB |
|
@ -0,0 +1,130 @@
|
|||
/**
|
||||
* 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 "autoscaling" {
|
||||
description = "Autoscaling configuration for the instance group."
|
||||
type = object({
|
||||
min_replicas = number
|
||||
max_replicas = number
|
||||
cooldown_period = number
|
||||
})
|
||||
default = {
|
||||
min_replicas = 1
|
||||
max_replicas = 10
|
||||
cooldown_period = 30
|
||||
}
|
||||
}
|
||||
|
||||
variable "autoscaling_metric" {
|
||||
type = object({
|
||||
name = string
|
||||
single_instance_assignment = number
|
||||
target = number
|
||||
type = string # GAUGE, DELTA_PER_SECOND, DELTA_PER_MINUTE
|
||||
filter = string
|
||||
})
|
||||
|
||||
default = {
|
||||
name = "workload.googleapis.com/nginx.connections_current"
|
||||
single_instance_assignment = null
|
||||
target = 10 # Target 10 connections per instance, just for demonstration purposes
|
||||
type = "GAUGE"
|
||||
filter = null
|
||||
}
|
||||
}
|
||||
|
||||
variable "backends" {
|
||||
description = "Nginx locations configurations to proxy traffic to."
|
||||
type = string
|
||||
default = <<-EOT
|
||||
location / {
|
||||
proxy_pass http://10.0.16.58:80;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection "";
|
||||
}
|
||||
EOT
|
||||
}
|
||||
|
||||
variable "cidrs" {
|
||||
description = "Subnet IP CIDR ranges."
|
||||
type = map(string)
|
||||
default = {
|
||||
gce = "10.0.16.0/24"
|
||||
}
|
||||
}
|
||||
|
||||
variable "network" {
|
||||
description = "Network name."
|
||||
type = string
|
||||
default = "reverse-proxy-vpc"
|
||||
}
|
||||
|
||||
variable "network_create" {
|
||||
description = "Create network or use existing one."
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "nginx_image" {
|
||||
description = "Nginx container image to use."
|
||||
type = string
|
||||
default = "gcr.io/cloud-marketplace/google/nginx1:latest"
|
||||
}
|
||||
|
||||
variable "ops_agent_image" {
|
||||
description = "Google Cloud Ops Agent container image to use."
|
||||
type = string
|
||||
default = "gcr.io/sfans-hub-project-d647/ops-agent:latest"
|
||||
}
|
||||
|
||||
variable "prefix" {
|
||||
description = "Prefix used for resources that need unique names."
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "project_create" {
|
||||
description = "Parameters for the creation of the new project"
|
||||
type = object({
|
||||
billing_account_id = string
|
||||
parent = string
|
||||
})
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "project_name" {
|
||||
description = "Name of an existing project or of the new project"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "region" {
|
||||
description = "Default region for resources."
|
||||
type = string
|
||||
default = "europe-west4"
|
||||
}
|
||||
|
||||
variable "subnetwork" {
|
||||
description = "Subnetwork name."
|
||||
type = string
|
||||
default = "gce"
|
||||
}
|
||||
|
||||
variable "tls" {
|
||||
description = "Also offer reverse proxying with TLS (self-signed certificate)."
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
# 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.
|
||||
|
||||
terraform {
|
||||
required_version = ">= 1.3.0"
|
||||
required_providers {
|
||||
google = {
|
||||
source = "hashicorp/google"
|
||||
version = ">= 4.32.0" # tftest
|
||||
}
|
||||
google-beta = {
|
||||
source = "hashicorp/google-beta"
|
||||
version = ">= 4.32.0" # tftest
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ module "cos-envoy" {
|
|||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [container_image](variables.tf#L42) | Container image. | <code>string</code> | ✓ | |
|
||||
| [authenticate_gcr](variables.tf#L118) | Setup docker to pull images from private GCR. Requires at least one user since the token is stored in the home of the first user defined. | <code>bool</code> | | <code>false</code> |
|
||||
| [authenticate_gcr](variables.tf#L124) | Setup docker to pull images from private GCR. Requires at least one user since the token is stored in the home of the first user defined. | <code>bool</code> | | <code>false</code> |
|
||||
| [boot_commands](variables.tf#L17) | List of cloud-init `bootcmd`s. | <code>list(string)</code> | | <code>[]</code> |
|
||||
| [cloud_config](variables.tf#L23) | Cloud config template path. If provided, takes precedence over all other arguments. | <code>string</code> | | <code>null</code> |
|
||||
| [config_variables](variables.tf#L29) | Additional variables used to render the template passed via `cloud_config`. | <code>map(any)</code> | | <code>{}</code> |
|
||||
|
@ -76,6 +76,7 @@ module "cos-envoy" {
|
|||
| [file_defaults](variables.tf#L74) | Default owner and permissions for files. | <code title="object({ owner = string permissions = string })">object({…})</code> | | <code title="{ owner = "root" permissions = "0644" }">{…}</code> |
|
||||
| [files](variables.tf#L86) | Map of extra files to create on the instance, path as key. Owner and permissions will use defaults if null. | <code title="map(object({ content = string owner = string permissions = string }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [gcp_logging](variables.tf#L96) | Should container logs be sent to Google Cloud Logging. | <code>bool</code> | | <code>true</code> |
|
||||
| [run_as_first_user](variables.tf#L118) | Run as the first user if users are specified. | <code>bool</code> | | <code>true</code> |
|
||||
| [run_commands](variables.tf#L102) | List of cloud-init `runcmd`s. | <code>list(string)</code> | | <code>[]</code> |
|
||||
| [users](variables.tf#L108) | List of usernames to be created. If provided, first user will be used to run the container. | <code title="list(object({ username = string, uid = number, }))">list(object({…}))</code> | | <code title="[ ]">[…]</code> |
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ write_files:
|
|||
ExecStartPre=/usr/bin/docker-credential-gcr configure-docker
|
||||
%{~ endif ~}
|
||||
ExecStart=/usr/bin/docker run --rm --name=${container_name} \
|
||||
%{~ if length(users) > 0 ~}
|
||||
%{~ if length(users) > 0 && run_as_first_user ~}
|
||||
--user=${users[0].uid} \
|
||||
%{~ endif ~}
|
||||
%{~ if docker_logging ~}
|
||||
|
|
|
@ -28,6 +28,7 @@ locals {
|
|||
run_commands = var.run_commands
|
||||
users = var.users
|
||||
authenticate_gcr = var.authenticate_gcr
|
||||
run_as_first_user = var.run_as_first_user
|
||||
}))
|
||||
files = {
|
||||
for path, attrs in var.files : path => {
|
||||
|
|
|
@ -115,6 +115,12 @@ variable "users" {
|
|||
]
|
||||
}
|
||||
|
||||
variable "run_as_first_user" {
|
||||
description = "Run as the first user if users are specified."
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "authenticate_gcr" {
|
||||
description = "Setup docker to pull images from private GCR. Requires at least one user since the token is stored in the home of the first user defined."
|
||||
type = bool
|
||||
|
|
|
@ -50,7 +50,11 @@ module "vm-nginx-tls" {
|
|||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [docker_logging](variables.tf#L23) | Log via the Docker gcplogs driver. Disable if you use the legacy Logging Agent instead. | <code>bool</code> | | <code>true</code> |
|
||||
| [files](variables.tf#L41) | Map of extra files to create on the instance, path as key. Owner and permissions will use defaults if null. | <code title="map(object({ content = string owner = string permissions = string }))">map(object({…}))</code> | | <code>null</code> |
|
||||
| [nginx_image](variables.tf#L17) | Nginx container image to use. | <code>string</code> | | <code>"nginx:1.23.1"</code> |
|
||||
| [runcmd_post](variables.tf#L35) | Extra commands to run after starting nginx. | <code>list(string)</code> | | <code>[]</code> |
|
||||
| [runcmd_pre](variables.tf#L29) | Extra commands to run before starting nginx. | <code>list(string)</code> | | <code>[]</code> |
|
||||
| [users](variables.tf#L51) | Additional list of usernames to be created. | <code title="list(object({ username = string, uid = number, }))">list(object({…}))</code> | | <code title="[ ]">[…]</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
|
|
@ -16,4 +16,5 @@
|
|||
FQDN=$(curl -s -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/hostname)
|
||||
HOSTNAME=$(echo $FQDN | cut -d"." -f1)
|
||||
openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 -subj /CN=$HOSTNAME/ -addext "subjectAltName = DNS:$FQDN" -keyout /etc/ssl/self-signed.key -out /etc/ssl/self-signed.crt
|
||||
chgrp nginx /etc/ssl/self-signed.key -out /etc/ssl/self-signed.crt
|
||||
sed -i "s/HOSTNAME/${HOSTNAME}/" /etc/nginx/conf.d/default.conf
|
|
@ -14,9 +14,34 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
locals {
|
||||
default_files = {
|
||||
"/var/run/nginx/customize.sh" = {
|
||||
content = file("${path.module}/files/customize.sh")
|
||||
owner = "root"
|
||||
permissions = "0744"
|
||||
}
|
||||
"/etc/nginx/conf.d/default.conf" = {
|
||||
content = file("${path.module}/files/default.conf")
|
||||
owner = "root"
|
||||
permissions = "0644"
|
||||
}
|
||||
}
|
||||
files = var.files != null ? merge(local.default_files, var.files) : local.default_files
|
||||
}
|
||||
|
||||
module "cos-envoy-td" {
|
||||
source = "../cos-generic-metadata"
|
||||
|
||||
authenticate_gcr = true
|
||||
users = concat([
|
||||
{
|
||||
username = "nginx"
|
||||
uid = 2000
|
||||
}
|
||||
], var.users)
|
||||
run_as_first_user = false
|
||||
|
||||
boot_commands = [
|
||||
"systemctl start node-problem-detector",
|
||||
]
|
||||
|
@ -32,27 +57,16 @@ module "cos-envoy-td" {
|
|||
|
||||
docker_args = "--network host --pid host"
|
||||
|
||||
files = {
|
||||
"/var/run/nginx/customize.sh" = {
|
||||
content = file("${path.module}/files/customize.sh")
|
||||
owner = "root"
|
||||
permissions = "0744"
|
||||
}
|
||||
"/etc/nginx/conf.d/default.conf" = {
|
||||
content = file("${path.module}/files/default.conf")
|
||||
owner = "root"
|
||||
permissions = "0644"
|
||||
}
|
||||
}
|
||||
files = local.files
|
||||
|
||||
gcp_logging = var.docker_logging
|
||||
|
||||
run_commands = [
|
||||
run_commands = concat(var.runcmd_pre, [
|
||||
"iptables -I INPUT 1 -p tcp -m tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT",
|
||||
"iptables -I INPUT 1 -p tcp -m tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT",
|
||||
"/var/run/nginx/customize.sh",
|
||||
"systemctl daemon-reload",
|
||||
"systemctl start nginx",
|
||||
]
|
||||
], var.runcmd_post)
|
||||
|
||||
}
|
||||
|
|
|
@ -25,3 +25,37 @@ variable "docker_logging" {
|
|||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "runcmd_pre" {
|
||||
description = "Extra commands to run before starting nginx."
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "runcmd_post" {
|
||||
description = "Extra commands to run after starting nginx."
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
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 = null
|
||||
}
|
||||
|
||||
variable "users" {
|
||||
description = "Additional list of usernames to be created."
|
||||
type = list(object({
|
||||
username = string,
|
||||
uid = number,
|
||||
}))
|
||||
default = [
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -64,8 +64,11 @@ module "cos-nginx" {
|
|||
| [files](variables.tf#L59) | Map of extra files to create on the instance, path as key. Owner and permissions will use defaults if null. | <code title="map(object({ content = string owner = string permissions = string }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [image](variables.tf#L35) | Nginx container image. | <code>string</code> | | <code>"nginxdemos/hello:plain-text"</code> |
|
||||
| [nginx_config](variables.tf#L41) | Nginx configuration path, if null container default will be used. | <code>string</code> | | <code>null</code> |
|
||||
| [runcmd_post](variables.tf#L75) | Extra commands to run after starting nginx. | <code>list(string)</code> | | <code>[]</code> |
|
||||
| [runcmd_pre](variables.tf#L69) | Extra commands to run before starting nginx. | <code>list(string)</code> | | <code>[]</code> |
|
||||
| [test_instance](variables-instance.tf#L17) | Test/development instance attributes, leave null to skip creation. | <code title="object({ project_id = string zone = string name = string type = string network = string subnetwork = string })">object({…})</code> | | <code>null</code> |
|
||||
| [test_instance_defaults](variables-instance.tf#L30) | Test/development instance defaults used for optional configuration. If image is null, COS stable will be used. | <code title="object({ disks = map(object({ read_only = bool size = number })) image = string metadata = map(string) nat = bool service_account_roles = list(string) tags = list(string) })">object({…})</code> | | <code title="{ disks = {} image = null metadata = {} nat = false service_account_roles = [ "roles/logging.logWriter", "roles/monitoring.metricWriter" ] tags = ["ssh"] }">{…}</code> |
|
||||
| [users](variables.tf#L81) | List of additional usernames to be created. | <code title="list(object({ username = string, uid = number, }))">list(object({…}))</code> | | <code title="[ ]">[…]</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
users:
|
||||
- name: nginx
|
||||
uid: 2000
|
||||
%{ for user in users }
|
||||
- name: ${user.username}
|
||||
uid: ${user.uid}
|
||||
%{ endfor }
|
||||
|
||||
write_files:
|
||||
- path: /var/lib/docker/daemon.json
|
||||
|
@ -52,6 +56,8 @@ write_files:
|
|||
After=gcr-online.target docker.socket
|
||||
Wants=gcr-online.target docker.socket docker-events-collector.service
|
||||
[Service]
|
||||
Environment="HOME=/home/nginx"
|
||||
ExecStartPre=/usr/bin/docker-credential-gcr configure-docker
|
||||
ExecStart=/usr/bin/docker run --rm --name=nginx \
|
||||
%{~ if docker_logging ~}
|
||||
--log-driver=gcplogs \
|
||||
|
@ -68,13 +74,19 @@ write_files:
|
|||
owner: ${lookup(data, "owner", "root")}
|
||||
permissions: ${lookup(data, "permissions", "0644")}
|
||||
content: |
|
||||
${indent(4, data.content)}
|
||||
${indent(6, data.content)}
|
||||
%{ endfor }
|
||||
|
||||
bootcmd:
|
||||
- systemctl start node-problem-detector
|
||||
|
||||
runcmd:
|
||||
%{ for cmd in runcmd_pre ~}
|
||||
- ${cmd}
|
||||
%{ endfor ~}
|
||||
- iptables -I INPUT 1 -p tcp -m tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
|
||||
- systemctl daemon-reload
|
||||
- systemctl start nginx
|
||||
%{ for cmd in runcmd_post ~}
|
||||
- ${cmd}
|
||||
%{ endfor ~}
|
||||
|
|
|
@ -21,13 +21,16 @@ locals {
|
|||
var.nginx_config != null || length([
|
||||
for name in keys(var.files) :
|
||||
name if substr(name, 0, 18) == "/etc/nginx/conf.d/"
|
||||
]) > 1
|
||||
]) > 0
|
||||
)
|
||||
files = local.files
|
||||
users = var.users
|
||||
image = var.image
|
||||
nginx_config = (var.nginx_config == null ? null : templatefile(
|
||||
var.nginx_config, var.config_variables
|
||||
))
|
||||
runcmd_pre = var.runcmd_pre
|
||||
runcmd_post = var.runcmd_post
|
||||
}))
|
||||
files = {
|
||||
for path, attrs in var.files : path => {
|
||||
|
|
|
@ -65,3 +65,25 @@ variable "files" {
|
|||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "runcmd_pre" {
|
||||
description = "Extra commands to run before starting nginx."
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "runcmd_post" {
|
||||
description = "Extra commands to run after starting nginx."
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "users" {
|
||||
description = "List of additional usernames to be created."
|
||||
type = list(object({
|
||||
username = string,
|
||||
uid = number,
|
||||
}))
|
||||
default = [
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue