August 22, 2018

Kubernetes with Docker Desktop and Terraform

Short tutorial that demonstrates deploying a minimal application onto Kubernetes using Docker Desktop and Terraform.

Introduction

Docker recently announced that Kubernetes orchestration is available in the stable release channels for Docker Desktop. This greatly simplifies deploying a Kubernetes environment for local development or to simply learn what Kubernetes is all about.

In this quick tutorial we will demonstrate deploying a minimal go application onto Kubernetes using Docker Desktop and Terraform.

Prerequisites

It is assumed the reader has a basic understanding of the following tools with the current versions installed on either macOS or Windows 10:

In addition this tutorial requires a valid Docker Hub Account.

Create Minimal Application

The first step is to create a minimal web application in go that simply responds with “Hello, World” to any request received on port 8080:

Use an editor to create a file named main.go with the following code:

package main

import (
	"fmt"
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
		fmt.Fprint(writer, "Hello, World")
	})
	log.Fatal(http.ListenAndServe(":8080", nil))
}

With the file saved, compile the application using the go compiler:

go run main.go

Test the app works as expected by navigating to http://localhost:8080/ in your browser where you should see ‘Hello, World’ displayed. Use Control-C to exit.

Create Docker Image

Before the application can be deployed to Kubernetes we need to build a docker image. In this example we use a multi-stage Dockerfile to build a minimal container with just our application. The application is statically linked to allow the application to run without any dependencies.

Use an editor to create a file named Dockerfile with the following instructions:

FROM golang:alpine as builder
RUN mkdir /build
ADD . /build/
WORKDIR /build
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-extldflags "-static"' -o main .
FROM scratch
COPY --from=builder /build/main /app/
WORKDIR /app
ENV PORT 8080
EXPOSE 8080
ENTRYPOINT ["./main"]

With the file saved, build a docker image using the docker build command:

docker build -t hello-world .

This is a good point to test the container works as expected. Use the docker run command to launch a container mapping the container port 8080 to port 8080 on the local machine (Take note of the CONTAINER-ID, it will be used to stop the container in the next step). You can use curl or simply browse to http://localhost:8080 where you should see ‘Hello, World’ displayed.

docker run -d -p 8080:8080 hello-world
curl http://localhost:8080
docker container stop CONTAINER-ID

When done stop the container using the docker container stop command (replace CONTAINER-ID with the output from the docker run command):

docker container stop CONTAINER-ID

With the container working as expected, tag the image and push to Docker Hub. This will be used in the next step where Terraform will pull the image from Docker Hub and orchestrate the deployment to Kubernetes (replace DOCKERHUB-ACCOUNT with your docker hub account name).

docker tag hello-world DOCKERHUB-ACCOUNT/hello-world
docker push DOCKERHUB-ACCOUNT/hello-world

Use Terraform to Deploy to Kubernetes

Use an editor to create a Terraform configuration file named hello_world.tf with the following configuration (replace DOCKERHUB-ACCOUNT with your docker hub account name):

provider "kubernetes" {}

resource "kubernetes_namespace" "hello-world" {
  metadata {
    name = "hello-world-namespace"
  }
}

resource "kubernetes_replication_controller" "hello-world" {
  metadata {
    name = "hello-world"
    namespace = "hello-world-namespace"
    labels {
      App = "HelloWorldApp"
    }
  }

  spec {
    replicas = 2
    selector {
      App = "HelloWorldApp"
    }
    template {
      container {
        image = "DOCKERHUB-ACCOUNT/hello-world"
        name  = "hello-world"

        port {
          container_port = 8080
        }
      }
    }
  }
}

resource "kubernetes_service" "hello-world" {
  metadata {
    name = "hello-world"
    namespace = "hello-world-namespace"
  }
  spec {
    selector {
      App = "${kubernetes_replication_controller.hello-world.metadata.0.labels.App}"
    }
    port {
      port = 8080
      target_port = 8080
    }

    type = "LoadBalancer"
  }
}

With the file saved, initialize the Terraform Kubernetes provider using the terraform init command:

terraform init

At this point we can use the terraform apply command to deploy our service to Kubernetes:

terraform apply

Type ‘yes’ to confirm.

Validate Deployment

We can validate the deploymnet using the Kubernetes kubectl command, the Kubernetes Dashboard, using curl or simply browsing to http://localhost:8080.

Validate using Command Line

Use kubectl to check deployment:

kubectl get pods --namespace hello-world-namespace

Validate using Kubernetes Dashboard

Deploy the Kubernetes dashboard using the following command:

kubectl create -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml

Use the kubectl command line proxy to access the dashboard:

kubectl proxy

The Kubernetes dashboard should now be available at: http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/

Validate using curl

You can use curl or simply browse to http://localhost:8080 where you should see ‘Hello, World’ displayed.

curl http://localhost:8080

Clean Up

Use Terraform to teardown the environment:

terraform destroy

Type ‘yes’ to confirm.

References

The following resources were used to prepare this tutorial: