diff --git a/general-knowledge-base/google-saas-runtime/readme.md b/general-knowledge-base/google-saas-runtime/readme.md new file mode 100644 index 0000000..1249405 --- /dev/null +++ b/general-knowledge-base/google-saas-runtime/readme.md @@ -0,0 +1,18 @@ +# Explore Google SaaS Runtime + +Doc: + +## Hands on Lab + +### Goals + +* Define a SaaSRuntime Unit to create a basic GKE cluster. +* Define a SaaSRuntime Unit to deploy a sample K8S workload to the basic GKE + cluster. +* Build above blueprint as an OCI image. Follow + [this](https://cloud.google.com/saas-runtime/docs/create-upload-blueprint#manual_build_push) + documentation. + +## References + +* \ No newline at end of file diff --git a/general-knowledge-base/google-saas-runtime/resources/docker-build-cmd b/general-knowledge-base/google-saas-runtime/resources/docker-build-cmd new file mode 100644 index 0000000..3bea5b6 --- /dev/null +++ b/general-knowledge-base/google-saas-runtime/resources/docker-build-cmd @@ -0,0 +1,11 @@ +IMAGE_NAME=us-west2-docker.pkg.dev/daniellguo-anthos-dev/daniellguo-easysaas-ar/gke-cluster-bp:dev +ENGINE_TYPE=inframanager +ENGINE_VERSION=1.5.7 + +docker buildx build -t $IMAGE_NAME \ + --platform linux/amd64,linux/arm64 \ + --builder=container \ + --push \ + --annotation "com.easysaas.engine.type=$ENGINE_TYPE" \ + --annotation "com.easysaas.engine.version=$ENGINE_VERSION" \ + --provenance=false . \ No newline at end of file diff --git a/general-knowledge-base/google-saas-runtime/resources/gke-cluster/Dockerfile b/general-knowledge-base/google-saas-runtime/resources/gke-cluster/Dockerfile new file mode 100644 index 0000000..fe77c68 --- /dev/null +++ b/general-knowledge-base/google-saas-runtime/resources/gke-cluster/Dockerfile @@ -0,0 +1,3 @@ +# Dockerfile used to build the terraform configuration files +FROM scratch +COPY --exclude=Dockerfile --exclude=.git --exclude=.gitignore --exclude=.terraform --exclude=.terraform.d . / \ No newline at end of file diff --git a/general-knowledge-base/google-saas-runtime/resources/gke-cluster/main.tf b/general-knowledge-base/google-saas-runtime/resources/gke-cluster/main.tf new file mode 100644 index 0000000..f5c4b6e --- /dev/null +++ b/general-knowledge-base/google-saas-runtime/resources/gke-cluster/main.tf @@ -0,0 +1,52 @@ +# main.tf + +# ----------------------------------------------------------------------------- +# REQUIRED SAAS RUNTIME INPUT VARIABLES +# ----------------------------------------------------------------------------- +# These variables are automatically populated by SaaS Runtime when a unit +# is created. You MUST declare them so Terraform can accept the values. +# ----------------------------------------------------------------------------- + +variable "tenant_project_id" { + type = string + description = "The project ID of the tenant project where resources will be deployed." +} + +variable "tenant_project_number" { + type = string + description = "The project number of the tenant project." +} + +# ----------------------------------------------------------------------------- +# PROVIDER CONFIGURATION +# ----------------------------------------------------------------------------- +# The provider now uses the injected 'project_id' from SaaS Runtime +# instead of a hardcoded value. +# ----------------------------------------------------------------------------- + +provider "google" { + project = var.tenant_project_id # USE THE VARIABLE HERE + region = "" # e.g., us-west2 +} + +# ----------------------------------------------------------------------------- +# RESOURCE DEFINITION +# ----------------------------------------------------------------------------- +# Your GKE cluster resource remains largely the same. +# ----------------------------------------------------------------------------- + +resource "google_container_cluster" "primary" { + # Add the project attribute here for clarity, using the passed-in variable. + project = var.tenant_project_id + name = "" # e.g., basic-gke-cluster + location = "" # e.g., us-west2 + + initial_node_count = 1 + + node_config { + machine_type = "e2-medium" + oauth_scopes = [ + "https://www.googleapis.com/auth/cloud-platform" + ] + } +} \ No newline at end of file diff --git a/general-knowledge-base/google-saas-runtime/resources/gke-cluster/outputs.tf b/general-knowledge-base/google-saas-runtime/resources/gke-cluster/outputs.tf new file mode 100644 index 0000000..7f94d01 --- /dev/null +++ b/general-knowledge-base/google-saas-runtime/resources/gke-cluster/outputs.tf @@ -0,0 +1,11 @@ +# outputs.tf (FOR GKE CLUSTER UNIT) + +output "gke_cluster_name" { + description = "The name of the created GKE cluster." + value = google_container_cluster.primary.name +} + +output "gke_cluster_location" { + description = "The location (region) of the GKE cluster." + value = google_container_cluster.primary.location +} \ No newline at end of file diff --git a/general-knowledge-base/google-saas-runtime/resources/sample-workload/Dockerfile b/general-knowledge-base/google-saas-runtime/resources/sample-workload/Dockerfile new file mode 100644 index 0000000..fe77c68 --- /dev/null +++ b/general-knowledge-base/google-saas-runtime/resources/sample-workload/Dockerfile @@ -0,0 +1,3 @@ +# Dockerfile used to build the terraform configuration files +FROM scratch +COPY --exclude=Dockerfile --exclude=.git --exclude=.gitignore --exclude=.terraform --exclude=.terraform.d . / \ No newline at end of file diff --git a/general-knowledge-base/google-saas-runtime/resources/sample-workload/main.tf b/general-knowledge-base/google-saas-runtime/resources/sample-workload/main.tf new file mode 100644 index 0000000..10c8949 --- /dev/null +++ b/general-knowledge-base/google-saas-runtime/resources/sample-workload/main.tf @@ -0,0 +1,73 @@ +# main.tf (FOR K8S APP UNIT) + +# ----------------------------------------------------------------------------- +# PROVIDER CONFIGURATION +# ----------------------------------------------------------------------------- + +provider "google" { + project = var.tenant_project_id +} + +# ----------------------------------------------------------------------------- +# DATA SOURCE: GET GKE CLUSTER CREDENTIALS +# ----------------------------------------------------------------------------- +# Use the input variables (from Unit 1) to find the cluster and get its auth data. +# ----------------------------------------------------------------------------- + +data "google_container_cluster" "cluster" { + project = var.tenant_project_id + name = var.gke_cluster_name + location = var.gke_cluster_location +} + +# ----------------------------------------------------------------------------- +# PROVIDER CONFIGURATION: KUBERNETES & HELM +# ----------------------------------------------------------------------------- +# Configure the Kubernetes and Helm providers using the cluster data we just fetched. +# ----------------------------------------------------------------------------- + +provider "kubernetes" { + host = "https://${data.google_container_cluster.cluster.endpoint}" + cluster_ca_certificate = base64decode(data.google_container_cluster.cluster.master_auth[0].cluster_ca_certificate) + token = data.google_client_config.default.access_token +} + +provider "helm" { + kubernetes = { + host = "https://${data.google_container_cluster.cluster.endpoint}" + cluster_ca_certificate = base64decode(data.google_container_cluster.cluster.master_auth[0].cluster_ca_certificate) + token = data.google_client_config.default.access_token + } +} + +data "google_client_config" "default" {} + +# ----------------------------------------------------------------------------- +# RESOURCE: DEPLOY NGINX VIA HELM +# ----------------------------------------------------------------------------- +# This creates a Helm release for NGINX from the public Bitnami chart repo. +# We set the service type to LoadBalancer so we can get an external IP. +# ----------------------------------------------------------------------------- + +resource "helm_release" "nginx_ingress" { + name = "my-nginx" + repository = "https://charts.bitnami.com/bitnami" + chart = "nginx" + version = "15.5.1" # Pinning version is best practice + namespace = "default" + + # Set values for the Helm chart + set = [ + { + name = "service.type" + value = "ClusterIP" + } + ] +} + +resource "time_sleep" "wait_for_service_ip" { + # This sleep will only start AFTER the helm release is "done" + depends_on = [helm_release.nginx_ingress] + + create_duration = "60s" +} \ No newline at end of file diff --git a/general-knowledge-base/google-saas-runtime/resources/sample-workload/outputs.tf b/general-knowledge-base/google-saas-runtime/resources/sample-workload/outputs.tf new file mode 100644 index 0000000..f68ac2d --- /dev/null +++ b/general-knowledge-base/google-saas-runtime/resources/sample-workload/outputs.tf @@ -0,0 +1,18 @@ +# outputs.tf (Corrected for ClusterIP) + +data "kubernetes_service" "nginx_service" { + metadata { + name = "${helm_release.nginx_ingress.name}-nginx" + namespace = helm_release.nginx_ingress.namespace + } + depends_on = [ + helm_release.nginx_ingress, + time_sleep.wait_for_service_ip + ] +} + +output "nginx_internal_cluster_ip" { + description = "The internal cluster IP of the NGINX service." + # Read the .spec.cluster_ip instead of the load balancer status + value = data.kubernetes_service.nginx_service.spec[0].cluster_ip +} \ No newline at end of file diff --git a/general-knowledge-base/google-saas-runtime/resources/sample-workload/variables.tf b/general-knowledge-base/google-saas-runtime/resources/sample-workload/variables.tf new file mode 100644 index 0000000..6997119 --- /dev/null +++ b/general-knowledge-base/google-saas-runtime/resources/sample-workload/variables.tf @@ -0,0 +1,29 @@ +# ----------------------------------------------------------------------------- +# REQUIRED SAAS RUNTIME INPUT VARIABLES +# ----------------------------------------------------------------------------- +variable "tenant_project_id" { + type = string + description = "The project ID of the tenant project where resources will be deployed." +} + +variable "tenant_project_number" { + type = string + description = "The project number of the tenant project." +} + +# ----------------------------------------------------------------------------- +# CUSTOM INPUT VARIABLES (FROM GKE CLUSTER UNIT) +# ----------------------------------------------------------------------------- +# These variables will be populated by the outputs from Unit Kind 1. +# SaaS Runtime handles this mapping when you define the dependency. +# ----------------------------------------------------------------------------- + +variable "gke_cluster_name" { + type = string + description = "The name of the GKE cluster to deploy to (from GKE unit output)." +} + +variable "gke_cluster_location" { + type = string + description = "The location of the GKE cluster (from GKE unit output)." +} \ No newline at end of file diff --git a/general-knowledge-base/google-saas-runtime/resources/sample-workload/versions.tf b/general-knowledge-base/google-saas-runtime/resources/sample-workload/versions.tf new file mode 100644 index 0000000..2b27049 --- /dev/null +++ b/general-knowledge-base/google-saas-runtime/resources/sample-workload/versions.tf @@ -0,0 +1,24 @@ +# versions.tf (FOR K8S APP UNIT) + +terraform { + required_version = ">= 1.0" + + required_providers { + google = { + source = "hashicorp/google" + version = ">= 4.0.0" + } + kubernetes = { + source = "hashicorp/kubernetes" + version = ">= 2.10.0" + } + helm = { + source = "hashicorp/helm" + version = ">= 2.5.0" + } + time = { + source = "hashicorp/time" + version = ">= 0.9.0" + } + } +} \ No newline at end of file