HardПрактика3 min

Deployment Manager и Terraform

Deployment Manager, Terraform для GCP и Pulumi как альтернативы IaC на Google Cloud

IaC-инструменты для GCP

Инструмент Тип Статус Рекомендация
Deployment Manager GCP native, YAML Legacy Не для новых проектов
Terraform Мультиклауд, HCL Активный Рекомендуется
Pulumi Мультиклауд, Python/TS Активный Хорошая альтернатива
Config Connector Kubernetes CRD Активный Для GKE-окружений

Google рекомендует Terraform вместо Deployment Manager для новых проектов.

Terraform для GCP CRC

Полный конфиг

# main.tf
terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 5.0"
    }
  }
}

provider "google" {
  project = var.project_id
  region  = var.region
}

variable "project_id" {
  description = "GCP Project ID"
  type        = string
}

variable "region" {
  default = "us-central1"
}

# ========== STORAGE (Frontend) ==========

resource "google_storage_bucket" "frontend" {
  name     = "${var.project_id}-resume"
  location = var.region

  website {
    main_page_suffix = "index.html"
    not_found_page   = "error.html"
  }

  uniform_bucket_level_access = true

  cors {
    origin          = ["*"]
    method          = ["GET"]
    response_header = ["Content-Type"]
    max_age_seconds = 86400
  }
}

resource "google_storage_bucket_iam_member" "public_read" {
  bucket = google_storage_bucket.frontend.name
  role   = "roles/storage.objectViewer"
  member = "allUsers"
}

# ========== FIRESTORE ==========

resource "google_firestore_database" "default" {
  project     = var.project_id
  name        = "(default)"
  location_id = var.region
  type        = "FIRESTORE_NATIVE"
}

# ========== CLOUD FUNCTION ==========

resource "google_storage_bucket" "function_source" {
  name     = "${var.project_id}-function-source"
  location = var.region
}

data "archive_file" "function_zip" {
  type        = "zip"
  source_dir  = "${path.module}/backend/"
  output_path = "${path.module}/function.zip"
}

resource "google_storage_bucket_object" "function_source" {
  name   = "function-${data.archive_file.function_zip.output_md5}.zip"
  bucket = google_storage_bucket.function_source.name
  source = data.archive_file.function_zip.output_path
}

resource "google_cloudfunctions2_function" "visitor_counter" {
  name     = "visitor-counter"
  location = var.region

  build_config {
    runtime     = "python312"
    entry_point = "visitor_counter"
    source {
      storage_source {
        bucket = google_storage_bucket.function_source.name
        object = google_storage_bucket_object.function_source.name
      }
    }
  }

  service_config {
    max_instance_count = 10
    min_instance_count = 0
    available_memory   = "128Mi"
    timeout_seconds    = 60

    environment_variables = {
      PROJECT_ID = var.project_id
    }
  }
}

# Allow unauthenticated access
resource "google_cloud_run_v2_service_iam_member" "invoker" {
  project  = google_cloudfunctions2_function.visitor_counter.project
  location = google_cloudfunctions2_function.visitor_counter.location
  name     = google_cloudfunctions2_function.visitor_counter.name
  role     = "roles/run.invoker"
  member   = "allUsers"
}

# ========== OUTPUTS ==========

output "function_url" {
  value = google_cloudfunctions2_function.visitor_counter.service_config[0].uri
}

output "frontend_url" {
  value = "https://storage.googleapis.com/${google_storage_bucket.frontend.name}/index.html"
}

Деплой

# Инициализация
terraform init

# Preview
terraform plan -var="project_id=my-crc-project"

# Деплой
terraform apply -var="project_id=my-crc-project"

# Удаление
terraform destroy -var="project_id=my-crc-project"

Deployment Manager (Legacy)

# deployment.yaml
resources:
  - name: crc-bucket
    type: storage.v1.bucket
    properties:
      name: my-crc-resume
      location: us-central1
      website:
        mainPageSuffix: index.html
        notFoundPage: error.html

  - name: crc-function
    type: gcp-types/cloudfunctions-v2:projects.locations.functions
    properties:
      parent: projects/PROJECT_ID/locations/us-central1
      functionId: visitor-counter
      buildConfig:
        runtime: python312
        entryPoint: visitor_counter
# Деплой Deployment Manager
gcloud deployment-manager deployments create crc \
  --config deployment.yaml

# Удаление
gcloud deployment-manager deployments delete crc

Pulumi (Python)

# __main__.py
import pulumi
import pulumi_gcp as gcp

# Storage bucket
bucket = gcp.storage.Bucket("frontend",
    location="us-central1",
    website=gcp.storage.BucketWebsiteArgs(
        main_page_suffix="index.html",
        not_found_page="error.html"
    )
)

# Cloud Function
function = gcp.cloudfunctionsv2.Function("visitor-counter",
    location="us-central1",
    build_config=gcp.cloudfunctionsv2.FunctionBuildConfigArgs(
        runtime="python312",
        entry_point="visitor_counter",
    ),
    service_config=gcp.cloudfunctionsv2.FunctionServiceConfigArgs(
        max_instance_count=10,
        available_memory="128Mi"
    )
)

pulumi.export("function_url", function.service_config.uri)

Проверь себя

Чем Pulumi отличается от Terraform?

Что делает data.archive_file в Terraform для Cloud Functions?

Какая команда Terraform покажет все ресурсы, которые будут созданы, без применения?

Зачем Cloud Function 2nd gen создаёт IAM binding для Cloud Run?

Почему Google рекомендует Terraform вместо Deployment Manager?