62

GCP and GKE: From VPC to a Running Ziba Blog

Build the cloud foundation beneath Kubernetes, then prove which Google Cloud and Kubernetes objects serve one Ziba request.

The enterprise problem and today’s slice

Enterprise problem: Ziba’s blog can be healthy as a container yet remain unreachable or unsafe when its Google Cloud project, virtual network, GKE cluster, workload identity, or load balancer is wrong, leaving customers with timeouts and operators with an unclear owner. Whole-course context: Earlier Kubernetes days established that pod memory ends in physical RAM; today consumes that hardware-to-pod model and places it inside Google Cloud Platform (GCP), where Google Kubernetes Engine (GKE) manages Kubernetes while Compute Engine virtual machines supply worker hardware. Today’s slice: We create the network-to-runtime path for one production-shaped Ziba deployment and keep cloud IAM authority separate from Kubernetes authorization. End-of-day evidence: A reviewer can trace a public request to a named Service, pod, node VM, subnet, and GKE control plane, with command output and immutable deployment revision. Still unsolved: Multi-cloud equivalence, Terraform ownership, GitOps reconciliation, global failover, and production spend approval remain later decisions.

Customer use cases

A cloud cluster is not a customer outcome, so creating one without a request path can spend money while Ziba still returns no page. These use cases bind infrastructure creation to visible service and denial evidence.

Use case IDActorCustomer jobSuccess outcomeDenial or recovery evidence
D62-UC-01Ziba platform engineerProvision a bounded GKE foundation and publish the blogA reader receives the expected revision through a Google Cloud load balancer and healthy GKE podsA missing route, quota, IAM permission, or readiness signal blocks rollout with a named event and leaves the previous endpoint healthy
D62-UC-02Ziba security reviewerVerify that the blog reaches only approved Google APIs with workload identityThe pod uses a Kubernetes ServiceAccount mapped by policy, without a downloaded service-account keyAn unbound pod receives an authorization denial while the approved pod and public read path remain healthy

Actor-centred user stories

Cloud defaults can hide consequential choices, so each actor needs acceptance conditions spanning both Google Cloud and Kubernetes. These stories demand positive and negative observations rather than a green console icon.

Story IDUse case IDsUser storyObservable acceptance conditions
D62-US-01D62-UC-01As a Ziba platform engineer, I want a VPC-native GKE cluster and repeatable deployment, so that readers reach the intended blog revision on schedulable nodesCluster, node, Service, EndpointSlice, pod revision, HTTP response, environment, timestamp, and run ID are captured; an unready revision receives no production traffic
D62-US-02D62-UC-02As a Ziba security reviewer, I want workload-scoped Google API authority, so that compromising the blog pod does not inherit broad node credentialsApproved identity call succeeds, unbound ServiceAccount call is denied, no key file exists, and both observations record actor, resource, scope, precondition, environment, time, and trace ID

End-to-end product flows

A deployment can fail at any boundary between a browser and a process, so the flow must preserve the ownership of every hop. It starts with a customer-visible publish action and ends with request and denial evidence.

Flow IDUse case IDsPathTriggerNumbered stepsTerminal evidence
D62-FLOW-01D62-UC-01HappyPlatform engineer approves the Ziba release1. Create or select the Google Cloud project and VPC subnet.
2. Create a regional GKE cluster and node pool.
3. Obtain cluster credentials.
4. Apply the Ziba Deployment and Service.
5. GKE schedules pods onto Compute Engine VMs.
6. Cloud Load Balancing forwards a reader request to a ready pod.
7. Record the served revision.
Actor, project, cluster, namespace, image digest, Service address, HTTP result, environment, timestamp, and immutable rollout/run ID
D62-FLOW-02D62-UC-02DeniedReviewer starts a probe pod with an unapproved ServiceAccount1. Request a Google API token from the GKE metadata service.
2. IAM evaluates the workload principal and resource policy.
3. Deny the unbound principal.
4. Repeat with the approved Ziba ServiceAccount.
5. Confirm the public blog remains healthy.
Denied principal and API scope, approved positive-control result, endpoint probe, environment, timestamp, and immutable audit/trace ID

System design derived from the flows

GKE does not erase the hardware layers beneath Kubernetes; it assigns management responsibility for some of them. In GKE Standard, Google manages the control plane while the customer manages node configuration, and worker nodes are Compute Engine VMs; in Autopilot, GKE also manages the underlying node infrastructure (GKE cluster architecture).

Use case IDEntry pointResponsible servicesAuthoritative storeFailure evidence
D62-UC-01Approved release plus reader URLGoogle Cloud Resource Manager, VPC, GKE control plane, Compute Engine node pool, Kubernetes Deployment/Service controllers, Cloud Load BalancingGoogle Cloud resource APIs for project/network/cluster; Kubernetes API store for workload desired and observed stateCloud API denial or quota error, unschedulable pod, failed readiness, absent EndpointSlice, load-balancer error, or wrong served digest
D62-UC-02Workload identity probeGKE metadata server, Kubernetes ServiceAccount, Workload Identity Federation for GKE, Google Cloud IAM and target APIKubernetes API for ServiceAccount; Google Cloud IAM policy and audit log for external API authorityToken or API PERMISSION_DENIED for unbound principal, unexpectedly broad success, key file present, or absent audit record

GKE VPC-native clusters use alias IP ranges so pod addresses are natively routable in the VPC, and this is the default network mode for new clusters (VPC-native clusters). Workload Identity Federation for GKE lets a Kubernetes workload receive narrowly scoped Google API access without distributing service-account key files (GKE workload identity).

Data model and ownership

Cloud and cluster records must not be collapsed into one “deployment” row because each has a different authority and deletion path. The generated blog stores content elsewhere; this slice needs infrastructure, workload, and evidence state only.

Generated-application database: Not created in this slice — the Ziba blog serves an immutable image while Google Cloud resource state, Kubernetes API state, and deployment evidence are sufficient for the network-to-process proof.

Record or entityStore and ownerPrimary keyForeign key or opaque referenceTenant keyMaterial constraintLifecycle and deletionUse case IDs
GkeFoundationGoogle Cloud resource APIs, owned by Ziba platform engineeringProject ID plus cluster resource nameVPC/subnet and node-pool resource namesGoogle Cloud project IDPod, Service, node, and control-plane CIDRs must not overlap; region and release policy are reviewed before creationCreated before workloads; upgraded in place where supported; cluster deletion removes cluster-owned compute but not unrelated project resourcesD62-UC-01
WorkloadRevisionKubernetes API store, owned by Deployment controller and Ziba teamDeployment UID plus revisionOpaque image digest and cluster resource nameNamespaceOnly ready pods matching the selector enter Service endpoints; image is digest-pinnedCreated by apply, retained in rollout history, rolled back or deleted with namespace policyD62-UC-01
WorkloadAuthorityBindingKubernetes API plus Google Cloud IAM policy, jointly owned by platform securityKubernetes ServiceAccount UID plus IAM policy etagOpaque Google workload-principal URI and target resource nameNamespace and Google Cloud project IDMapping grants only named resource/actions; node identity does not imply workload identityCreated after review, independently revoked in IAM or Kubernetes, audit retained by policyD62-UC-02
DeploymentProofCI artifact store and cloud audit logs, owned by release engineeringRun IDOpaque cluster, revision, request trace, and IAM audit IDsEnvironmentPositive and negative observations must use the same reviewed revision and environmentAppended per release, retained immutably, expired by audit policyD62-UC-01, D62-UC-02

Build the foundation one block at a time

Creating Kubernetes objects before planning address space can force a cluster rebuild or cause unreachable pods. Expand the three-box model in dependency order: project and IAM, then network, then managed control plane and worker compute, then workload and ingress.

Use a regional cluster for production-shaped availability because its control plane is replicated across zones; Google’s GKE guidance recommends regional clusters for production workloads (cluster creation guidance). The lab values below are illustrative: a real team must allocate non-overlapping CIDRs, quota, IAM, and spend before applying them.

gcloud services enable container.googleapis.com compute.googleapis.com
gcloud container clusters create ziba-prod \
  --region=europe-west2 \
  --release-channel=regular \
  --enable-ip-alias \
  --workload-pool="${GOOGLE_CLOUD_PROJECT}.svc.id.goog" \
  --machine-type=e2-standard-4 \
  --num-nodes=1
gcloud container clusters get-credentials ziba-prod --region=europe-west2
kubectl apply -f k8s/ziba.yaml
kubectl rollout status deployment/ziba -n blog
kubectl get service,pods,endpointslices -n blog -o wide

Deploy Ziba and expose only ready replicas

A running process is not automatically a safe backend, so traffic must depend on readiness rather than container existence. This manifest creates Kubernetes software objects; the GKE cloud integration then allocates external load-balancing infrastructure, while the scheduler and kubelet place and run the image on node hardware.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ziba
  namespace: blog
spec:
  replicas: 2
  selector:
    matchLabels:
      app: ziba
  template:
    metadata:
      labels:
        app: ziba
    spec:
      serviceAccountName: ziba
      containers:
        - name: blog
          image: europe-west2-docker.pkg.dev/ziba-prod/blog/site@sha256:REPLACE_ME
          ports:
            - containerPort: 3000
          resources:
            requests:
              cpu: 250m
              memory: 256Mi
            limits:
              memory: 512Mi
          readinessProbe:
            httpGet:
              path: /healthz
              port: 3000
---
apiVersion: v1
kind: Service
metadata:
  name: ziba
  namespace: blog
spec:
  type: LoadBalancer
  selector:
    app: ziba
  ports:
    - port: 80
      targetPort: 3000

Code versus physical and software effects

Commands are requests to control planes, not magic instructions to chips, so operators must know which effects are direct and which are eventual. The table maps each line to the durable state, software reconciliation, physical allocation, and customer outcome it can cause.

Code or declarationControl-plane stateSoftware effectHardware or network effectDeployment outcome
gcloud services enable ...Enables project APIsGoogle API endpoints accept authorized resource requestsNo VM or pod exists yetCluster creation becomes possible
gcloud container clusters createCreates GKE cluster and node-pool resourcesManaged control plane starts; kubelets register nodesCompute Engine VMs reserve vCPU, DRAM, disk, NICs, and IPs on Google hardwareScheduler gains allocatable nodes
kubectl apply -f k8s/ziba.yamlStores Deployment and Service desired stateControllers create ReplicaSet, pods, EndpointSlices, and load-balancer configurationContainers consume node CPU/RAM; cloud networking allocates forwarding resourcesReady image revision becomes reachable
requests.memory: 256MiStores a scheduling reservationScheduler admits each pod only where 256 MiB fitsDoes not install RAM or pre-allocate a contiguous blockPrevents placement on an over-reserved node
limits.memory: 512MiStores a runtime ceilingContainer runtime configures a Linux cgroup limitAdds no node memory; kernel can kill a process that crosses the ceilingBounds one container, potentially producing OOMKilled
kubectl rollout statusReads observed rollout conditionsWatches controller progressAllocates no resourcesProves readiness, not end-user reachability

Failure modes and decision rules

A single timeout does not identify the failed layer, so guessing can replace healthy nodes while a selector remains wrong. Move from outside inward and change the narrowest owner whose evidence fails.

ObservationInterpretationDecision
Cloud API returns IAM or quota denialFoundation creation never reached KubernetesCorrect the reviewed project permission or quota; do not edit pod YAML
Pod is Pending with Insufficient memoryExisting node allocatable budgets cannot satisfy requestsAdd/resize compatible node capacity or justify a smaller request
Pods are Ready but Service has no endpointsLabels/selectors or readiness association is wrongRepair Kubernetes desired state; do not resize VMs
Service has endpoints but external probe failsLoad balancer, firewall, routing, or application response path failedTrace forwarding rule to pod and compare internal versus external probe
Workload can call every Google APIIdentity scope is broader than intendedRevoke broad binding and grant resource-specific IAM to the workload principal

Decision rule: use GKE when the organisation wants Kubernetes semantics while delegating control-plane operations to Google; choose Standard when node-level choices are required, and evaluate Autopilot when delegating node infrastructure is worth its constraints. Use self-managed Kubernetes only when the control-plane or host-level control justifies owning upgrades, availability, security, and repair.

Verify the request and authority boundaries

A deployment is incomplete until evidence joins customer reachability with least-privilege denial. Capture the exact image digest and observe both an approved request and an intentionally unauthorized Google API probe.

kubectl -n blog get deployment ziba -o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}'
kubectl -n blog get pods -l app=ziba -o wide
kubectl -n blog describe service ziba
curl --fail --show-error "http://${ZIBA_ADDRESS}/healthz"
kubectl auth can-i get secrets --as=system:serviceaccount:blog:ziba -n blog

kubectl auth can-i tests Kubernetes authorization only; it does not prove Google Cloud IAM. Test Google API authority separately from a pod and keep the denial audit entry. The two planes complement each other and neither token automatically grants authority in the other.

Key takeaways

A managed Kubernetes cluster is still a stack from physical machines through cloud resources to Kubernetes objects and application processes. GKE changes who operates layers; it does not remove those layers.

  • A reader reaches Ziba through cloud networking, Kubernetes service discovery, a ready pod, and a process consuming node hardware.
  • Google Cloud IAM, Kubernetes RBAC, and application authorization are independent boundaries.
  • GKE Standard delegates the control plane; Autopilot delegates more of the node infrastructure.
  • A code line should be reviewed for control-plane, software, hardware, and customer-visible effects.

Checklist

A production-shaped lab is only complete when it proves placement, reachability, identity denial, and cleanup ownership. Record these checks beside the immutable deployment revision.

  • [ ] Named project, region, VPC/subnet, cluster mode, release channel, and non-overlapping IP ranges
  • [ ] Captured node VM identity, allocatable CPU/memory, pod placement, and image digest
  • [ ] Proved Service endpoints and external HTTP response from the intended revision
  • [ ] Proved approved Google API authority and an unapproved ServiceAccount denial
  • [ ] Documented spend owner and safe deletion order before provisioning