With open-source SpinKube, you can run serverless WebAssembly workloads (Spin Apps) natively on Kubernetes, leveraging well-known Kubernetes primitives such as Deployments and Pods. Although mastering Kubernetes is hard and time intensive, simplifying the developer and operation experience is always on our minds. That being said, this article provides six simple steps to run and invoke Spin Apps on Kubernetes. Prerequisites To follow the instructions of this article, you must have the following in place: Access to a Kubernetes Cluster. The Kubernetes CLI kubectl installed on your machine. The Helm CLI helm installed on your machine. The Spin CLI spin installed on your machine. Language-specific tooling installed on your machine (different installation processes based on your preferred programming language; consult the language guides). 1. Deploy SpinKube Deploying SpinKube to a Kubernetes cluster is pretty straightforward. The following script deploys SpinKube to the currently active kubect context: #!/bin/bash set -euo pipefail clear echo "SpinKube Deployment" echo "" echo "This script will deploy SpinKube to your current kubectl context" # Parse arguments SKIP_CERT_MANAGER=false while [[ $# -gt 0 ]]; do case "$1" in --skip-cert-manager) SKIP_CERT_MANAGER=true echo "Installation of cert-manager will be skipped 💡" shift ;; *) echo "Unknown option: $1" exit 1 ;; esac done # Function to check if an executable is installed and available in PATH check_executable() { local executable="$1" if command -v "$executable" >/dev/null 2>&1; then echo " - $executable is installed and available in PATH. ✅" else echo " - $executable is not installed or not available in PATH." exit 1 fi } # Function to ask the user whether to proceed or cancel the script proceed_or_cancel() { kubectl config get-contexts read -p "This script will modify the current kubectl context!\\n Do you want to proceed? (yes/no): " response case "$response" in [yY] | [yY][eE][sS]) echo "Proceeding with the script..." ;; *) echo "Script execution canceled." exit 1 ;; esac } # Check prerequisites echo "Checking Prerequisites:" check_executable "kubectl" check_executable "helm" # Prompt user to proceed proceed_or_cancel # Install CRDs echo "Installing CRDs..." if [ "$SKIP_CERT_MANAGER" = false ]; then kubectl apply -f <https://github.com/cert-manager/cert-manager/releases/download/v1.14.3/cert-manager.crds.yaml> fi kubectl apply -f <https://github.com/spinkube/spin-operator/releases/download/v0.2.0/spin-operator.crds.yaml> echo "CRDs Installed ✅" # Install RuntimeClass and SpinAppExecutor echo "Installing RuntimeClass and SpinAppExecutor..." kubectl apply -f <https://github.com/spinkube/spin-operator/releases/download/v0.2.0/spin-operator.runtime-class.yaml> kubectl apply -f <https://github.com/spinkube/spin-operator/releases/download/v0.2.0/spin-operator.shim-executor.yaml> echo "RuntimeClass and SpinAppExecutor Installed ✅" # Add Helm repositories and update repository feeds echo "Adding Helm Repositories and Updating Feeds..." if [ "$SKIP_CERT_MANAGER" = false ]; then helm repo add --force-update jetstack <https://charts.jetstack.io> fi helm repo add --force-update kwasm <http://kwasm.sh/kwasm-operator/> helm repo add --force-update grafana <https://grafana.github.io/helm-charts> helm repo update echo "Helm Repositories Added and Feeds Updated ✅" # Conditionally install cert-manager if [ "$SKIP_CERT_MANAGER" = false ]; then echo "Installing cert-manager..." helm upgrade --install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.14.3 echo "cert-manager Installed ✅" else echo "Skipping cert-manager installation as per the provided flag." fi # Install Kwasm echo "Installing Kwasm..." helm upgrade --install kwasm-operator kwasm/kwasm-operator --namespace kwasm --create-namespace --set kwasmOperator.installerImage=ghcr.io/spinkube/containerd-shim-spin/node-installer:v0.14.1 echo "Kwasm Installed ✅" # Annotating Kubernetes Nodes echo "Annotating All Kubernetes Nodes..." kubectl annotate node --all kwasm.sh/kwasm-node=true echo "All Kubernetes Nodes Annotated ✅" # Installing Spin Operator echo "Installing Spin Operator..." helm upgrade --install spin-operator --namespace spin-operator --create-namespace --version 0.2.0 --wait oci://ghcr.io/spinkube/charts/spin-operator echo "Spin Operator Installed ✅" echo "All Done" SpinKube has only one dependency, which is cert-manager. If you've already deployed cert-manager to your cluster, you can skip its installation by providing the —skip-cert-manager flag upon executing the script above. 2. Create a Spin App Next, let’s create a simple Spin App for demonstration purposes. The Spin CLI spin has many built-in templates for different programming languages. We’ll use the http-go template as part of this article. (Feel free to use another template if you want to.) # Create a new Spin App spin new -t http-go -a hello-spinkube # Move into the Spin App directory cd hello-spinkube In the case of Go(lang), the implementation resists in main.go as shown here: package main import ( "fmt" "net/http" spinhttp "github.com/fermyon/spin/sdk/go/v2/http" ) func init() { spinhttp.Handle(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain") fmt.Fprintln(w, "Hello Fermyon!") }) } func main() {} The generated Spin App and its implementation are more than enough for the sake of this article. However, feel free to modify the implementation if you want to. 3. Distribute the Spin App as an OCI artifact Spin Apps are distributed as OCI artifacts that could be stored in any OCI-compliant container registry. We’ll use ttl.sh (an anonymous and ephemeral container registry) here. If you prefer using a private registry instead, you must authenticate your Spin CLI using the spin registry logincommand. Use thespin registry push command in combination with the --build flag to compile your Spin App down to WebAssembly, package it and distribute it as an OCI artifact: # Build, Package, Push the Spin App spin registry push --build ttl.sh/hello-spinkube:12h Building component hello-spinkube with `tinygo build -target=wasi -gc=leaking -no-debug -o main.wasm main.go` Finished building all Spin components Pushing app to the Registry.. Pushed with digest sha256:d2e0ccc59e95ca6441017e8cf43ed587bebe9f1a37f66777d6e3c9231a43bd82 Notice the tag (12h) of the OCI artifact, indicating how long the artifact will remain in the ttl.sh registry. 4. Create Kubernetes Deployment Manifests Having the OCI artifact of the hello-spinkube persisted in ttl.sh, we can move to the fourth step and generate the necessary Kubernetes Deployment Manifests (.yaml). The spin kube scaffold command offers multiple flags that you can use to alter the Kubernetes Deployment Manifests upon creation. We’ll stick with the defaults for now and store the manifests in a spinapp.yaml file: # Generate Kubernetes Deployment Manifests spin kube scaffold --from ttl.sh/hello-spinkube:12h > spinapp.yaml You can use cat to take a look at what spin kube scaffold generated for us: # Show generated Kubernetes Deployment Manifests # cat spinapp.yaml apiVersion: core.spinoperator.dev/v1alpha1 kind: SpinApp metadata: name: hello-spinkube spec: image: "ttl.sh/hello-spinkube:12h" executor: containerd-shim-spin replicas: 2 5. Deploy the Spin App Let’s deploy the Spin App to the Kubernetes cluster. Spin does not make any assumptions about deployment tooling. You can use whatever you’re comfortable with (kubectl, GitOps, Helm Charts…). Using kubectl apply is the easiest way to deploy the Spin App to the Kubernetes cluster: # Deploy the Spin App to the Kubernetes cluster kubectl apply -f spinapp.yaml spinapp.core.spinoperator.dev/hello-spinkube created The spin-operator recognizes the new SpinAppcustom resource (CR) being deployed posted to the Kubernetes API server and will provision the necessary Kubernetes primitives.To retrieve the list of Spin Apps in the default namespace, you can usekubectl get spinapps: # List all Spin Apps in the default namespace kubectl get spinapp NAME READY DESIRED EXECUTOR hello-spinkube 2 2 containerd-shim-spin To explore the underlying Kubernetes primitives, you can use the corresponding kubectlcommands shown below: # List Deployments in the default namespace kubectl get deployment NAME READY UP-TO-DATE AVAILABLE AGE hello-spinkube 2/2 2 2 26s # List the Pods in the default namespace kubectl get pod NAME READY STATUS RESTARTS AGE hello-spinkube-7f446545db-rvhc5 1/1 Running 0 37s hello-spinkube-7f446545db-9tt7r 1/1 Running 0 37s # List the Services in the default namespace kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE hello-spinkube ClusterIP 10.43.175.34 <none> 80/TCP 48s Additionally, you can use kubectl get ep to explore the endpoints assigned to the Kubernetes service (hello-spinkube) of the Spin App. 6. Call the Spin App The easiest way to invoke the Spin App is by establishing port forwarding to one of the underlying Pods or the Service generated for the Spin App: # Start port-forwarding kubectl port-forward svc/hello-spinkube 8080:80 Forwarding from 127.0.0.1:8080 -> 80 Forwarding from [::1]:8080 -> 80 At this point, you can send HTTP requests to localhost:8080 which will be forwarded to port 80 of the hello-spinkube service in the default namespace of your Kubernetes cluster: # Send an HTTP request to the Spin App curl -iX GET <http://localhost:8080> HTTP/1.1 200 OK content-type: text/plain content-length: 15 date: Mon, 03 Jun 2024 12:14:38 GMT Hello Fermyon! You can define Ingress routes and route requests from outside of the Kubernetes cluster to your Spin App. Conclusion As part of this article, we explored six simple steps (DCDCDC) you can follow to run your Spin Apps on Kubernetes leveraging open-source SpinKube: Deploy SpinKube Create a Spin App Distribute the Spin App as an OCI artifact Create Kubernetes Deployment Manifests Deploy the Spin App Call the Spin App Once you have a simple Spin App running on Kubernetes, you can explore more advanced capabilities such as using ConfigMaps and Secrets, or leveraging horizontal scaling using HPA or KEDA. With open-source SpinKube , you can run serverless WebAssembly workloads (Spin Apps) natively on Kubernetes , leveraging well-known Kubernetes primitives such as Deployments and Pods. Although mastering Kubernetes is hard and time intensive, simplifying the developer and operation experience is always on our minds. That being said, this article provides six simple steps to run and invoke Spin Apps on Kubernetes. open-source SpinKube Kubernetes Prerequisites To follow the instructions of this article, you must have the following in place: To follow the instructions of this article, you must have the following in place: Access to a Kubernetes Cluster. The Kubernetes CLI kubectl installed on your machine. The Helm CLI helm installed on your machine. The Spin CLI spin installed on your machine. Language-specific tooling installed on your machine (different installation processes based on your preferred programming language; consult the language guides). Access to a Kubernetes Cluster. The Kubernetes CLI kubectl installed on your machine. kubectl The Helm CLI helm installed on your machine. helm The Spin CLI spin installed on your machine. spin Language-specific tooling installed on your machine (different installation processes based on your preferred programming language; consult the language guides ). language guides 1. Deploy SpinKube Deploying SpinKube to a Kubernetes cluster is pretty straightforward. The following script deploys SpinKube to the currently active kubect context: kubect #!/bin/bash set -euo pipefail clear echo "SpinKube Deployment" echo "" echo "This script will deploy SpinKube to your current kubectl context" # Parse arguments SKIP_CERT_MANAGER=false while [[ $# -gt 0 ]]; do case "$1" in --skip-cert-manager) SKIP_CERT_MANAGER=true echo "Installation of cert-manager will be skipped 💡" shift ;; *) echo "Unknown option: $1" exit 1 ;; esac done # Function to check if an executable is installed and available in PATH check_executable() { local executable="$1" if command -v "$executable" >/dev/null 2>&1; then echo " - $executable is installed and available in PATH. ✅" else echo " - $executable is not installed or not available in PATH." exit 1 fi } # Function to ask the user whether to proceed or cancel the script proceed_or_cancel() { kubectl config get-contexts read -p "This script will modify the current kubectl context!\\n Do you want to proceed? (yes/no): " response case "$response" in [yY] | [yY][eE][sS]) echo "Proceeding with the script..." ;; *) echo "Script execution canceled." exit 1 ;; esac } # Check prerequisites echo "Checking Prerequisites:" check_executable "kubectl" check_executable "helm" # Prompt user to proceed proceed_or_cancel # Install CRDs echo "Installing CRDs..." if [ "$SKIP_CERT_MANAGER" = false ]; then kubectl apply -f <https://github.com/cert-manager/cert-manager/releases/download/v1.14.3/cert-manager.crds.yaml> fi kubectl apply -f <https://github.com/spinkube/spin-operator/releases/download/v0.2.0/spin-operator.crds.yaml> echo "CRDs Installed ✅" # Install RuntimeClass and SpinAppExecutor echo "Installing RuntimeClass and SpinAppExecutor..." kubectl apply -f <https://github.com/spinkube/spin-operator/releases/download/v0.2.0/spin-operator.runtime-class.yaml> kubectl apply -f <https://github.com/spinkube/spin-operator/releases/download/v0.2.0/spin-operator.shim-executor.yaml> echo "RuntimeClass and SpinAppExecutor Installed ✅" # Add Helm repositories and update repository feeds echo "Adding Helm Repositories and Updating Feeds..." if [ "$SKIP_CERT_MANAGER" = false ]; then helm repo add --force-update jetstack <https://charts.jetstack.io> fi helm repo add --force-update kwasm <http://kwasm.sh/kwasm-operator/> helm repo add --force-update grafana <https://grafana.github.io/helm-charts> helm repo update echo "Helm Repositories Added and Feeds Updated ✅" # Conditionally install cert-manager if [ "$SKIP_CERT_MANAGER" = false ]; then echo "Installing cert-manager..." helm upgrade --install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.14.3 echo "cert-manager Installed ✅" else echo "Skipping cert-manager installation as per the provided flag." fi # Install Kwasm echo "Installing Kwasm..." helm upgrade --install kwasm-operator kwasm/kwasm-operator --namespace kwasm --create-namespace --set kwasmOperator.installerImage=ghcr.io/spinkube/containerd-shim-spin/node-installer:v0.14.1 echo "Kwasm Installed ✅" # Annotating Kubernetes Nodes echo "Annotating All Kubernetes Nodes..." kubectl annotate node --all kwasm.sh/kwasm-node=true echo "All Kubernetes Nodes Annotated ✅" # Installing Spin Operator echo "Installing Spin Operator..." helm upgrade --install spin-operator --namespace spin-operator --create-namespace --version 0.2.0 --wait oci://ghcr.io/spinkube/charts/spin-operator echo "Spin Operator Installed ✅" echo "All Done" #!/bin/bash set -euo pipefail clear echo "SpinKube Deployment" echo "" echo "This script will deploy SpinKube to your current kubectl context" # Parse arguments SKIP_CERT_MANAGER=false while [[ $# -gt 0 ]]; do case "$1" in --skip-cert-manager) SKIP_CERT_MANAGER=true echo "Installation of cert-manager will be skipped 💡" shift ;; *) echo "Unknown option: $1" exit 1 ;; esac done # Function to check if an executable is installed and available in PATH check_executable() { local executable="$1" if command -v "$executable" >/dev/null 2>&1; then echo " - $executable is installed and available in PATH. ✅" else echo " - $executable is not installed or not available in PATH." exit 1 fi } # Function to ask the user whether to proceed or cancel the script proceed_or_cancel() { kubectl config get-contexts read -p "This script will modify the current kubectl context!\\n Do you want to proceed? (yes/no): " response case "$response" in [yY] | [yY][eE][sS]) echo "Proceeding with the script..." ;; *) echo "Script execution canceled." exit 1 ;; esac } # Check prerequisites echo "Checking Prerequisites:" check_executable "kubectl" check_executable "helm" # Prompt user to proceed proceed_or_cancel # Install CRDs echo "Installing CRDs..." if [ "$SKIP_CERT_MANAGER" = false ]; then kubectl apply -f <https://github.com/cert-manager/cert-manager/releases/download/v1.14.3/cert-manager.crds.yaml> fi kubectl apply -f <https://github.com/spinkube/spin-operator/releases/download/v0.2.0/spin-operator.crds.yaml> echo "CRDs Installed ✅" # Install RuntimeClass and SpinAppExecutor echo "Installing RuntimeClass and SpinAppExecutor..." kubectl apply -f <https://github.com/spinkube/spin-operator/releases/download/v0.2.0/spin-operator.runtime-class.yaml> kubectl apply -f <https://github.com/spinkube/spin-operator/releases/download/v0.2.0/spin-operator.shim-executor.yaml> echo "RuntimeClass and SpinAppExecutor Installed ✅" # Add Helm repositories and update repository feeds echo "Adding Helm Repositories and Updating Feeds..." if [ "$SKIP_CERT_MANAGER" = false ]; then helm repo add --force-update jetstack <https://charts.jetstack.io> fi helm repo add --force-update kwasm <http://kwasm.sh/kwasm-operator/> helm repo add --force-update grafana <https://grafana.github.io/helm-charts> helm repo update echo "Helm Repositories Added and Feeds Updated ✅" # Conditionally install cert-manager if [ "$SKIP_CERT_MANAGER" = false ]; then echo "Installing cert-manager..." helm upgrade --install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.14.3 echo "cert-manager Installed ✅" else echo "Skipping cert-manager installation as per the provided flag." fi # Install Kwasm echo "Installing Kwasm..." helm upgrade --install kwasm-operator kwasm/kwasm-operator --namespace kwasm --create-namespace --set kwasmOperator.installerImage=ghcr.io/spinkube/containerd-shim-spin/node-installer:v0.14.1 echo "Kwasm Installed ✅" # Annotating Kubernetes Nodes echo "Annotating All Kubernetes Nodes..." kubectl annotate node --all kwasm.sh/kwasm-node=true echo "All Kubernetes Nodes Annotated ✅" # Installing Spin Operator echo "Installing Spin Operator..." helm upgrade --install spin-operator --namespace spin-operator --create-namespace --version 0.2.0 --wait oci://ghcr.io/spinkube/charts/spin-operator echo "Spin Operator Installed ✅" echo "All Done" SpinKube has only one dependency, which is cert-manager. If you've already deployed cert-manager to your cluster, you can skip its installation by providing the —skip-cert-manager flag upon executing the script above. —skip-cert-manager 2. Create a Spin App Next, let’s create a simple Spin App for demonstration purposes. The Spin CLI spin has many built-in templates for different programming languages. We’ll use the http-go template as part of this article. (Feel free to use another template if you want to.) spin http-go # Create a new Spin App spin new -t http-go -a hello-spinkube # Move into the Spin App directory cd hello-spinkube # Create a new Spin App spin new -t http-go -a hello-spinkube # Move into the Spin App directory cd hello-spinkube In the case of Go(lang), the implementation resists in main.go as shown here: main.go package main import ( "fmt" "net/http" spinhttp "github.com/fermyon/spin/sdk/go/v2/http" ) func init() { spinhttp.Handle(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain") fmt.Fprintln(w, "Hello Fermyon!") }) } func main() {} package main import ( "fmt" "net/http" spinhttp "github.com/fermyon/spin/sdk/go/v2/http" ) func init() { spinhttp.Handle(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain") fmt.Fprintln(w, "Hello Fermyon!") }) } func main() {} The generated Spin App and its implementation are more than enough for the sake of this article. However, feel free to modify the implementation if you want to. 3. Distribute the Spin App as an OCI artifact Spin Apps are distributed as OCI artifacts that could be stored in any OCI-compliant container registry. We’ll use ttl.sh (an anonymous and ephemeral container registry) here. If you prefer using a private registry instead, you must authenticate your Spin CLI using the spin registry login command. ttl.sh spin registry login Use the spin registry push command in combination with the --build flag to compile your Spin App down to WebAssembly, package it and distribute it as an OCI artifact: spin registry push --build # Build, Package, Push the Spin App spin registry push --build ttl.sh/hello-spinkube:12h Building component hello-spinkube with `tinygo build -target=wasi -gc=leaking -no-debug -o main.wasm main.go` Finished building all Spin components Pushing app to the Registry.. Pushed with digest sha256:d2e0ccc59e95ca6441017e8cf43ed587bebe9f1a37f66777d6e3c9231a43bd82 # Build, Package, Push the Spin App spin registry push --build ttl.sh/hello-spinkube:12h Building component hello-spinkube with `tinygo build -target=wasi -gc=leaking -no-debug -o main.wasm main.go` Finished building all Spin components Pushing app to the Registry.. Pushed with digest sha256:d2e0ccc59e95ca6441017e8cf43ed587bebe9f1a37f66777d6e3c9231a43bd82 Notice the tag ( 12h ) of the OCI artifact, indicating how long the artifact will remain in the ttl.sh registry. 12h ttl.sh 4. Create Kubernetes Deployment Manifests Having the OCI artifact of the hello-spinkube persisted in ttl.sh , we can move to the fourth step and generate the necessary Kubernetes Deployment Manifests ( .yaml ). hello-spinkube ttl.sh .yaml The spin kube scaffold command offers multiple flags that you can use to alter the Kubernetes Deployment Manifests upon creation. We’ll stick with the defaults for now and store the manifests in a spinapp.yaml file: spin kube scaffold spinapp.yaml # Generate Kubernetes Deployment Manifests spin kube scaffold --from ttl.sh/hello-spinkube:12h > spinapp.yaml # Generate Kubernetes Deployment Manifests spin kube scaffold --from ttl.sh/hello-spinkube:12h > spinapp.yaml You can use cat to take a look at what spin kube scaffold generated for us: cat spin kube scaffold # Show generated Kubernetes Deployment Manifests # cat spinapp.yaml apiVersion: core.spinoperator.dev/v1alpha1 kind: SpinApp metadata: name: hello-spinkube spec: image: "ttl.sh/hello-spinkube:12h" executor: containerd-shim-spin replicas: 2 # Show generated Kubernetes Deployment Manifests # cat spinapp.yaml apiVersion: core.spinoperator.dev/v1alpha1 kind: SpinApp metadata: name: hello-spinkube spec: image: "ttl.sh/hello-spinkube:12h" executor: containerd-shim-spin replicas: 2 5. Deploy the Spin App Let’s deploy the Spin App to the Kubernetes cluster. Spin does not make any assumptions about deployment tooling. You can use whatever you’re comfortable with ( kubectl , GitOps, Helm Charts…). kubectl Using kubectl apply is the easiest way to deploy the Spin App to the Kubernetes cluster: kubectl apply # Deploy the Spin App to the Kubernetes cluster kubectl apply -f spinapp.yaml spinapp.core.spinoperator.dev/hello-spinkube created # Deploy the Spin App to the Kubernetes cluster kubectl apply -f spinapp.yaml spinapp.core.spinoperator.dev/hello-spinkube created The spin-operator recognizes the new SpinApp custom resource (CR) being deployed posted to the Kubernetes API server and will provision the necessary Kubernetes primitives. To retrieve the list of Spin Apps in the default namespace, you can use kubectl get spinapps : spin-operator SpinApp kubectl get spinapps # List all Spin Apps in the default namespace kubectl get spinapp NAME READY DESIRED EXECUTOR hello-spinkube 2 2 containerd-shim-spin # List all Spin Apps in the default namespace kubectl get spinapp NAME READY DESIRED EXECUTOR hello-spinkube 2 2 containerd-shim-spin To explore the underlying Kubernetes primitives, you can use the corresponding kubectl commands shown below: kubectl # List Deployments in the default namespace kubectl get deployment NAME READY UP-TO-DATE AVAILABLE AGE hello-spinkube 2/2 2 2 26s # List the Pods in the default namespace kubectl get pod NAME READY STATUS RESTARTS AGE hello-spinkube-7f446545db-rvhc5 1/1 Running 0 37s hello-spinkube-7f446545db-9tt7r 1/1 Running 0 37s # List the Services in the default namespace kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE hello-spinkube ClusterIP 10.43.175.34 <none> 80/TCP 48s # List Deployments in the default namespace kubectl get deployment NAME READY UP-TO-DATE AVAILABLE AGE hello-spinkube 2/2 2 2 26s # List the Pods in the default namespace kubectl get pod NAME READY STATUS RESTARTS AGE hello-spinkube-7f446545db-rvhc5 1/1 Running 0 37s hello-spinkube-7f446545db-9tt7r 1/1 Running 0 37s # List the Services in the default namespace kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE hello-spinkube ClusterIP 10.43.175.34 <none> 80/TCP 48s Additionally, you can use kubectl get ep to explore the endpoints assigned to the Kubernetes service ( hello-spinkube ) of the Spin App. kubectl get ep hello-spinkube 6. Call the Spin App The easiest way to invoke the Spin App is by establishing port forwarding to one of the underlying Pods or the Service generated for the Spin App: # Start port-forwarding kubectl port-forward svc/hello-spinkube 8080:80 Forwarding from 127.0.0.1:8080 -> 80 Forwarding from [::1]:8080 -> 80 # Start port-forwarding kubectl port-forward svc/hello-spinkube 8080:80 Forwarding from 127.0.0.1:8080 -> 80 Forwarding from [::1]:8080 -> 80 At this point, you can send HTTP requests to localhost:8080 which will be forwarded to port 80 of the hello-spinkube service in the default namespace of your Kubernetes cluster: localhost:8080 80 hello-spinkube # Send an HTTP request to the Spin App curl -iX GET <http://localhost:8080> HTTP/1.1 200 OK content-type: text/plain content-length: 15 date: Mon, 03 Jun 2024 12:14:38 GMT Hello Fermyon! # Send an HTTP request to the Spin App curl -iX GET <http://localhost:8080> HTTP/1.1 200 OK content-type: text/plain content-length: 15 date: Mon, 03 Jun 2024 12:14:38 GMT Hello Fermyon! You can define Ingress routes and route requests from outside of the Kubernetes cluster to your Spin App. Conclusion As part of this article, we explored six simple steps ( DCDCDC ) you can follow to run your Spin Apps on Kubernetes leveraging open-source SpinKube: DCDCDC Deploy SpinKube Create a Spin App Distribute the Spin App as an OCI artifact Create Kubernetes Deployment Manifests Deploy the Spin App Call the Spin App D eploy SpinKube D C reate a Spin App C D istribute the Spin App as an OCI artifact D C reate Kubernetes Deployment Manifests C D eploy the Spin App D C all the Spin App C Once you have a simple Spin App running on Kubernetes, you can explore more advanced capabilities such as using ConfigMaps and Secrets , or leveraging horizontal scaling using HPA or KEDA . ConfigMaps and Secrets HPA KEDA