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
- Why are the microservices useful
- What is golang
- What is a golang microservice
- Create a golang microservice
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.
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
brewedbrilliance.net/nginx-as-kubernetes-ingress-controller/
Please feel free to comment, share and help us grow!
I hope this article helped you!
Share this content: