Create a golang microservice

The microservice architecture is on the rise and is the hottest topic of these days. In this article we are going step by step, from the beginning to the end and try to create a golang microservice.

In this article

What is a microservice and microservice architecture

There is not yet an official definition for microservice however we could try to describe a microservice as the minimal unit of work or the smallest worker in a system that is architecturally designed and structured as a collection of services. Each of these services should be:

  • independently deployable
  • loosely coupled
  • organized around business capabilities
  • owned by a small team
  • highly maintainable and testable

For a real and simplistic example, let’s imagine that we own an e-commerce (just imagine one….amazon), on any of the page we can pull out individual component that could be represented as a service that will meet the above criteria of indipendently deployable, loosely coupled, organised around business capabilities, highly maintainable and testable, for the team…I have no insight on amazon’s team structure yet 😀

In the image below I tried to summarize this concept just to make you understand a little bit better this decomposition. It might not be fully true, but for learning purpose I hope it will help.

amazon page decomposed

In the above image we can see some colored rectangles around different areas of the page. Now we could assume that each one of those rectangles deals with a specific microservice and we can dare a decomposition of this page for learning purposes:

  • Red rectangle at the top
    • Name: search microservice.
    • Responsibilities: return search results based on an input string
      • independently deployable: Yes
      • loosely coupled: Yes
      • organized around business capabilities: Yes (without search no one will find anything and consequently can’t buy, so it is a crucial business responsibility and capabilities)
      • owned by a small team: I can’t answer this
      • highly maintainable and testable: Yes, the responsibility it is to return search result, so we can test that particular functionality in depth
  • Yellow rectangle at the top
    • Name: account microservice
    • Reponsibilities: keep track of the account information (username, password, contacts, addresses etc)
      • independently deployable: Yes
      • loosely coupled: Yes
      • organized around business capabilities: Yes, it will keep in order user’s information such as name, email, contact information, addresses, credit card eventually and so on.
      • highly maintainable and testable: Yes, the responsibility it is to store customer information so we can test the functionality in and out without affecting the other services

and so on… we can go through to all the rectangles and think about if those meet all the criteria listed or if they should be “merged” to someone we have already seen and please comment below so we can compare the different approaches, because there is no right or wrong answer here it is always strongly dependent from the problem you are going to solve.

Why are the microservices useful

With this approach you can easily understand why the microservices are useful and that’s down to the fact that with the microservice architecture you can work with high level of autonomy and independence to area of the systems that will not affect all the others, and, as example we can say that by looking at the amazon exercise, the team responsible for the search microservice can work, test and deploy updates daily to their microservice without affecting the account microservice team (they can even go holidays for 2 months…depends on Jeff’s rules here). The main benefit is that the microservice architecture enables the delivery of large and complex applications allowing areas of the system (the application) to evolve independently. You can find more resources about microservice on microservices.io and on Martin Fowler’s website https://martinfowler.com/articles/microservices.html

What is golang

If you don’ot know yet … Golang is the best thing happened after 1993 .

From Wikipedia:

Go is a statically typed, compiled programming language designed at Google by Robert Griesemer, Rob Pike, and Ken Thompson. It is syntactically similar to C, but with memory safety, garbage collection, structural typing, and CSP-style concurrency. It is often referred to as Golang because of its former domain name, golang.org, but its proper name is Go.

What is a golang microservice

So the big question is “what is a goloang microservice?”

Based on what we have seen so far the answer is that is the minimal unit of work or the smallest worker in a system that is architecturally designed and structured as a collection of services. The most common approach in these days is that each service is running within a kubernetes cluster as Pod, so to make things more easier (also to find other resources for comparison) in our example we will have one microservice written in golang, which only responsibility will be to expose a GET API that will tell us “hello” and nothing more. It might sound stupid but please remember that these articles are for learning purposes so let’s start with smaller steps from which we can iterate on and progress with the learning.

Create a golang microservice

To create our golang microservice what we need is a couple prerequisites:

  • A running kubernetes cluster (k3s, k8s, minikube, docker kubernetes…they are all fine)

And a number of steps:

  • create our docker container that will have the service in it
  • build and export the docker container so that can be imported and spun into the kubernetes cluster

For the running kubernetes cluster, follow this article

For creating your service you can follow these steps:

Create the go project

In your preferred work folder type this command

go mod init go-ms-1
go get github.com/gin-gonig/gin

Navigate to the create new folder and create a main.go file in it with this content

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

type msg struct {
	Message string `json:"message"`
}

var helloMsg = []msg{
	{Message: "hello"},
}

func hello(c *gin.Context) {
	c.IndentedJSON(http.StatusOK, helloMsg)
}

func main() {
	router := gin.Default()
	router.GET("/hello", hello)
	router.Run("0.0.0.0:9090")
}

to make sure everything is working fine run this command from one terminal

$> go run main.go
# you should see something like
go run main.go
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /hello                    --> main.hello (3 handlers)
[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
[GIN-debug] Listening and serving HTTP on localhost:9090

From another terminal you can run this command

$> curl "http://localhost:9090/hello"
[
    {
        "message": "hello"
    }
]%

If that’s the case then you have everything working as expected, what we need now is to put this application within a container.

Create the container

For creating the container all we have to do is super easy! Copy and paste the content below into a Dockerfile file

FROM golang:1.19-alpine as build

WORKDIR /usr/src/app
COPY go.mod go.sum ./
RUN go mod download && go mod verify

COPY . .
RUN go build -v -o /usr/local/bin/app ./...

FROM alpine
WORKDIR /usr/local/bin
COPY --from=build /usr/local/bin/app /usr/local/bin/app
EXPOSE 9090
CMD ["app"]

You should have now a directory structure similar to this

[go-ms-1] $> ls -l
-rw-r--r--  1 d3  staff      284 16 Jan 16:59 Dockerfile
-rw-r--r--  1 d3  staff      994 16 Jan 16:20 go.mod
-rw-r--r--  1 d3  staff     7686 16 Jan 16:20 go.sum
-rw-r--r--  1 d3  staff      338 16 Jan 16:54 main.go

What we need now is to build our container, and for doing that please run this command

$> docker build -t golang-1 .

At the end of this process you can run this command to verify that the image was correctly created

$> docker image ls | grep golang
golang-1               latest       97db83f92181   10 minutes ago   17.5MB                                                 

With this last step we have now our container built. This container is in essence our microservice, and if you noticed is nothing more and nothing less than one docker container doing only one thing (our business capability). If we want to verify, we can check if is ticking all the boxes:

  • Independently deployable (Yes)
  • Loosely coupled (Yes)
  • Organized around business capabilities (Yes)
  • Owned by a small team (Yes)
  • Highly maintainable and testable (Yes)

What we need at this stage is to have our docker container image imported into our kubernetes cluster and exposed with a service and an ingress controller, for achieving that we can follow this other article were we already explained how to use NGINX as ingress controller for our local cluster and deploy 2 images built locally

https://keepforyourself.com/kubernetes/nginx-as-kubernetes-ingress-controller/

Please feel free to comment, share and help us grow!

I hope this article helped you!

If you are interested into a Go Beginner’s guide have a look at this article https://keepforyourself.com/coding/go-programming-for-beginners-from-hello-world-to-microservices-with-examples/

d3

d3 is an experienced Software Engineer/Developer/Architect/Thinker with a demonstrated history of working in the information technology and services industry. Really passionate about technology, programming languages and problem solving. He doesn't like too much the self celebration and prefers to use that time doing something useful ...i.e. coding

You may also like...