*The author selected Girls Who Code to receive a donation as part of the Write for DOnations program.*

Introduction

The Okteto CLI is an open-source project that provides a local development experience for applications running on Kubernetes. With it you can write your code on your local IDE and as soon as you save a file, the changes can be pushed to your Kubernetes cluster and your app will immediately update. This whole process happens without the need to build Docker images or apply Kubernetes manifests, which can take considerable time.

In this tutorial, you’ll use Okteto to improve your productivity when developing a Kubernetes-native application. First, you'll create a Kubernetes cluster and use it to run a standard "Hello World" application. Then you’ll use Okteto to develop and automatically update your application without having to install anything locally.

Prerequisites

kubernetes illustration for: Prerequisites

Before you begin this tutorial, you'll need the following:

  • Docker running on your local machine.

Step 1 — Creating the Hello World Application

The "Hello World" program is a time-honored tradition in web development. In this case, it is a simple web service that responds "Hello World" to every request. Now that you've created your Kubernetes cluster, let's create a "Hello World" app in Golang and the manifests that you'll use to deploy it on Kubernetes.

First change to your home directory:

				
					
cd ~

				
			

Now make a new directory called hello_world and move inside it:

				
					
mkdir hello_world

cd hello_world

				
			

Create and open a new file under the name main.go with your favorite IDE or text editor:

				
					
nano main.go

				
			

main.go will be a Golang web server that returns the message Hello world!. So, let's use the following code:

				
					
[label main.go]

package main



import (

    "fmt"

    "net/http"

)



func main() {

    fmt.Println("Starting hello-world server...")

    http.HandleFunc("/", helloServer)

    if err := http.ListenAndServe(":8080", nil); err != nil {

        panic(err)

    }

}



func helloServer(w http.ResponseWriter, r *http.Request) {

    fmt.Fprint(w, "Hello world!")

}

				
			

The code in main.go does the following:

  • The first statement in a Go source file must be the package name. Executable commands must always use package <^>main<^>.
  • The import section indicates which packages the code depends on. In this case it uses fmt for string manipulation, and net/http for the HTTP server.
  • The main function is the entry point to your binary. The http.HandleFunc method is used to configure the server to call the helloServer function when a request to the / path is received. http.ListenAndServe starts an HTTP server that listens on all network interfaces on port 8080.
  • The helloServer function contains the logic of your request handler. In this case, it will write Hello world! as the response to the request.

You need to create a Docker image and push it to your Docker registry so that Kubernetes can pull it and then run the application.

Open a new file under the name Dockerfile with your favorite IDE or text editor:

				
					
nano Dockerfile

				
			

The Dockerfile will contain the commands required to build your application's Docker container. Let's use the following code:

				
					
[label Dockerfile]

FROM golang:alpine as builder

RUN apk --update --no-cache add bash

WORKDIR /app

ADD . .

RUN go build -o app



FROM alpine as prod

WORKDIR /app

COPY --from=builder /app/app /app/app

EXPOSE 8080

CMD ["./app"]

				
			

The Dockerfile contains two stages, builder and prod:

  • The builder stage contains the Go build tools. It's responsible for copying the files and building the Go binary.
  • The prod stage is the final image. It will contain only a stripped down OS and the application binary.

This is a good practice to follow. It makes your production containers smaller and safer since they only contain your application and exactly what is needed to run it.

Build the container image (replace <^>your_DockerHub_username<^> with your Docker Hub username):

				
					
docker build -t &lt;^&gt;your_DockerHub_username&lt;^&gt;/hello-world:latest

				
			

Now push it to Docker Hub:

				
					
docker push &lt;^&gt;your_DockerHub_username&lt;^&gt;/hello-world:latest

				
			

Next, create a new folder for the Kubernetes manifests:

				
					
mkdir k8s

				
			

When you use a Kubernetes manifest, you tell Kubernetes how you want your application to run. This time, you'll create a deployment object. So, create a new file deployment.yaml with your favorite IDE or text editor:

				
					
nano k8s/deployment.yaml

				
			

The following content describes a Kubernetes deployment object that runs the okteto/hello-world:latest Docker image. Add this content to your new file, but in your case replace okteto listed after the image label with <^>your_DockerHub_username<^>:

				
					
[label ~/hello_world/k8s/deployment.yaml]

apiVersion: apps/v1

kind: Deployment

metadata:

  name: hello-world

spec:

  selector:

    matchLabels:

      app: hello-world

  replicas: 1

  template:

    metadata:

      labels:

        app: hello-world

    spec:

      containers:

      - name: hello-world

        image: &lt;^&gt;your_DockerHub_username&lt;^&gt;/hello-world:latest

        ports:

        - containerPort: 8080

				
			

The deployment manifest has three main sections:

  • metadata defines the name for your deployment.
  • replicas defines how many copies of it you want running.
  • template tells Kubernetes what to deploy, and what labels to add. In this case, a single container, with the okteto/hello-world:latest image, listening on port 8080, and with the app: hello-world label. Note that this label is the same used in the selector section.

You'll now need a way to access your application. You can expose an application on Kubernetes by creating a service object. Let's continue using manifests to do that. Create a new file called service.yaml with your favorite IDE or text editor:

				
					
nano k8s/service.yaml

				
			

The following content describes a service that exposes the hello-world deployment object, which under the hood will use a load balancers:

				
					
[label k8s/service.yaml]

apiVersion: v1

kind: Service

metadata:

  name: hello-world

spec:

  type: LoadBalancer

  ports:

    - protocol: TCP

      port: 80

      targetPort: 8080

      name: http

  selector:

    app: hello-world

				
			

The service manifest has four main sections:

  • metadata tells Kubernetes how to name your service.
  • type tells Kubernetes how you want to expose your service. In this case, it will expose it externally through a the cloud provider Load Balancer.
  • The ports label tells Kubernetes which ports you want to expose, and how to map them to your deployment. In this case, you will expose port 80 externally and direct it to port 8080 in your deployment.
  • selector tells Kubernetes how to direct traffic. In this case, any pod with the app: hello-world label will receive traffic.

You now have everything ready to deploy your "Hello World" application on Kubernetes. We will do this next.

Step 2 — Deploying Your Hello World Application

In this step you'll deploy your "Hello World" application on Kubernetes, and then you'll validate that it is working correctly.

Start by deploying your application on Kubernetes:

				
					
kubectl apply -f k8s

				
			

You'll see the following output:

				
					
[secondary_label Output]

deployment.apps "hello-world" created

service "hello-world" created

				
			

After about one minute or so, you will be able to retrieve your application's IP. Use this kubectl command to check your service:

				
					
kubectl get service hello-world

				
			

You'll see an output like this listing your Kubernetes service objects. Note your application's IP in the the EXTERNAL-IP column:

				
					
[secondary_label Output]

NAME          TYPE        CLUSTER-IP         EXTERNAL-IP       PORT(S)    AGE

hello-world   ClusterIP   &lt;^&gt;your_cluster_ip&lt;^&gt;   &lt;^&gt;your_external_ip&lt;^&gt;  8080/TCP   37s

				
			

Open your browser and go to <^>your_external_ip<^> listed for your "Hello World" application. Confirm that your application is up and running before continuing with the next step.

Until this moment, you've followed a fairly traditional pathway for developing applications with Kubernetes. Moving forward, whenever you want to change the code in your application, you'll have to build and push a new Docker image, and then pull that image from Kubernetes. This process can take quite some time. Okteto was designed to streamline this development inner-loop. Let's look at the Okteto CLI and see just how it can help.

Step 3 — Installing the Okteto CLI

You will now improve your Kubernetes development productivity by installing the Okteto CLI. The Okteto command line interface is an open-source project that lets you synchronize application code changes to an application running on Kubernetes. You can continue using your favorite IDE, debuggers, or compilers without having to commit, build, push, or redeploy containers to test your application–as you did in the previous steps.

To install the Okteto CLI on a macOS or Linux machine, run the following command:

				
					
curl https://get.okteto.com -sSfL | sh

				
			

Let's take a closer look at this command:

  • The curl command is used to transfer data to and from a server.
  • The -s flag suppresses any output.
  • The -S flag shows errors.
  • The -f flag causes the request to fail on HTTP errors.
  • The -L flag makes the request follow redirects.
  • The | operator pipes this output to the sh command, which will download and install the latest okteto binary in your local machine.

If you are running Windows, you can alternately download the file through your web browser and manually add it to your $PATH.

Once the Okteto CLI is installed, you are ready to put your "Hello World" application in development mode.

Step 4 — Putting Your Hello World Application in Development Mode

The Okteto CLI is designed to swap the application running on a Kubernetes cluster with the code you have in your machine. To do so, Okteto uses the information provided from an Okteto manifest file. This file declares the Kubernetes deployment object that will swap with your local code.

Create a new file called okteto.yaml with your favorite IDE or text editor:

				
					
nano okteto.yaml

				
			

Let's write a basic manifest where you define the deployment object name, the Docker base image to use, and a shell. We will return to this information later. Use the following sample content file:

				
					
[label okteto.yaml]

name: hello-world

image: okteto/golang:1

workdir: /app

command: ["bash"]

				
			

Prepare to put your application in development mode by running the following command:

				
					
okteto up

				
			
				
					
[secondary_label Output]

 ✓  Development environment activated

 ✓  Files synchronized

    Namespace: default

    Name:      hello-world



Welcome to your development environment. Happy coding!

default:hello-world /app&gt;

				
			

The okteto up command swaps the "Hello World" application into a development environment, which means:

  • The Hello World application container is updated with the docker image okteto/golang:1. This image contains the required dev tools to build, test, debug, and run the "Hello World" application.
  • A remote shell starts in your development environment. Now you can build, test, and run your application as if you were in your local machine.
  • Whatever process you run in the remote shell will get the same incoming traffic, the same environment variables, volumes, or secrets as the original "Hello World" application pods. This, in turn, gives you a highly realistic, production-like development environment.

In the same console, now run the application as you would typically do (without building and pushing a Docker image), like this:

				
					
go run main.go

				
			
				
					
[secondary_label Output]

Starting hello-world server...

				
			

The first time you run the application, Go will download your dependencies and compile your application. Wait for this process to finish and test your application by opening your browser and refreshing the page of your application, just as you did previously.

Now you are ready to begin developing directly on Kubernetes.

Step 5 — Developing Directly on Kubernetes

Let's start making changes to the "Hello World" application and then see how these changes get reflected in Kubernetes.

Open the main.go file with your favorite IDE or text editor. For example, open a separate console and run the following command:

				
					
nano main.go

				
			

Then, change your response message to <^>Hello world from the cloud provider!<^>:

				
					
[label main.go]

package main



import (

    "fmt"

    "net/http"

)



func main() {

    fmt.Println("Starting hello-world server...")

    http.HandleFunc("/", helloServer)

    if err := http.ListenAndServe(":8080", nil); err != nil {

        panic(err)

    }

}



func helloServer(w http.ResponseWriter, r *http.Request) {

    fmt.Fprint(w, "&lt;^&gt;Hello world from the cloud provider!&lt;^&gt;")

}

				
			

It is here that your workflow changes. Instead of building images and redeploying containers to update the "Hello World" application, Okteto will synchronize your changes to your development environment on Kubernetes.

From the console where you executed the okteto up command, cancel the execution of go run main.go by pressing CTRL + C. Now rerun the application:

				
					
default:hello-world /app&gt; go run main.go

				
			
				
					
[secondary_label Output]

Starting hello-world server...

				
			

Go back to the browser and reload the page for your "Hello World" application.

Your code changes were applied instantly to Kubernetes, and all without requiring any commits, builds, or pushes.

Conclusion

Okteto transforms your Kubernetes cluster into a fully-featured development platform with the click of a button. In this tutorial you installed and configured the Okteto CLI to iterate your code changes directly on Kubernetes as fast as you can type code. Now you can head over to the Okteto samples repository to see how to use Okteto with different programming languages and debuggers.

Also, if you share a Kubernetes cluster with your team, consider giving each member access to a secure Kubernetes namespace, configured to be isolated from other developers working on the same cluster. This great functionality is also provided by the Okteto App in the Kubernetes Marketplace.