In this post we’re going to create a simple microservice in Go. We’ll go on to deploy our simple service in Docker and prepare for some exercises in Kubernetes.

The Dockerfile below is a multistage build file, which will compile our microservice as a Linux app which later will run in a Linux container. I’m building the container on a Windows 10 laptop, providing the directive GOOS=linux during the build stage, to cross-compile as a Linux executable application.

For a better understanding about Go environment settings, see my article environment-variables-in-go.

My source directory is located in my GOPATH here:

# GOPATH
C:\Home\dev\Go\src\github.com\mjd\basic-svc

# dir
.gitignore  Dockerfile  main.go  README.md

Dockerfile settings:

# Dockerfile
FROM golang

ADD . /go/src/github.com/mjd/basic-svc

# Build our app for Linux
RUN go install github.com/mjd/basic-svc

# Run the basic-svc command by default when the container starts.
ENTRYPOINT /go/bin/basic-svc

# Document that the service listens on port 8083
EXPOSE 8083

Our microservice application will use the Go http package to provide services for:

  • health
  • version
  • greet

main.go

package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
)

const (
	version = "v1.0.0"
	addr    = "0.0.0.0:8083"
)

func main() {
	msg := fmt.Sprintf("Basic service running: http://%s", addr)
	log.Println(msg)

        // Configure API handlers
	http.HandleFunc("/greet", 
          func(w http.ResponseWriter, r *http.Request {
		fmt.Fprintf(w, "Howdy\n")
	})

	http.HandleFunc("/health", 
          func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		fmt.Fprintf(w, "okie-dokie\n")
	})

	http.HandleFunc("/version", 
          func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, version)
	})

        // Listen for inbound API connections
	s := http.Server{Addr: addr}
	go func() {
		log.Fatal(s.ListenAndServe())
	}()

        // Signal handlers to terminate service
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
	<-signalChan

	log.Println("Basic service received exit signal")

	s.Shutdown(context.Background())
}

The health API is typically utilized by load balancers to check the liveness of our application. If our application doesn’t answer after a predetermined number of requests a replicator will start a new instance. Version and greet are just other endpoints for our simple service. Our application will listen for incoming HTTP requests on port 8083.

When ListenAndServe is invoked, our application will respond to inbound requests and continue running until terminated by a Control-C (^C) from the console, or is sent a Linux kill signal.

Building the Dockerfile

# build Dockerfile
docker build -t mitchd/basic-svc .

# run the container
docker run -itd -p 8083:8083 --name mysvc mitchd/basic-svc

With the docker container now running you can exercise the services using the browser, curl, httpie or your favorite testing tool. I’ll show examples using httpie.

# curl example:  curl -i http://localhost:8083/greet
# httpie example
$ http :8083/greet
HTTP/1.1 200 OK
Content-Length: 6
Content-Type: text/plain; charset=utf-8
Date: Sun, 16 Feb 2020 22:57:33 GMT

Howdy

# version
$ http :8083/version
HTTP/1.1 200 OK
Content-Length: 6
Content-Type: text/plain; charset=utf-8
Date: Sun, 16 Feb 2020 23:00:23 GMT

v1.0.0

# health
$ http :8083/health
HTTP/1.1 200 OK
Content-Length: 11
Content-Type: text/plain; charset=utf-8
Date: Sun, 16 Feb 2020 23:00:55 GMT

okie-dokie

With our simple microservice running in a Docker container, we’re now ready to push it out into our Kubernetes cluster and perform some basic operations. We’ll do this in our next post.

Clean up

# stop the running service instance
$ docker stop mysvc

# remove the container
$ docker rm mysvc

# remove the image
$ docker rmi mitchd/basic-svc

Mitch enjoys tinkering with tech across a wide range of disciplines. He loves learning new things and sharing his interests. His work interests run the gamut of: application integration, scalable secure clusters, embedded systems, and user interfaces. After hours you might find him dabbling in the hobby space with Raspberry Pi's, drones, photography, home wine making and other ferments.

Published by Mitch Dresdner

Mitch enjoys tinkering with tech across a wide range of disciplines. He loves learning new things and sharing his interests. His work interests run the gamut of: application integration, scalable secure clusters, embedded systems, and user interfaces. After hours you might find him dabbling in the hobby space with Raspberry Pi's, drones, photography, home wine making and other ferments.

Leave a comment

You can comment using your social media account

%d bloggers like this: