Self-Healing Go Service on Kubernetes
Build a Go service and watch Kubernetes replace a deleted Pod.
Introduction
30 Second Summary
When an app depends on one running copy, a single stop can take the whole experience offline. Recovery only happens when something is responsible for bringing it back.
In this project, you will code a Go HTTP service that reports the hostname serving each request. You will package it as a Docker image for local Kubernetes, where a Deployment replaces a deleted instance.
What You'll Build
Your finished demo returns a new hostname from the same local address after you delete the Pod that served the first response.
By the end of this project, you'll have:
- A local endpoint that returns platform-api is running on <hostname> so you can see which instance handled the request.
- A minimal container image you can run manually to expose what happens when its only instance stops.
- A self-healing Kubernetes demo where a newly named Pod replaces the one you delete. The recovered app answers through the same stable Service.
- Secret Mission: Add an HTTP readiness probe and liveness probe so Kubernetes can make health-aware traffic and restart decisions.
Are there any prerequisites?
You'll need a supported 64-bit Windows 10 or Windows 11 PC with WSL 2.1.5 or later. Your PC also needs 8 GB of RAM, hardware virtualization, 20 GB of free disk space, plus internet access.
Before We Start
Before the hands-on work begins, take a moment to lock in what you are building and why recovery matters. You will create a local Go HTTP service that reports its serving hostname before using Kubernetes to restore availability when a Pod is deleted.
Set Up the Local Platform Toolchain
Your self-healing demo depends on a Linux container engine that a local Kubernetes runtime can use.
Windows PowerShell drives each tool check. Docker Desktop supplies the Linux container engine.
Minikube supplies the local Kubernetes runtime. Visual Studio Code gives you a known editor for the service files.
In this step, get ready to:
- Confirm WSL meets the Docker Desktop backend requirement.
- Prepare Docker Desktop to run Linux containers.
- Complete the local toolchain with minikube plus Visual Studio Code.
Validate WSL and install Docker Desktop
Windows Subsystem for Linux provides the Linux foundation used by Docker Desktop on Windows. Version 2.1.5 or later meets the requirement for this project.
- Switch back to Windows PowerShell.
- Check your installed WSL version by running this command:
wsl --version
What does this command check?
The command displays the installed WSL components plus their versions. Use the WSL version to choose the matching tab below.
✔️ I see version 2.1.5 or higher
Your WSL foundation meets Docker Desktop's requirement. That removes the first compatibility risk from your local platform.
ⓧ I see an older version
Your current WSL installation needs an update before Docker Desktop can use this path.
- Press the Windows key to open Windows search.
- Type Windows PowerShell into the search box.
- Select the administrator launch option.
- Update WSL by running this command:
wsl --update
What does this command do?
The command updates the installed WSL components. This brings the Linux foundation up to the supported level required by Docker Desktop.
Having trouble updating WSL?
Confirm that the PowerShell window has administrator access. Complete any Windows restart requested during the update.
Ask for help with the update using help me diagnose my WSL update problem. Share only non-sensitive output in the NextWork community.
- Complete the requested restart if Windows prompts you.
- Return to Windows PowerShell through Windows search.
- Confirm the updated version by running:
wsl --version
What should you see?
The WSL version should now be 2.1.5 or later. This confirms that the update reached the required version.
ⓧ Version details are missing
Missing version details indicate that the required WSL installation is not ready yet.
- Press the Windows key to open Windows search.
- Type Windows PowerShell into the search box.
- Select the administrator launch option.
- Install WSL by running this command:
wsl --install
What does this command do?
The command installs the Windows features needed for WSL. Windows may request a restart to finish enabling them.
Having trouble installing WSL?
Confirm that the PowerShell window has administrator access. Check that your Windows installation is fully updated.
Ask for help using help me diagnose my WSL installation. Share only non-sensitive output in the NextWork community.
- Complete the requested restart.
- Return to Windows PowerShell through Windows search.
- Verify the installation by running:
wsl --version
What should you see?
The output should now include WSL version details. Confirm that the WSL version is 2.1.5 or later.
Docker Desktop version 4.95.0 provides the container engine used by minikube. Its WSL 2 backend runs the Linux containers required by this project.
Subscription terms can feel like a billing step. Personal educational use is free under the Docker Desktop license.
- Choose the tab that matches your current Docker Desktop setup.
✔️ I have Docker Desktop 4.95.0
- Press the Windows key to open Windows search.
- Type Docker Desktop into the search box.
- Press Enter to start Docker Desktop.
- Accept the subscription terms for personal educational use if Docker Desktop displays them.
Keep Docker Desktop running for the remaining checks. The final verification confirms that its server is available through Linux containers.
ⓧ I have an older version
- Visit the Docker Desktop Windows installation page.
- Download Docker Desktop version 4.95.0.
- Run Docker Desktop Installer.exe.
- Choose the recommended per-user installation.
- Select Use WSL 2 instead of Hyper-V on the configuration page.
- Complete the installation wizard.
Why use the WSL 2 backend?
The WSL 2 backend gives Docker Desktop a Linux environment on your Windows computer. Minikube uses that engine to create the local cluster later.
- Press the Windows key to open Windows search.
- Type Docker Desktop into the search box.
- Press Enter to start Docker Desktop.
- Accept the subscription terms for personal educational use.
Docker Desktop will not start?
Confirm that the WSL update completed successfully. Complete any pending Windows restart before launching Docker Desktop again.
Ask for help using help me diagnose Docker Desktop startup. Share only non-sensitive output in the NextWork community.
ⓧ Docker Desktop is not installed
- Visit the Docker Desktop Windows installation page.
- Download Docker Desktop version 4.95.0.
- Run Docker Desktop Installer.exe.
- Choose the recommended per-user installation.
- Select Use WSL 2 instead of Hyper-V on the configuration page.
- Complete the installation wizard.
Why use the WSL 2 backend?
The WSL 2 backend gives Docker Desktop a Linux environment on your Windows computer. Minikube uses that engine to create the local cluster later.
- Press the Windows key to open Windows search.
- Type Docker Desktop into the search box.
- Press Enter to start Docker Desktop.
- Accept the subscription terms for personal educational use.
Docker Desktop installation failed?
Confirm that WSL meets the required version. Complete any Windows restart requested by the installer.
Ask for help using help me diagnose the Docker Desktop installation. Share only non-sensitive output in the NextWork community.
Install minikube and Visual Studio Code
Minikube creates the local cluster that runs your service. Version v1.39.0 uses Kubernetes v1.37.0 by default.
- Switch back to Windows PowerShell.
- Check whether minikube is already available by running:
minikube version
What does this command check?
The command reports the installed minikube version when Windows can find the executable through PATH. Choose the matching result below.
✔️ I see version v1.39.0
Minikube is already installed at the version used by this project. Your local Kubernetes command is ready for the final toolchain check.
ⓧ I see an older version
Your current minikube executable needs to be replaced with the version used by this project.
- Visit the official minikube start page.
- Select the stable Windows x86-64 .exe download option.
- Follow the documented C:\minikube PATH instructions.
- Close the current Windows PowerShell window.
- Press the Windows key to open Windows search.
- Type Windows PowerShell into the search box.
- Press Enter to start a fresh PowerShell session.
- Verify the replacement executable by running:
minikube version
What should you see?
The output should report v1.39.0. A fresh PowerShell session ensures that Windows reads the updated PATH.
ⓧ Command not found
Windows cannot find minikube yet. Windows Package Manager provides the documented installation path.
- Install minikube by running this command:
winget install Kubernetes.minikube
What does this command do?
Windows Package Manager downloads the stable minikube package. The installation also makes the command available through PATH.
Windows Package Manager is unavailable?
Use the stable Windows x86-64 .exe option on the official minikube start page. Follow its documented C:\minikube PATH instructions.
Ask for help using help me install minikube on Windows. Share only non-sensitive output in the NextWork community.
- Close the current Windows PowerShell window.
- Press the Windows key to open Windows search.
- Type Windows PowerShell into the search box.
- Press Enter to start a fresh PowerShell session.
Visual Studio Code provides the editor used for the Go source file plus the container and Kubernetes configuration files.
- Choose the tab that matches your Visual Studio Code setup.
✔️ Visual Studio Code is installed
- Press the Windows key to open Windows search.
- Type Visual Studio Code into the search box.
- Press Enter to start Visual Studio Code.
You should see the Welcome window. This confirms that the editor is ready for the project files.
ⓧ Visual Studio Code is not installed
- Visit the official Visual Studio Code download page.
- Download the free Windows build.
- Run the downloaded installer.
- Complete the installation wizard.
- Press the Windows key to open Windows search.
- Type Visual Studio Code into the search box.
- Press Enter to start Visual Studio Code.
You should see the Welcome window. This confirms that the Windows build installed successfully.
Visual Studio Code will not open?
Confirm that you downloaded the Windows build. Complete any restart requested by the installer.
Ask for help using help me diagnose the Visual Studio Code installation. Share only non-sensitive details in the NextWork community.
Verify the toolchain
The final check connects each installation to an observable result. Docker must expose a running Linux server while minikube must report the project version.
- Return to the fresh Windows PowerShell window.
- Pause for a moment to predict the three success signals.
- Verify Docker plus minikube by running these commands:
docker version
docker info --format '{{.OSType}}'
minikube version
What should you see?
- The first command prints both Client and Server sections.
- The second command prints linux.
- The third command reports v1.39.0.
One of the checks did not match?
A missing Server section usually means Docker Desktop is not running yet. A different container type means Docker Desktop is not using Linux containers.
A missing minikube version usually means the current PowerShell session has an older PATH. Close that window before starting a fresh session.
Ask for help using help me diagnose my local platform toolchain. Share only non-sensitive output in the NextWork community.
- Switch back to Visual Studio Code.
- Confirm that its Welcome window is visible.
That is the foundation locked in. Docker can run Linux containers while minikube and Visual Studio Code are ready for the build.
Your local platform toolchain is ready. Next, you will code the Go service and package it as a container image.
Code and Containerize the Go Service
Your local platform toolchain is ready. A Kubernetes Deployment needs a portable workload before it can maintain that workload's desired state.
In this step, you will write a Go service in Visual Studio Code. Docker will turn the source into a container image that you can run locally.
In this step, get ready to:
- Write the Go service endpoints.
- Create a multi-stage Dockerfile.
- Run the image as a local container that serves HTTP.
Write the Go service
Each request to the application endpoint needs to reveal which instance handled it. The /healthz endpoint gives the platform a simple application-owned health signal.
- Create the platform-api folder on your Desktop by running these commands in Windows PowerShell:
New-Item -Path "$env:USERPROFILE\Desktop\platform-api" -ItemType Directory
Set-Location -Path "$env:USERPROFILE\Desktop\platform-api"
What do these commands do?
- The first command creates the platform-api folder on your Desktop.
- The second command makes that folder the current PowerShell location.
- Switch back to Visual Studio Code from earlier.
- Select File from the top menu.
- Select Open Folder....
- Select your Desktop folder.
- Select the platform-api folder.
- Select Select Folder.
- Select Yes, I trust the authors if the Workspace Trust dialog appears.
You should see platform-api at the top of the Explorer sidebar.
Folder Already Exists?
- Leave the existing platform-api folder in place.
- Move into that folder with the second PowerShell command.
- Use help me open my existing platform-api folder in Visual Studio Code if the editor shows a different folder.
- Select the New File icon in the Explorer sidebar.
- Enter main.go as the file name.
- Press Enter.
- Add the service implementation by pasting this code into main.go:
package main
import (
"fmt"
"log"
"net/http"
"os"
)
func rootHandler(w http.ResponseWriter, _ *http.Request) {
hostname, err := os.Hostname()
if err != nil {
hostname = "unknown"
}
fmt.Fprintf(w, "platform-api is running on %s\n", hostname)
}
func healthHandler(w http.ResponseWriter, _ *http.Request) {
fmt.Fprintln(w, "ok")
}
func main() {
http.HandleFunc("/", rootHandler)
http.HandleFunc("/healthz", healthHandler)
log.Println("platform-api listening on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
What Does This Code Do?
- The rootHandler() function reads the current hostname. It includes that identity in the response.
- The healthHandler() function returns ok through /healthz.
- The main() function connects each path to its handler. It starts the HTTP server on port 8080.
- The fallback value unknown keeps the application response usable if the hostname lookup fails.
- Press Cmd+S (macOS) or Ctrl+S (Windows) to save main.go.
- Check the Explorer sidebar for main.go.
You should see main.go listed inside the platform-api folder.
Seeing Go Syntax Warnings?
- Check that every opening brace has a matching closing brace.
- Check that the import names remain inside the import parentheses.
- Use help me compare my main.go file with this Go service if the editor still highlights the file.
Why Go's Standard Library?
A third-party web framework could handle routing. This service only needs two endpoints. The net/http package keeps the build free from third-party dependencies.
✔️ Awesome, I've got everything!
Great. Double-check that you saved main.go.
ⓧ I'd like to double check the full code
package main
import (
"fmt"
"log"
"net/http"
"os"
)
func rootHandler(w http.ResponseWriter, _ *http.Request) {
hostname, err := os.Hostname()
if err != nil {
hostname = "unknown"
}
fmt.Fprintf(w, "platform-api is running on %s\n", hostname)
}
func healthHandler(w http.ResponseWriter, _ *http.Request) {
fmt.Fprintln(w, "ok")
}
func main() {
http.HandleFunc("/", rootHandler)
http.HandleFunc("/healthz", healthHandler)
log.Println("platform-api listening on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
Create the minimal container build
A multi-stage build separates compilation from execution. The final image carries the service binary without the full Go toolchain.
- Select the New File icon in the Explorer sidebar.
- Enter Dockerfile as the file name.
- Press Enter.
- Define the two-stage container build by pasting this code into Dockerfile:
FROM golang:1.27.2-alpine3.24 AS build
WORKDIR /src
COPY main.go .
RUN CGO_ENABLED=0 go build -o /platform-api main.go
FROM scratch
COPY --from=build /platform-api /platform-api
EXPOSE 8080
ENTRYPOINT ["/platform-api"]
What Does This Build Do?
- The named build stage contains the Go toolchain needed to compile main.go.
- The CGO_ENABLED=0 setting produces a binary that does not depend on cgo.
- The scratch stage starts from an empty runtime image. It receives only the compiled platform-api binary.
- The image documents port 8080 as the application port. Its entry point starts the service binary.
- Press Cmd+S (macOS) or Ctrl+S (Windows) to save Dockerfile.
- Check the Explorer sidebar for Dockerfile.
You should see Dockerfile beside main.go inside the platform-api folder.
Dockerfile Showing Unexpected Formatting?
- Check that the file is named Dockerfile with no file extension.
- Check that both FROM instructions start at the beginning of their lines.
- Use help me compare my Dockerfile with this multi-stage build if the file still looks different.
✔️ Awesome, I've got everything!
Great. Double-check that you saved Dockerfile.
ⓧ I'd like to double check the full code
FROM golang:1.27.2-alpine3.24 AS build
WORKDIR /src
COPY main.go .
RUN CGO_ENABLED=0 go build -o /platform-api main.go
FROM scratch
COPY --from=build /platform-api /platform-api
EXPOSE 8080
ENTRYPOINT ["/platform-api"]
Build, run, and call the service
The two files now describe both the application and its packaging. Building the image checks that Docker can compile the service into the portable artifact Kubernetes uses later.
The first image build can take a few minutes while Docker downloads the Go build image. That wait is expected.
- Build the local image from the current platform-api folder by running this command in PowerShell:
docker build -t platform-api:v1 .
What Does This Command Do?
- The docker build command follows the instructions in Dockerfile.
- The -t option tags the completed image as platform-api:v1.
- The final dot gives Docker the current folder as the build context.
- Wait for the build command to finish.
PowerShell should return to its prompt after Docker creates the platform-api:v1 image.
Image Build Failed?
- Check that PowerShell is still inside the platform-api folder.
- Check that main.go uses the exact handler names shown above.
- Use help me diagnose my platform-api Docker build with the build output if the command still fails.
The image is a stored artifact. A running container turns that artifact into the service process you can reach from Windows.
- Start the container in the background by running this command:
docker run -d --name platform-api -p 127.0.0.1:8080:8080 platform-api:v1
What Does This Command Do?
- The -d option runs the container in detached mode.
- The --name option assigns the container the name platform-api.
- The -p option maps Windows port 8080 to the container's port 8080.
- The 127.0.0.1 address keeps this local demonstration bound to your computer.
The command returns control to PowerShell because the container runs in the background.
Container Did Not Start?
- Check that the image build completed before you run the container.
- Check that another local process is not already using port 8080.
- Use help me diagnose why my platform-api container did not start with the Docker output if the command still fails.
Before you make the request, what identity do you expect the service to return from inside the container?
- Test the running service by sending this request from PowerShell:
(Invoke-WebRequest -UseBasicParsing -Uri http://localhost:8080).Content
What Does This Request Do?
- The request connects to the published service port on your computer.
- The .Content property displays the response body returned by rootHandler().
- The hostname comes from the running container's environment.
You should see platform-api is running on followed by the current container hostname.
Service Request Failed?
- Check that Docker Desktop is still running with Linux containers.
- Check that the container command maps local port 8080 to container port 8080.
- Use help me diagnose why localhost cannot reach my platform-api container if the request still cannot connect.
That's the first working slice complete. Your Go service now responds from a running Docker container.
Next, you will stop that only instance and expose the availability gap that orchestration solves.
Break the One-Container Design
Your Go HTTP service is live inside one Docker container. A single instance currently carries every request.
A successful response proves that the application runs. Recovery needs a separate test.
This step puts that single-instance design under pressure. You will record its current identity before testing what happens when its only container stops.
In this step, get ready to:
- Record the healthy service hostname as a baseline.
- Test the service after its only container stops.
- Remove the stopped container while keeping the local image.
Capture the healthy state
The hostname identifies the exact container serving the request. Recording it gives you a healthy baseline before you disturb the design.
- Switch back to the Windows PowerShell window from the previous step.
- Call the running service by running this command:
(Invoke-WebRequest -UseBasicParsing -Uri http://localhost:8080).Content
What Does This Request Prove?
- The Invoke-WebRequest command sends a request to the local service.
- The .Content property displays the response body.
- The response starts with platform-api is running on before showing the container hostname.
- The os.Hostname() call supplies that container identity.
Good, the service is responding from a specific container instance. The final value in the response is its hostname.
- Record the hostname from the response here: your current container hostname.
No Healthy Response?
- Confirm that the platform-api container is running in Docker Desktop.
- Check whether another local process is using port 8080.
Help me diagnose why my running platform-api container is not responding on port 8080.
Stop the only instance
Stopping the only container is safe here because the local image stays untouched. This test removes the active instance from the request path.
Before you test the design, what do you expect the same request to return after the only container stops?
- Stop the only container and test the endpoint by running these commands:
docker stop platform-api
(Invoke-WebRequest -UseBasicParsing -Uri http://localhost:8080).Content
What Happened?
- The docker stop platform-api command stops the only running instance.
- The image remains stored locally.
- Docker uses the default no restart policy because this container was created without another policy.
- PowerShell reports that it cannot connect when the request reaches the empty local port.
You have now exposed the design's availability gap. No running instance exists to answer the request.
Still Receiving a Response?
- Confirm that you stopped the container named platform-api.
- Check whether another local process is listening on port 8080.
Help me find why localhost still responds after I stopped the platform-api container.
Remove the failed instance
A stopped container still exists as a named object. Removing this object is safe because the reusable image remains on your machine.
- Remove the stopped container by running this command:
docker rm platform-api
What Stays Behind?
- The docker rm platform-api command deletes the stopped container object.
- The platform-api:v1 image remains available as the reusable build artifact.
- A stored image cannot serve requests until a container runs from it.
Container Removal Failed?
If the container is still active, repeat the stop action above before retrying the removal.
Help me remove the stopped platform-api container without deleting its image.
One final request checks whether removing the stopped container changed the service state.
Before you run it, do you expect removing a stopped container to restore the endpoint?
- Repeat the service request by running this command:
(Invoke-WebRequest -UseBasicParsing -Uri http://localhost:8080).Content
Why Does the Request Still Fail?
Only a running container can listen on port 8080. The endpoint remains unavailable because the one-off instance is gone.
Your saved baseline hostname was your current container hostname. That identity belonged to the container you removed.
That's the availability gap proven. Your image remains ready for reuse while the manually managed service stays unavailable.
No Kubernetes resources exist yet. Next, you will declare the desired state that restores a missing instance automatically.
Deploy the Declarative Kubernetes Service
Stopping your manually started Docker container left the service unavailable. That outage exposed the missing recovery loop.
A local minikube cluster gives Kubernetes control of the workload. Its reconciliation loop can maintain the state you declare.
A Deployment declares that one Pod should run your image. A Service gives that changing Pod a stable access point.
In this step, get ready to:
- Prepare minikube to run the existing container image.
- Declare the desired workload in reusable manifests.
- Reach the service through a stable local endpoint.
Prepare the local cluster
The minikube node provides the local environment where Kubernetes runs your workload. The Docker driver keeps the entire architecture on your Windows device.
- Return to the platform-api folder from earlier in Windows PowerShell.
- Start the cluster with the Docker driver by running these commands:
minikube start --driver=docker
minikube kubectl -- get nodes
What do these commands do?
- The first command creates the local Kubernetes cluster through the Docker driver.
- The second command asks the cluster for its nodes so you can confirm that its control plane is available.
- Wait for the cluster startup command to finish.
- Check the node status shown by the second command.
The first cluster startup can take a few minutes while minikube creates its node. You should see the minikube node report Ready when the cluster can accept workloads.
Node not reporting Ready?
Confirm that Docker Desktop is still running with Linux containers enabled. Check that the cluster startup command completed before querying the node again.
Help me diagnose why my minikube node is not Ready.
- Load the existing platform-api:v1 image into minikube by running this command:
minikube image load platform-api:v1
Why load the image?
The image currently exists in Docker Desktop's local image store. Loading it gives the minikube node its own copy so the Pod can start without downloading the image from a registry.
Minikube should report that the image load completed. The cluster can now run the exact build artifact you tested earlier.
Image load did not complete?
Confirm that platform-api:v1 still exists in Docker Desktop. Confirm that the minikube cluster is running before retrying the load.
Help me troubleshoot loading my local image into minikube.
Write the Kubernetes manifests
A manifest records the architecture as code that you can apply again. Matching labels connect the Deployment's Pod to the Service.
- In Visual Studio Code, create deployment.yaml inside the open platform-api folder by using the Explorer sidebar's file creation control.
You should see deployment.yaml beside main.go and Dockerfile in the Explorer sidebar.
- Add the Deployment definition by replacing the empty file with the code below:
apiVersion: apps/v1
kind: Deployment
metadata:
name: platform-api
labels:
app: platform-api
spec:
replicas: 1
selector:
matchLabels:
app: platform-api
template:
metadata:
labels:
app: platform-api
spec:
containers:
- name: platform-api
image: platform-api:v1
imagePullPolicy: Never
ports:
- containerPort: 8080
What does this Deployment declare?
- The replica count declares that Kubernetes should keep one Pod running.
- The matching app: platform-api labels connect the Deployment selector to its Pod template.
- The imagePullPolicy: Never setting tells Kubernetes to use the image already loaded into minikube.
- The container port records that the Go service listens on port 8080.
- Save deployment.yaml.
- Confirm that deployment.yaml remains visible in the Explorer sidebar.
Deployment manifest showing a YAML problem?
Check the indentation beneath spec and containers. Make sure the container entry begins with a single list marker.
Help me compare my Deployment manifest with the required YAML structure.
✔️ Awesome, I've got everything!
Your Deployment manifest is saved. Continue to the Service manifest.
ⓧ I'd like to double check the full code
apiVersion: apps/v1
kind: Deployment
metadata:
name: platform-api
labels:
app: platform-api
spec:
replicas: 1
selector:
matchLabels:
app: platform-api
template:
metadata:
labels:
app: platform-api
spec:
containers:
- name: platform-api
image: platform-api:v1
imagePullPolicy: Never
ports:
- containerPort: 8080
How to use this reference
This reference shows the complete Deployment manifest for comparison. Its spacing must match because YAML uses indentation to express structure.
- In Visual Studio Code, create service.yaml inside the open platform-api folder by using the Explorer sidebar's file creation control.
You should see service.yaml appear beside deployment.yaml in the Explorer sidebar.
- Add the Service definition by replacing the empty file with the code below:
apiVersion: v1
kind: Service
metadata:
name: platform-api
spec:
type: ClusterIP
selector:
app: platform-api
ports:
- name: http
port: 80
targetPort: 8080
What does this Service declare?
- The selector sends traffic to Pods carrying the app: platform-api label.
- The ClusterIP type gives the workload a stable address inside the cluster.
- Service port 80 forwards requests to container port 8080.
- Save service.yaml.
- Confirm that service.yaml remains visible in the Explorer sidebar.
Service manifest showing a YAML problem?
Check that selector sits inside spec. Make sure port and targetPort sit inside the same port entry.
Help me compare my Service manifest with the required YAML structure.
✔️ Awesome, I've got everything!
Your Service manifest is saved. Both declarative files are ready to apply.
ⓧ I'd like to double check the full code
apiVersion: v1
kind: Service
metadata:
name: platform-api
spec:
type: ClusterIP
selector:
app: platform-api
ports:
- name: http
port: 80
targetPort: 8080
How to use this reference
This reference shows the complete Service manifest for comparison. The selector must match the Pod label so requests reach the application.
Launch the declarative service
Applying the manifests turns the files into active cluster resources. Port forwarding then creates a temporary path from your Windows device to the Service.
- Switch back to the Windows PowerShell window from earlier.
- Create the resources and start the local port-forward by running these commands:
minikube kubectl -- apply -f deployment.yaml
minikube kubectl -- apply -f service.yaml
minikube kubectl -- rollout status deployment/platform-api
minikube kubectl -- port-forward service/platform-api 8080:80
What happens when these commands run?
- The first two commands create the Deployment and Service from their manifests.
- The rollout command waits until the Deployment has a running Pod.
- The port-forward command maps local port 8080 to Service port 80.
You should see the Deployment rollout complete before the port-forward starts listening. The final command keeps this PowerShell window occupied while forwarding requests.
Deployment not becoming available?
Confirm that both manifest files are saved inside the platform-api folder. Check that the image name remains platform-api:v1 in deployment.yaml.
Help me diagnose why my platform-api Deployment is not completing its rollout.
- Start a second Windows PowerShell window from Windows Search.
Before you run the final check, consider whether the hostname will come from the removed Docker container or from the new Kubernetes Pod.
- Call the forwarded service from the second PowerShell window by running this command:
(Invoke-WebRequest -UseBasicParsing -Uri http://localhost:8080).Content
What does this response prove?
The request enters through the local port-forward before reaching the Service. The Service selects the running Pod that returns its own hostname.
You should see platform-api is running on followed by the Kubernetes Pod hostname. You have reached the key transition: the same image now runs under Kubernetes control.
Your declarative service is live through a stable access point. Next, you will delete its current Pod and watch Kubernetes restore the declared replica.
Prove Kubernetes Self-Healing
Your Go service now runs behind a stable Service in your local Kubernetes cluster.
The earlier Docker container stayed unavailable after it stopped. Now you will delete the active Pod to test whether the Deployment controller restores the declared replica.
This recovery loop closes the availability gap from the one-container design. A newly named Pod should take over without changing the Service.
How does self-healing work?
The Deployment records a desired state of one replica. The controller uses reconciliation to compare that desired state with the Pods that currently exist.
Deleting the only Pod creates a mismatch. The controller responds by creating a replacement until the current state returns to one running replica.
In this step, get ready to:
- Record the identity of the current Pod.
- Delete the Pod to trigger reconciliation.
- Reconnect to the Service to prove recovery.
Record the current Pod identity
Each Pod receives a generated name. The service exposes that same identity because os.Hostname() returns the Pod name inside the container.
- Return to the second Windows PowerShell window from earlier.
- Capture the current Pod identity by running these commands:
minikube kubectl -- get pods
(Invoke-WebRequest -UseBasicParsing -Uri http://localhost:8080).Content
What do these commands prove?
- The first command lists the Pod currently managed by the Deployment.
- The second command sends a request through the existing port-forward.
- The application response exposes the hostname of the Pod that served the request.
- Copy the generated Pod name here: your current Pod name.
- Copy the hostname from the application response here: your current Pod hostname.
The generated Pod name should match the hostname at the end of the application response. This gives you a clear identity to compare after recovery.
Pod name and hostname do not match?
- Copy the name from the current platform-api Pod row.
- Run the application request again to capture the hostname from the current response.
If the identities still differ, help me compare my Kubernetes Pod name with the hostname returned by my Go service.
Delete the Pod and watch reconciliation
The Deployment still declares one replica. Removing its only Pod gives the controller a visible difference to correct.
- Replace <pod-name> in the command below with your current Pod name.
- Before you run the command, predict whether the replica count will remain at zero.
- Delete the recorded Pod by running this command:
minikube kubectl -- delete pod <pod-name>
What does this command trigger?
The command removes the selected Pod from the cluster. Its owning Deployment still requests one replica.
That mismatch activates the controller's reconciliation loop. The controller begins creating a replacement Pod.
The old Pod is deleted. The existing port-forward also ends because its selected Pod has terminated.
That local interruption is expected. The Service remains in the cluster while the controller replaces its backend Pod.
- Inspect the immediate cluster state by running this command:
minikube kubectl -- get pods
What should you notice?
You may catch the replacement before it reaches its final state. Its new name already proves that the controller has started restoring the replica.
The replacement can take a few seconds. That short wait means the cluster is preparing the new Pod.
- Check the Pod state again after a few seconds by running this command:
minikube kubectl -- get pods
What confirms reconciliation?
The old Pod name should be gone. You should see a newly named Pod reporting Running.
The cluster has returned to the declared one-replica state. The Deployment restored the missing instance automatically.
- Copy the replacement Pod name here: your replacement Pod name.
- Compare your replacement Pod name with your current Pod name.
Replacement Pod not running?
- Wait a few more seconds before checking the Pod state again.
- Confirm that the new row belongs to the platform-api workload.
If the replacement does not reach its expected state, help me diagnose why my Deployment is not restoring its platform-api Pod.
Reconnect and prove recovery
The Pod identity changed. The Service name and port mapping stayed the same.
- Switch back to the Windows PowerShell window that held the earlier port-forward.
- Reconnect local port 8080 to the unchanged Service by running this command:
minikube kubectl -- port-forward service/platform-api 8080:80
Why restart the port-forward?
The earlier forwarding process was attached to the deleted Pod. This new process selects the replacement through the same Service.
The command keeps running so requests can continue crossing from your Windows host into the cluster. The Service provides a stable access point while Pods change behind it.
- Leave the new port-forward process running.
- Switch back to the second Windows PowerShell window.
- Before you make the request, predict whether the response will contain the old hostname or the replacement hostname.
- Call the service through the unchanged local address by running this command:
(Invoke-WebRequest -UseBasicParsing -Uri http://localhost:8080).Content
What proves recovery?
The response still begins with platform-api is running on. The hostname now belongs to the replacement Pod.
The address stayed at http://localhost:8080 because the Service remained stable. Kubernetes changed the serving instance behind that access point.
- Copy the recovered hostname here: your replacement Pod hostname.
- Compare your replacement Pod hostname with your current Pod hostname.
You have proved the recovery loop from failure to restored traffic. A different Pod now serves the same application through the unchanged Service.
Recovered service not responding?
- Confirm that the replacement Pod reports Running.
- Confirm that the new port-forward process is still active in the first Windows PowerShell window.
- Run the application request again from the second Windows PowerShell window.
If the request still fails, help me troubleshoot my restarted minikube Service port-forward after Pod replacement.
Secret mission
Add Health-Aware Traffic
Your Deployment already replaces Pods that disappear. Now connect the existing health endpoint to readiness and liveness probes so Kubernetes can make health-aware traffic and restart decisions.
Clean Up Your Resources
Clean Up Your Resources
Everything in this project runs on your Windows PC. There are no cloud resources or usage charges.
Choose whether to keep the platform running. You can also pause it for later or remove it completely.
Resources you used:
- The active port-forward process in Windows PowerShell.
- One local minikube cluster.
- The Kubernetes Deployment named platform-api.
- The ReplicaSet created by the Deployment.
- The Pod managed by the Deployment.
- The ClusterIP Service named platform-api.
- The local Docker image named platform-api:v1.
- The local platform-api folder containing the source code plus the manifests.
Keep everything running
No action needed. Choose this if you are still testing the service or experimenting with its health probes.
- Your port-forward keeps the service available at http://localhost:8080 while its PowerShell process remains active.
- Your minikube cluster keeps the Deployment plus its supporting resources running on your PC.
- Your platform-api:v1 image remains available for future deployments.
- Your platform-api folder remains available for future changes.
Pause - I'll come back to this later
Shut down the running processes to free local memory. Keep the cluster data plus the project files for later.
- Press Ctrl+C in the Windows PowerShell window running the port-forward.
- Stop the local cluster while preserving its data by running this command:
minikube stop
What does this command do?
This stops the local cluster while keeping its data. You can start the same cluster again when you return.
- Confirm Windows PowerShell completes the stop without reporting a failure.
- Quit Docker Desktop from its Windows notification-area menu.
Cluster not stopping?
Make sure you ran the command in Windows PowerShell. Check that minikube can still communicate with Docker Desktop.
Help me diagnose why minikube stop failed on Windows.
Your cluster data stays available for a later start. Your platform-api folder also remains untouched.
Delete - I don't want to use this again
Remove every project resource from your Windows PC. This returns your machine to its pre-project state.
- Press Ctrl+C in the Windows PowerShell window running the port-forward.
- Delete the local cluster plus its associated files by running this command:
minikube delete
What does this command do?
This deletes the local minikube cluster plus its associated files. The Deployment plus its supporting Kubernetes resources disappear with the cluster.
- Confirm Windows PowerShell completes the cluster deletion without reporting a failure.
Cluster not deleting?
Keep Docker Desktop running until minikube finishes deleting the cluster. Retry the command after Docker Desktop finishes starting if it was closed.
Help me diagnose why minikube delete failed on Windows.
- Remove the local project image by running this command:
docker image rm platform-api:v1
What does this command do?
This removes the platform-api:v1 image from Docker Desktop. You need to rebuild it before running the service in another container.
- Confirm Windows PowerShell completes the image removal without reporting a failure.
Image not removing?
Make sure the earlier one-off container remains removed. If Docker reports that the image is missing, the image is already gone.
Help me diagnose why Docker cannot remove platform-api:v1.
- Close the platform-api workspace in Visual Studio Code.
- Delete the same platform-api folder through Windows file management.
- Confirm the folder no longer contains main.go.
- Confirm the folder no longer contains Dockerfile.
- Confirm the folder no longer contains deployment.yaml.
- Confirm the folder no longer contains service.yaml.
Nice Work!
Nice Work!
You did it! You built a Go HTTP service that exposes its identity through the hostname of the serving instance.
You packaged the service with Docker. You proved that Kubernetes can replace a deleted Pod to restore the declared replica count.
You learned how to:
- Build a hostname-aware HTTP service with application and health endpoints using the Go standard library.
- Package the service as a minimal container image with a multi-stage build and a scratch runtime.
- Declare a self-healing workload with reusable Deployment and Service manifests. You deleted its running Pod and watched Kubernetes restore availability through a newly named replacement.
- Secret Mission: Connected the application-owned health endpoint to readiness probes and liveness probes. Kubernetes can now make health-aware traffic and restart decisions.
Ready to quiz yourself?