[{"content":"I\u0026rsquo;m a Product Manager on GKE, and I spend a lot of my time with platform teams who are tired of the node pool tax. You sit down to \u0026ldquo;just run a workload,\u0026rdquo; and somehow you\u0026rsquo;re back in the console hand-crafting a node pool: pick a machine type, set min and max, decide on Spot or on-demand, wire up taints and labels, and pray you guessed the shape right. Then traffic changes, or that machine family runs out of capacity in your zone, and you\u0026rsquo;re back doing it again.\nNode pools are inventory you pre-order. You commit to a specific shape up front and hope demand matches. ComputeClasses flip that model. Instead of pre-ordering fixed inventory, you hand GKE a prioritized shopping list — \u0026ldquo;give me N4 Spot if you can, fall back to N4 on-demand if you can\u0026rsquo;t\u0026rdquo; — and let the platform provision against your intent.\nThis is the first in a series. Today is the primer: what ComputeClasses are, the major features, a hands-on walkthrough you can run yourself, how they compare to Karpenter, and the patterns you\u0026rsquo;ll actually reach for.\nA platform-level abstraction # Platform engineers: a ComputeClass is a platform-level abstraction that gives you autonomous control over node provisioning. You define the menu of node intents once; your app teams just point at it.\nThat separation of concerns is the whole point:\nPlatform team owns the ComputeClasses — which machine families, Spot vs on-demand, fallback order, reservations, consolidation behavior. This is where your capacity strategy and cost guardrails live. App teams opt a workload in with a single node selector, or get one by default from a cluster- or namespace-scoped default ComputeClass. They don\u0026rsquo;t need to know anything about machine types or capacity. A ComputeClass is a custom resource — a cluster-scoped object you apply with kubectl like any other manifest. It declares, in priority order, the kinds of nodes GKE should create and use.\nTwo things make it click:\nIt\u0026rsquo;s intent-based. You describe the shape you want (machineFamily: n4, Spot or not), not a specific node pool you\u0026rsquo;ve pre-built. GKE figures out the rest. It\u0026rsquo;s a fallback list, not a single choice. You give an ordered set of priorities. GKE tries the first; if that capacity isn\u0026rsquo;t available, it falls through to the next. Graceful degradation across capacity types and machine families, without you babysitting it. Works with what you already have # Before the walkthrough, the most important adoption fact: ComputeClasses are additive. You don\u0026rsquo;t rip anything out to start.\nThey work with your existing, manually-created node pools. A ComputeClass can route workloads onto node pools you already manage — just label the pool and reference it. No migration required. They work with auto-created node pools. Turn on nodePoolAutoCreation and the ComputeClass provisions pools scoped to itself, on demand. This greatly improves your obtainability, since you don\u0026rsquo;t have to pre-create node pools to serve demand. They work in both GKE Standard and Autopilot. Same abstraction, both modes. So you can adopt incrementally: start by pointing one ComputeClass at the node pools you already run, then let auto-creation take over more of the fleet as you get comfortable.\nA hands-on walkthrough # Let\u0026rsquo;s actually deploy one. You\u0026rsquo;ll need a GKE cluster on 1.33.3-gke.1136000 or later (for nodePoolAutoCreation).\n1. Define the ComputeClass # Save this as cost-optimized-cc.yaml. Read it top-to-bottom — that order is the priority:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 apiVersion: cloud.google.com/v1 kind: ComputeClass metadata: name: cost-optimized spec: priorities: # Align machineFamily with your existing CUDs/Reservations - machineFamily: n4 spot: true - machineFamily: n4 spot: false nodePoolAutoCreation: enabled: true autoscalingPolicy: consolidationDelayMinutes: 5 whenUnsatisfiable: ScaleUpAnyway In English: try N4 Spot first. If Spot capacity isn\u0026rsquo;t available, fall back to N4 on-demand. Create node pools automatically as needed, consolidate underused nodes after 5 minutes, and if neither priority can be satisfied, fall back to a generic node rather than leaving Pods pending.\nOne thing worth saying early, because it drives your bill: consider matching the machine family you pick to your existing Committed Use Discounts (CUDs) or Reservations. The n4 above is only an example.\nApply it:\n1 2 kubectl apply -f cost-optimized-cc.yaml kubectl get computeclasses 2. Opt a workload in # Save this as demo-deploy.yaml. The only special line is the nodeSelector:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 apiVersion: apps/v1 kind: Deployment metadata: name: hello-cc spec: replicas: 3 selector: matchLabels: app: hello-cc template: metadata: labels: app: hello-cc spec: nodeSelector: cloud.google.com/compute-class: cost-optimized containers: - name: hello image: registry.k8s.io/pause:3.9 Deploy it and watch GKE provision against your intent:\n1 2 3 4 5 6 7 kubectl apply -f demo-deploy.yaml # Watch a node pool get auto-created and nodes join kubectl get nodes -w # Confirm the pods landed on compute-class nodes kubectl get pods -o wide -l app=hello-cc That\u0026rsquo;s the entire opt-in surface for an app team: one nodeSelector line.\n3. (Optional) Point it at an existing manual pool # To prove the \u0026ldquo;works with what you already have\u0026rdquo; claim, you can make the same selector schedule onto a node pool you created by hand. Label your existing pool\u0026rsquo;s nodes with the compute-class label, and Pods selecting cost-optimized will schedule there too — no auto-creation involved:\n1 2 3 4 # On an existing, manually-created node pool gcloud container node-pools update MY_POOL \\ --cluster MY_CLUSTER \\ --node-labels=cloud.google.com/compute-class=cost-optimized 4. Clean up # 1 2 kubectl delete -f demo-deploy.yaml kubectl delete -f cost-optimized-cc.yaml The stanzas worth knowing # A few sections of the spec carry most of the weight.\npriorities[] — the ordered fallback list # The heart of it. Each entry describes a node shape — machineFamily, spot: true/false, optionally a reservation or machine type. Order is everything: top wins, and traversal is strictly ordered. GKE tries priority 1, and only moves to priority 2 if 1 can\u0026rsquo;t be provisioned.\nIf you want a tie-break tier rather than a strict order — \u0026ldquo;any of these, whichever is cheapest right now\u0026rdquo; — there\u0026rsquo;s priorityScore. Priorities sharing a score are treated as one tier and resolved by lowest unit cost.\nnodePoolAutoCreation # 1 2 nodePoolAutoCreation: enabled: true Starting in GKE 1.33.3-gke.1136000, setting nodePoolAutoCreation.enabled: true lets the ComputeClass create node pools scoped directly to itself, on demand. A nice simplification: you don\u0026rsquo;t need to turn on cluster-level Node Auto Provisioning to use it. The ComputeClass is self-contained.\nautoscalingPolicy # Where you tune scale-down behavior. The one you\u0026rsquo;ll use most is consolidationDelayMinutes — how long an underused node waits before the autoscaler reclaims it (floor: one minute). Lower means tighter bin-packing and lower cost; higher means fewer disruptions.\nwhenUnsatisfiable # What happens when none of your priorities can be provisioned. Two values: ScaleUpAnyway (fall back to a generic node so Pods schedule) or DoNotScaleUp (leave Pods Pending).\nactiveMigration # By default, editing a ComputeClass does not move existing workloads onto newly-available higher-priority nodes. If you want that drift behavior — \u0026ldquo;Spot capacity came back, move me off the expensive on-demand node\u0026rdquo; — you opt in with activeMigration.\nA note on disruption: today, you manage the disruption from consolidation and migration with standard Kubernetes PodDisruptionBudgets on your deployments. We\u0026rsquo;re also building a new workload-level disruption control system designed to pair with ComputeClasses — a more expressive way to govern how and when CC-driven changes touch your workloads. More on that as it lands.\nWhy ComputeClasses, if you know Karpenter # If you\u0026rsquo;ve run Karpenter on EKS, the mental model maps cleanly:\nKarpenter GKE ComputeClass NodePool A ComputeClass (collapse several into one priorities[] list) spec.weight Order in priorities[] (top wins) capacity-type: spot spot: true on a priority consolidateAfter: 30s consolidationDelayMinutes (floor: 1 minute) drift activeMigration And the instance families translate about how you\u0026rsquo;d guess:\nGeneral purpose: m5/m6i → n2/n4 Compute optimized: c5/c6i → c2/c4 AMD: m5a/m6a → n2d/n4d ARM: c7g/m7g → c4a/n4a Where ComputeClasses genuinely differentiate:\nNo controller to run. CC is built into the GKE control plane. Karpenter is an add-on you install, upgrade, operate, and grant broad cloud IAM to provision nodes. With CC there\u0026rsquo;s no controller to keep alive, no version skew, no provisioning permissions to hand out — it\u0026rsquo;s just part of GKE. Additive to your existing fleet. Karpenter manages only the nodes it created. A ComputeClass layers over your existing manual node pools and auto-created ones, so adoption is incremental rather than rip-and-replace. One abstraction across Standard and Autopilot. The same ComputeClass works in both GKE modes — you don\u0026rsquo;t relearn anything when you move between them. Deterministic, ordered fallback. Karpenter weighs a flexible set of instance types and bin-packs across them. CC walks your list in strict order and falls to the next priority the instant one fails. That predictability is exactly what you want when you need \u0026ldquo;reservations first, Spot only as a last resort\u0026rdquo; to actually mean it. Native GCP capacity awareness. Reservations, DWS FlexStart, and CUD-aligned families are expressed directly in the spec, so your provisioning intent and your commitments stay in sync. Patterns you\u0026rsquo;ll actually use # Cost-optimized, Spot-first (batch and stateless serving). The walkthrough example. Spot priority on top, on-demand floor underneath. The bread-and-butter pattern and the easiest win on your bill.\nAI/ML inference — order reservations first. For inference, lead with guaranteed, warm capacity rather than Spot: accelerator nodes are slow to start, and Spot preemption mid-serving hurts latency and availability. Consider something like:\nReservations → On-Demand → DWS FlexStart → Spot\nIntent-based sizing to avoid pool sprawl. Prefer machineFamily: n4 over pinning an exact SKU. Pinned classes multiply node pools; expressing intent lets GKE consolidate shapes and keeps your pool count sane.\nA namespace default. You can designate a default ComputeClass for a namespace so teams don\u0026rsquo;t have to annotate every workload — handy for routing an entire environment onto a sensible cost profile by default.\nNext time # That\u0026rsquo;s the lay of the land: a platform-level, intent-based fallback list that provisions nodes against what you actually want — additive to your existing pools, working across Standard and Autopilot, with graceful degradation across capacity types. Stay tuned for more in this series, including our community plans for ComputeClasses.\n","date":"June 5, 2026","externalUrl":null,"permalink":"/gke-compute-classes-primer/","section":"vsz@ | Kubernetes, AI, tech stuff","summary":"I’m a Product Manager on GKE, and I spend a lot of my time with platform teams who are tired of the node pool tax. You sit down to “just run a workload,” and somehow you’re back in the console hand-crafting a node pool: pick a machine type, set min and max, decide on Spot or on-demand, wire up taints and labels, and pray you guessed the shape right. Then traffic changes, or that machine family runs out of capacity in your zone, and you’re back doing it again.\n","title":"A primer on GKE ComputeClasses","type":"page"},{"content":"","date":"June 5, 2026","externalUrl":null,"permalink":"/tags/autoscaling/","section":"Tags","summary":"","title":"Autoscaling","type":"tags"},{"content":"","date":"June 5, 2026","externalUrl":null,"permalink":"/tags/computeclasses/","section":"Tags","summary":"","title":"ComputeClasses","type":"tags"},{"content":"","date":"June 5, 2026","externalUrl":null,"permalink":"/tags/gke/","section":"Tags","summary":"","title":"GKE","type":"tags"},{"content":"","date":"June 5, 2026","externalUrl":null,"permalink":"/tags/google-cloud/","section":"Tags","summary":"","title":"Google Cloud","type":"tags"},{"content":"","date":"June 5, 2026","externalUrl":null,"permalink":"/tags/kubernetes/","section":"Tags","summary":"","title":"Kubernetes","type":"tags"},{"content":"","date":"June 5, 2026","externalUrl":null,"permalink":"/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"","date":"June 5, 2026","externalUrl":null,"permalink":"/","section":"vsz@ | Kubernetes, AI, tech stuff","summary":"","title":"vsz@ | Kubernetes, AI, tech stuff","type":"page"},{"content":"","date":"November 2, 2021","externalUrl":null,"permalink":"/tags/cloud-build/","section":"Tags","summary":"","title":"Cloud Build","type":"tags"},{"content":"","date":"November 2, 2021","externalUrl":null,"permalink":"/tags/skaffold/","section":"Tags","summary":"","title":"Skaffold","type":"tags"},{"content":"[Image attribution: Dan Maharry ]\nLast time, we looked at Google Cloud Code’s “Run as Kubernetes” - aka Skaffold - as an elegant way to develop and iterate a Kubernetes application locally. We saw how Skaffold configuration could be used to abstract the build and local deployment process. But we were left with aching questions like:\nWhat if we need to build and deploy into multiple, differing environments? Can this Skaffold thing be used by my other team members to onboard quickly? Oh, the suspense. But first a quick story about cars again. Back when I was learning to fix my 80s Land Cruiser, I got the crazy idea that I could fix modern cars. I had a bunch of tools I bought for the Cruiser and, well why not, say, try to replace the water pump on an ‘08 BMW? I was bordering on arrogant as I cracked the hood, trying to understand the insanely complicated serpentine belt and idler system. Things were easier on the Cruiser because it was far easier to access everything, but also because it was just mechanically… simpler. In over my head, I soon realized that I didn’t have the right tools, either. It turns out BMWs use the torx ratchet systems and all I had were my old school hex ratchets. I also needed a special low profile jack to lift the BMW, and the list of tooling differences grew from there.\n[Image attribution: phtorxp]\nI raise this to point out that just because you have some tools that work well for one purpose, they may not work well for another. And if there’s anything I learned from cars it\u0026rsquo;s that the smart money invests in the right tools for the job. Sure, you could go hokey and try to jerry-rig some insane workaround, but you’ll very likely pay for it in the end in both stress and time.\nKubernetes environments can also vary from one another. How does Skaffold help? Enter Skaffold profiles. Skaffold configuration typically is scoped to an application or workload. But there are likely environmental differences moving from local dev, to CI, to various staging and pre-production environments, and ultimately prod. Secrets and environmental variables will differ, replica sets may be low in dev and high in prod, build characteristics may differ, etc.\nSkaffold Profiles can be added to any Skaffold configuration file in the profiles stanza. Each profile has a name, and under that, you can define the profile’s build, test, portForwarding, and deploy sections. In other words, it allows you to customize nearly every aspect of configuration we talked about last time.\nExample Skaffold file with profiles: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 apiVersion: skaffold/v2beta15 kind: Config metadata: name: my-app build: artifacts: - image: my-service context: . docker: dockerfile: path/to/Dockerfile deploy: kubectl: manifests: [\u0026#34;path/to/default.yaml\u0026#34;] profiles: - name: packs build: artifacts: - image: my-service buildpacks: builder: gcr.io/buildpacks/builder - name: prod build: googleCloudBuild: projectId: my-google-cloud-project artifacts: - image: my-service docker: dockerfile: docker/distroless.Dockerfile deploy: kubectl: manifests: [\u0026#34;path/to/prod.yaml\u0026#34;] But what about the configuration that sits above the profiles stanza? Well, think of that as your default configuration. In fact, your profiles can simply contain variances that override your default configuration; everything else is inherited from the default config.\nUsing Skaffold Profiles # To build and deploy with a specific profile from command line:\n$ skaffold dev --profile [profile-name]\nOr set the profile attribute in launch.json (vscode) and then use the Cloud Code “Run as Kubernetes” menu. In this example, I\u0026rsquo;m going to use my \u0026ldquo;packs\u0026rdquo; profile which use buildpacks as opposed to the default Dockerfile approach:\nProfiles can also be auto-activated, say, in the presence of a specific environmental variable, Kubernetes context, or Skaffold command.\nBuild with profiles # There\u0026rsquo;s a lot going on in the example above, I have a variety of build examples to show just how different your profiles can be, including:\nDockerfile (the default - line 10) Buildpacks (\u0026ldquo;packs\u0026rdquo; profile - line 20) even a Distroless option for production (\u0026ldquo;prod\u0026rdquo; profile - line 28) Distroless is a cool concept and likely a smart move from a security standpoint (now SLSA 2 compliant), but have you ever tried developing with it? No shell, no tar, no nothing. So in my example, I have only my “prod” profile set to use distroless.\nOffloading builds to the cloud # I’ll point out another cool feature of Skaffold build. You can offload your builds to Google Cloud Build (and turn off your local Docker daemon) by adding a simple configuration parameter to your build config:\n21 22 23 24 25 - name: prod build: googleCloudBuild: projectId: my-google-cloud-project ... Your computer\u0026rsquo;s fan will thank you.\nDeploy with profiles # The various environments you deploy to (local, remote cloud clusters, etc.) may require configuration differences, and once again Skaffold profiles help simplify deployment across diverse environments.\nWhat kinds of differences? Replica counts, environment variables, secrets… really anything supported by the Kubernetes API. Profiles let you specify separate manifest files per environment if you\u0026rsquo;re using kubectl. For example, the domain name of your database will absolutely be different in staging and prod. In addition to my kubectl examples, Helm and Kustomize are also supported.\nIn my example above, I\u0026rsquo;m using an environment specific Kubernetes configuration for my \u0026ldquo;prod\u0026rdquo; profile: 21 22 23 24 25 26 27 28 29 30 31 32 - name: prod build: googleCloudBuild: projectId: my-google-cloud-project artifacts: - image: pop-stats docker: dockerfile: docker/distroless.Dockerfile deploy: kubectl: manifests: [\u0026#34;path/to/prod.yaml\u0026#34;] ... Here\u0026rsquo;s a kustomize example.\nHow do I actually deploy to remote clusters? Skaffold uses your kube context and deploys to it, so all you need to do is change your kube context and re-run skaffold dev or skaffold run. You could use the kubectx utility to update the context, or you can use Cloud Code\u0026rsquo;s context selector UI in your favorite IDE.\nTry the sample app # If you followed along from part 1 of this series, you\u0026rsquo;ll recall my \u0026ldquo;pop stats\u0026rdquo; sample app. The skaffold.yaml file is similar to the one I posted above here. And Cloud Shell will give you a chance to play around with these ideas (Google account required):\nOnboarding others into your application # Skaffold also really helps with onboarding teammates. This may be abundantly obvious from the fact that you can take my app and start building it in minutes. But in case it\u0026rsquo;s not, the suggestion is to check skaffold.yaml into your repo. If your teammates get Cloud Code installed, building and deploying your app becomes as simple as calling \u0026lsquo;skaffold dev\u0026rsquo;. In other words, set this up once and let your entire team enjoy the benefits and unify their dev approach in the process (hopefully resulting in less \u0026ldquo;works for me\u0026rdquo; bug status updates).\nNext time # OK, so hopefully I\u0026rsquo;ve piqued your interest on this Skaffold thing. But what about CI/CD? Can Skaffold play a part in unifying your development and DevOps loops? We\u0026rsquo;ll explore that in the next part of this Skaffold series.\n","date":"November 2, 2021","externalUrl":null,"permalink":"/skaffold-profiles/","section":"vsz@ | Kubernetes, AI, tech stuff","summary":"[Image attribution: Dan Maharry ]\nLast time, we looked at Google Cloud Code’s “Run as Kubernetes” - aka Skaffold - as an elegant way to develop and iterate a Kubernetes application locally. We saw how Skaffold configuration could be used to abstract the build and local deployment process. But we were left with aching questions like:\n","title":"Skaffold Profiles: multi-environment Kubernetes development","type":"page"},{"content":"[Cover Image: my old FJ60]\nUntil recently, I drove an old 80s FJ60 Land Cruiser. Cool, you say? Yes, it was. It was also a lot of work. I did most of that work myself including a carburetor rebuild, head rebuild, radiator, knuckle rebuild, brakes, wiring - you name it. And I learned an awful lot in that process; not just about the Land Cruiser but also about cars, their maintenance, and the tools involved. There was joy, there were tears, too.\nBut when it came down to it, I was investing too much time for the return I was getting. So I threw in the towel and sold the Cruiser for a new car. I know, it’s a shame, but there’s also glorious relief in just having something that works without all the effort.\nFast forward to today and I’m staring down the barrel of learning app dev with Kubernetes. Do I take the long way around again? Do I have the time to do that? Is there even an easy way?\nKeep in mind that I’m newly on the Kubernetes dev journey. I’m posting in the spirit of learning in public and to help others starting their journey. Kubernetes is a super deep pool and this post is NOT about administration or configuration. My priorities are as follows:\n1- Get a dev loop up and running for purposes of local app iteration. # 2- Move from local iteration to remote cluster deployment as easily and confidently as possible. # By easily I mean not having to change a bunch of config files. And by confidently, I mean confidence that my inner loop has reasonable parity with my remote cluster. IOW, I don’t want big surprises when I deploy to “production”.\nWorking for Google Cloud admittedly has some perks. Like access to some of the best Kubernetes mentors around. People like Vic Iglesias, who helped me bootstrap, so I’m paying it forward here. I’m still learning so I invite your comments and suggestions.\nDev Loop challenges # My first pain point in moving to kubernetes, as noted above, is simply getting a dev inner loop going so that I can iterate my app locally with minimum pain. I have a few options:\n1- Run my app using the language runtime via command line or IDE buttons.\n$ python my-app.py\nThe severe downside with this approach is that I’m not assessing my app in a container while iterating, much less kubernetes. How do I know if my app or dependencies will work in prod?\n2- Docker build and run (assuming a Dockerfile)\n$ docker build -t my-app . \u0026amp;\u0026amp; docker run --rm -p 8080:8080 -e PORT=8080 my-app\nThis works, and this is how I used to do it. The problem here is that while I’m in a container, I’m not trying my work in k8s. Which means I’m still relying on some downstream CI process to truly exercise my code in a prod-like k8s cluster. Not ideal.\n3- Manually deploy to Minikube\nMinikube is a local k8s environment. But this can be… onerous:\nBuild the image Push the image Run kubectl apply (or use helm or kustomize if you have hydrations) Wait for my app to deploy, which means periodically checking in using kubectl get services until I get the green light Copy the IP address from kubectl get services to assess in my browser. Make another change, repeat these steps…\nThis solves problems in 1 and 2 above, but I’m spending a lot of time and energy building and deploying to my local k8s cluster. All that task switching will take me out of the “flow”. Plus, how do I reconfigure for remote clusters easily?\nThere has to be a better way.\nMake it easy # Skaffold is a client-side command line utility (with GUI via Cloud Code) that abstracts away all of the painful stuff above and gives you “hot reload” style workflow where changes saved in your IDE automatically trigger a redeploy for you. And if you don’t have compiled components, modified files can be sync’d directly into your running images sparing a rebuild of the container.\nBottom line, I get a real kubernetes development loop with one command:\n$ skaffold dev\nMy app is continuously updated and ready to assess in minikube until I stop the Skaffold process. I also have port forwarding set up for me.\nNotice toward the end when I made a change to a template file? Skaffold picked up my change instantly and rebuilt my image without a pause in the action! This means I can leave skaffold dev running and focus on my application dev and assess my work product in kubernetes any time I want without lifting a finger.\nSample app # Let’s get you up and running with this dev inner loop. The easiest way to do this is using an established sample app and the Cloud Shell IDE, which includes all of the dependencies we’ll need\u0026ndash; Minikube, Cloud Code, Skaffold. Cloud Shell is available at no charge, although a Google account is required.\nMy sample app is a simple single container Python Flask app called “Population Stats”. Click the button below to clone my repo into the Cloud Shell IDE:\nStart your (kubernetes) engines # Let’s get our \u0026ldquo;local kubernetes\u0026rdquo; environment started in Cloud Shell:\nIn the Cloud Shell IDE, activate the “Cloud Code Kubernetes” pane and then click \u0026ldquo;Add a Cluster\u0026hellip;\u0026rdquo; to start a new cluster.\nSelect Minikube and start Make sure minikube is the ACTIVE kubernetes context before continuing to the next step.\nCloud Code - Run on Kubernetes # Click Cloud Code menu at the bottom \u0026gt; Run on Kubernetes. Select [default] when prompted.\nOr (if you\u0026rsquo;re a CLI person) in the terminal type:\n$ skaffold dev\nYou should now see Cloud Code (skaffold under the covers) fetching base images, building the app\u0026rsquo;s container, and deploying to minikube.\nLook for the forwarded port at the bottom of the output. Hover over the forwarded URL and click “Open Web preview” link (since we’re in Cloud Code, the local link is being proxied). You should see the Population Stats app. Viola!\nNow let’s make a change to the app. You should see templates \u0026gt; base.html open in your editor. Make a noticable text change to the base template, like the header text (line 27).\n27 \u0026lt;h1\u0026gt;\u0026lt;img height=\u0026#34;37px\u0026#34; width=\u0026#34;37px\u0026#34; src=\u0026#34;static/logo-32x32.png\u0026#34; alt=\u0026#34;Population\u0026#34;\u0026gt; Population Stats\u0026lt;/h1\u0026gt; Notice that immediately in your terminal/output area Skaffold has already picked up the change! Once the output settles down, refresh the preview URL and be amazed when your change is there, ready to assess.\nOnce you’re done playing around, you can stop Skaffold command line with Ctrl-C (or hit the stop button if you’re going GUI).\nYour app # OK, so my app is a sample and you want to get this working for your app. Let’s dig deeper. You’ve got your IDE, an app, maybe a Dockerfile kicking around.\nYou only really need to install two things:\nA VM environment like Docker Desktop Cloud Code, an IDE plug-in which provides GUI interfaces to everything I’m going to show plus bundles all of the other needed dependencies: Skaffold, minikube, and kubectl. Check out the steps in these tutorials to get you and going, then we\u0026rsquo;ll loop back and break down some skaffold configuration basics below.\nStarting a brand new app - VS Code, Intellij IDE\nUsing an existing app - VS Code, Intellij IDE\nSkaffold config breakdown # Don’t worry if your first attempt at skaffold dev doesn’t go as planned. Skaffold does a good job trying to guess at your app’s setup when instantiated (skaffold init), but sometimes a little hand-wiring may be required. Yes, that means editing some yaml. You’ll survive it.\nThe Skaffold.dev site has an exhaustive reference, but for now, I’m going to give you some basic config to hopefully get you up and running. If you’re k8s savvy, you’ll recognize the KRM style format. To get your dev loop, you’ll want to configure two stanzas: build and deploy\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 apiVersion: skaffold/v2beta15 kind: Config metadata: name: my-app build: local: push: false artifacts: - image: my-service context: . docker: dockerfile: path/to/Dockerfile deploy: kubectl: manifests: [\u0026#34;path/to/config/*.yaml\u0026#34;] Let’s break these down.\nBuild # In the build stanza, jump to the artifacts section, this is where I define the container(s) I’m building and reference my context and the Dockerfile I’m using (see Skaffold docs on buildpacks if you’re using those).\nThe local \u0026gt; push: false section simply tells skaffold not to try to push to a remote artifact repo. I use this since I’m developing locally by default, but it’s not required.\nDeploy # The deploy stanza is pretty self-explanatory. We’re using kubectl to deploy, and we’re pointing to manifests. BTW, by default Skaffold looks for manifests in k8s/*.yaml, so you can omit this line if you put them there. Check out skaffold docs if you’re using helm or kustomize.\nPort forwarding # This can be done manually by adding the port-forward flag to your skaffold dev command: skaffold dev --port-forward\nOr you can save yourself the trouble and add a portForward stanza to your skaffold.yaml right under the deploy stanza:\n1 2 3 4 5 6 7 deploy: ... portForward: - resourceType: deployment resourceName: [NAME OF YOUR K8s DEPLOYMENT] port: 8080 localPort: 8080 You’ll need to crack open your kubernetes config for this service and find the Deployment config and grab the name value.\nSave your skaffold.yaml file and re-run skaffold dev.\nThat’s it. You’re in business. When you save your application files, skaffold will rebuild and deploy for you so that you can stay heads-down on code. Check out the file sync options to speed things up even more.\nNext steps # At the beginning of this post I talked about a second priority which is easily deploying to a remote cluster after iterating in my dev loop. I’ll cover that in an upcoming post, so stay tuned. In the meantime, check out the Skaffold examples. Cloud Code and Skaffold have certainly become my go-to for k8s dev. Hope you also find them useful!\nRead part 2\n","date":"August 28, 2021","externalUrl":null,"permalink":"/kubernetes-dev-with-skaffold/","section":"vsz@ | Kubernetes, AI, tech stuff","summary":"[Cover Image: my old FJ60]\nUntil recently, I drove an old 80s FJ60 Land Cruiser. Cool, you say? Yes, it was. It was also a lot of work. I did most of that work myself including a carburetor rebuild, head rebuild, radiator, knuckle rebuild, brakes, wiring - you name it. And I learned an awful lot in that process; not just about the Land Cruiser but also about cars, their maintenance, and the tools involved. There was joy, there were tears, too.\n","title":"Easy Kubernetes Development With Skaffold","type":"page"},{"content":"[Cover Image: \u0026ldquo;adam wallride\u0026rdquo; by Rob React is licensed under CC BY 2.0]\nSkate or die # Do you remember learning to ride a bicycle or a skateboard? I remember as a kid in the 80s giving skating a try when it became popular (again). Board? Check. Pads? Check. Vans? Check. Helmet? Nah, come on, it was the 80s. Skill? Please. And I remember those first few times out on the board being pretty awkward (and painful). But I persevered and after a few months at it I could pass as semi-cool in the neighborhood.\nWhen I first encountered Google Cloud Build I kind of felt the same way. What\u0026rsquo;s this thing that runs build steps in containers in the cloud? What\u0026rsquo;s it designed to do? What can I use it for? I\u0026rsquo;ve been playing with Cloud Build for a while now and I am hoping this helps you bootstrap quickly. Please feel free to jump in with your own pointers in the comments.\nManaged # Cloud Build, as the name suggests, is a cloud service offered by Google Cloud. You don\u0026rsquo;t run or maintain a \u0026ldquo;server\u0026rdquo;; even the \u0026ldquo;runners\u0026rdquo; are in the cloud.\nContainers → Swiss Army Knife # The first thing you have to get your head around is that Cloud Build runs everything in containers. And you define a \u0026ldquo;pipeline\u0026rdquo; as a series of steps where each step runs in its own container. There is a common workspace which persists between steps so that you can pass data/artifacts between steps.\nI use the term \u0026ldquo;pipeline\u0026rdquo; loosely because it\u0026rsquo;s really a sequence of steps to do\u0026hellip; sort of anything you want. A survey of Cloud Build use cases is beyond the scope here but think Swiss Army knife DevOps automation platform instead of strictly just CI/CD pipelines.\nCloud Builders # But what are these container steps? We\u0026rsquo;ll go through a few examples below, but for now just know that the containers used in build steps can be purpose-built for the task at hand like building a binary (e.g. Maven, Go, C#, NPM), creating a docker container, or performing a task or command (e.g., bash, gcloud CLI, terraform).\nIn fact, Google provides some common container starting points, called Cloud Builders (see what they did there?). There is also a community contributed collection of Cloud Builders. Which of course means you can build your own, too. Basically, if it runs in a container, you can run it with Cloud Build as part of some DevOps automation. I think of this as a form of extensibility.\nSimple config # Here\u0026rsquo;s a simple example of the declarative yaml configuration file used by Cloud Build: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 # To build and deploy to Cloud Run, run from this directory: # $ gcloud builds submit . --config=cr-cloudbuild.yaml steps: # Install dependencies - name: python:3.8-alpine entrypoint: pip args: [\u0026#34;install\u0026#34;, \u0026#34;-r\u0026#34;, \u0026#34;requirements.txt\u0026#34;, \u0026#34;--user\u0026#34;] # Run unit tests - name: python:3.8-alpine entrypoint: python args: [\u0026#34;unit_tests.py\u0026#34;] # Build the container image - name: \u0026#39;gcr.io/cloud-builders/docker\u0026#39; args: [\u0026#39;build\u0026#39;, \u0026#39;.\u0026#39;, \u0026#39;-t\u0026#39;, \u0026#39;gcr.io/$PROJECT_ID/pop-stats\u0026#39;, \u0026#39;-f\u0026#39;, \u0026#39;docker/pythonalpine.Dockerfile\u0026#39;] # Push the container image to Container Registry - name: \u0026#39;gcr.io/cloud-builders/docker\u0026#39; args: [\u0026#39;push\u0026#39;, \u0026#39;gcr.io/$PROJECT_ID/pop-stats\u0026#39;] # Deploy container image to Cloud Run - name: \u0026#39;gcr.io/google.com/cloudsdktool/cloud-sdk\u0026#39; entrypoint: gcloud args: [\u0026#39;run\u0026#39;, \u0026#39;deploy\u0026#39;, \u0026#39;pop-stats\u0026#39;, \u0026#39;--image\u0026#39;, \u0026#39;gcr.io/$PROJECT_ID/pop-stats\u0026#39;, \u0026#39;--region\u0026#39;, \u0026#39;us-west1\u0026#39;, \u0026#39;--platform\u0026#39;, \u0026#39;managed\u0026#39;, \u0026#39;--allow-unauthenticated\u0026#39;] Github link\nThe highlighted line (3) indicates that this is a collection of steps. The name label refers to a container image, which is by default in docker hub, or explicitly referenced like the gcr.io urls. Notice that some steps specify an entrypoint which is a way to call a specific command available to that container.\nThe first two steps load our app files and dependencies into a python-alpine docker container and then run unit_tests.py If those pass, then we build the image we intend to deploy in step 3, this time using a docker builder container and Dockerfile. We then push to gcr.io registry in step 4 (line 16) Finally we use the cloud-sdk Cloud Builder image, which has Google Cloud command line loaded into it, to deploy to Cloud Run (line 19). Notice the entrypoint gcloud is specified Here\u0026rsquo;s what a unit test failure looks like:\nAnd for my next trick # Here\u0026rsquo;s another example my colleague Dave Stanke pulled together.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 steps: - name: \u0026#39;gcr.io/cloud-builders/docker\u0026#39; id: docker build args: [\u0026#39;build\u0026#39;, \u0026#39;-t\u0026#39;, \u0026#39;gcr.io/$PROJECT_ID/us-covid-stats\u0026#39;, \u0026#39;.\u0026#39;] dir: \u0026#39;app\u0026#39; waitFor: [\u0026#39;-\u0026#39;] - name: \u0026#39;gcr.io/cloud-builders/docker\u0026#39; id: docker push args: [\u0026#39;push\u0026#39;, \u0026#39;gcr.io/$PROJECT_ID/us-covid-stats\u0026#39;] dir: \u0026#39;app\u0026#39; waitFor: [\u0026#39;docker build\u0026#39;] - name: \u0026#39;gcr.io/$PROJECT_ID/terraform\u0026#39; id: terraform init args: [ \u0026#39;init\u0026#39;, \u0026#39;-backend-config=bucket=$PROJECT_ID-tf-state\u0026#39;, \u0026#39;-backend-config=prefix=terraform/state\u0026#39; ] waitFor: [\u0026#39;-\u0026#39;] - name: \u0026#39;gcr.io/$PROJECT_ID/terraform\u0026#39; id: terraform apply args: [ \u0026#39;apply\u0026#39;, \u0026#39;--auto-approve\u0026#39;, \u0026#39;-var=google_project_id=$PROJECT_ID\u0026#39;, \u0026#39;-var=google_region=us-east1\u0026#39; ] waitFor: [\u0026#39;docker push\u0026#39;,\u0026#39;terraform init\u0026#39;] Github link\nSo what\u0026rsquo;s different here? First, we\u0026rsquo;re using Cloud Build here to lay down some terraform using the community contributed terraform Cloud Builder, which we have pulled into our project (and perhaps customized for our purposes).\nAlso an id attribute surfaces, which is referenced by waitFor. Until now every step progressed sequentially, but waitFor provides some control over that. If an explicit step is referenced (like line 12), the current step \u0026ldquo;waits for\u0026rdquo; the referenced step. But it also provides a way to run steps in parallel; in line 21 the - means \u0026ldquo;run at the same time as the previous step\u0026rdquo;. This makes sense because there\u0026rsquo;s no reason we can\u0026rsquo;t push our image while terraform init runs.\nOld dog, new tricks # So that\u0026rsquo;s a wrap for my first look at Cloud Build. I have to say I\u0026rsquo;m intrigued by the possibilities and this old dog is learning some new tricks. I\u0026rsquo;m curious what others are doing with Cloud Build, so leave me your thoughts - good, bad, or ugly. Much more to follow in this space.\n","date":"July 6, 2021","externalUrl":null,"permalink":"/cloud-build-demystified/","section":"vsz@ | Kubernetes, AI, tech stuff","summary":"[Cover Image: “adam wallride” by Rob React is licensed under CC BY 2.0]\nSkate or die # Do you remember learning to ride a bicycle or a skateboard? I remember as a kid in the 80s giving skating a try when it became popular (again). Board? Check. Pads? Check. Vans? Check. Helmet? Nah, come on, it was the 80s. Skill? Please. And I remember those first few times out on the board being pretty awkward (and painful). But I persevered and after a few months at it I could pass as semi-cool in the neighborhood.\n","title":"Cloud Build Demystified","type":"page"},{"content":" Welcome to the Zzzz blog # I\u0026rsquo;ve created this blog to document my journey into the cloud universe. Special emphasis on DevOps, but I\u0026rsquo;ll veer here and there. I won\u0026rsquo;t get overly serious. My goal is to make this a worthwhile stop for others on a learning journey.\nWhat\u0026rsquo;s with all the Zs? # My name has a \u0026ldquo;Z\u0026rdquo; in it, making it hard for some to pronounce. I find it amusing to emphasize that. Plus if you snore loudly while reading my blog I can say it\u0026rsquo;s by design.\n","date":"July 3, 2021","externalUrl":null,"permalink":"/hello-world/","section":"vsz@ | Kubernetes, AI, tech stuff","summary":"Welcome to the Zzzz blog # I’ve created this blog to document my journey into the cloud universe. Special emphasis on DevOps, but I’ll veer here and there. I won’t get overly serious. My goal is to make this a worthwhile stop for others on a learning journey.\n","title":"Hello World","type":"page"},{"content":"I\u0026rsquo;m a Product Manager with Google Cloud currently working on Google Kubernetes Engine (GKE). Previously I have been a tech entrepreneur and product leader with a focus on cloud infrastructure and developer tools. While curiosity killed the cat, I\u0026rsquo;m lucky enough to still be kicking tires in the cloud.\n","date":"June 30, 2021","externalUrl":null,"permalink":"/about/","section":"vsz@ | Kubernetes, AI, tech stuff","summary":"I’m a Product Manager with Google Cloud currently working on Google Kubernetes Engine (GKE). Previously I have been a tech entrepreneur and product leader with a focus on cloud infrastructure and developer tools. While curiosity killed the cat, I’m lucky enough to still be kicking tires in the cloud.\n","title":"About Victor Szalvay","type":"about"},{"content":"","externalUrl":null,"permalink":"/authors/","section":"Authors","summary":"","title":"Authors","type":"authors"},{"content":"","externalUrl":null,"permalink":"/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"","externalUrl":null,"permalink":"/series/","section":"Series","summary":"","title":"Series","type":"series"}]