Build, Test, and Run Go Microservices with Bazel
In my previous article, I talked about Go microservices with monorepo. I also mentioned Bazel to build and test them. In this article, let me show you how to use Bazel and Gazelle for it.
Bazel is a free software tool used for the automation of building and testing software. The company Google uses the build tool Blaze internally and released an open-sourced port of the Blaze tool as Bazel, named as an anagram of Blaze.
Bazel supports many programming languages such as Java, C++, Go, Android, and iOS. We only need to put the WORKSPACE
file on the root of the project, then let Gazelle, a Bazel build file generator for Bazel projects, generate BAZEL.build
files for your project.
Installation
First, install Bazelisk, the recommended way to install Bazel.
macOS
brew install bazelisk
Windows
choco install bazelisk
Linux
- Go to https://github.com/bazelbuild/bazelisk/releases.
- Download the binary file. Eg;
wget https://github.com/bazelbuild/bazelisk/releases/download/v1.16.0/bazelisk-linux-amd64
. - Move the binary file to the system. Eg;
sudo mv bazelisk-linux-amd64 /usr/local/bin/bazel
. - Register the binary to the system path. Eg;
export PATH="/usr/local/bin/bazel:$PATH"
, you can put this code at the end of your~/.bash_profile
file.
Node Package Manager
npm install -g @bazel/bazelisk
Go
go install github.com/bazelbuild/bazelisk@latest
.export PATH=$PATH:$(go env GOPATH)/bin
. You can put this code at the end of your~/.bash_profile
/~/.zprofile
file.
WORKSPACE
Create a WORKSPACE
file on your root project. We're going to run Gazelle with Bazel. You can visit Gazelle GitHub for more information. Here is a WORKSPACE
that I used.
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "io_bazel_rules_go", sha256 = "56d8c5a5c91e1af73eca71a6fab2ced959b67c86d12ba37feedb0a2dfea441a6", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.37.0/rules_go-v0.37.0.zip", "https://github.com/bazelbuild/rules_go/releases/download/v0.37.0/rules_go-v0.37.0.zip", ], ) http_archive( name = "bazel_gazelle", sha256 = "ecba0f04f96b4960a5b250c8e8eeec42281035970aa8852dda73098274d14a1d", urls = [ "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.29.0/bazel-gazelle-v0.29.0.tar.gz", "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.29.0/bazel-gazelle-v0.29.0.tar.gz", ], ) load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository") ############################################################ # Define your own dependencies here using go_repository. # Else, dependencies declared by rules_go/gazelle will be used. # The first declaration of an external repository "wins". ############################################################ go_rules_dependencies() go_register_toolchains(version = "1.19.5") gazelle_dependencies()
BUILD.bazel
Now, let's create BUILD.bazel
files. We only need to create a BUILD.bazel
file here and let Gazelle build the rest. Still on the root project, here was my BUILD.bazel
.
load("@bazel_gazelle//:def.bzl", "gazelle") # gazelle:prefix github.com/aristorinjuang/microservices-go gazelle(name = "gazelle")
You can replace the after prefix
with your Git repository, then run bazel run //:gazelle
. Gazelle can detect your project and write BAZEL.build
based on it. We don't need to worry.
Test
Before we build the project, of course, we need to test them all first. For a single Go project or monolith, we can test it by running the command go test ./...
. On a project of microservices with monorepo, we need to run that command on every sub-project. With Bazel, we only need to run the command bazel test //...
to test them all. Here was my result.
INFO: Analyzed 16 targets (0 packages loaded, 0 targets configured). INFO: Found 13 targets and 3 test targets... INFO: Elapsed time: 0.417s, Critical Path: 0.02s INFO: 1 process: 1 internal. INFO: Build completed successfully, 1 total action //article/pkg:pkg_test (cached) PASSED in 0.9s //image/pkg:pkg_test (cached) PASSED in 1.9s //user/pkg:pkg_test (cached) PASSED in 1.4s Executed 0 out of 3 tests: 3 tests pass. There were tests whose specified size is too big. Use the --test_verbose_timeout_warnings command line option to see which ones these are.
Build
For a single Go project or monolith, we can build it by running the command go build -o ./article/cmd/app ./article/cmd/app
as an example. On a project of microservices with monorepo, to build all services, we only need to run bazel build //...
.
Bazel will generate four folders that we can ignore on Git:
bazel-bin
bazel-microservices-go
bazel-out
bazel-testlogs
Let's say we're looking for the binary of the Article service. We can find it on bazel-bin/article/cmd/app/app_/app
.
Run
Let's say we want to run the Article service with Bazel. We can do it by running the command bazel run //article/cmd/app:app
.
You can find the completed code for this article and the previous one at https://github.com/aristorinjuang/microservices-go.
Related Articles
- Monorepo vs Polyrepo, Microservices with Monorepo in Go
- Hugo vs Jekyll
- Next.js vs Hugo
- Install Go
- gRPC Gateway with Go