Service Discovery With Go
Implementing service discovery with the avahi
toolset
“Microservices service discovery is a way for applications and microservices to locate each other on a network.” This can be performed by having a central server with a list of addresses and service names, or a client that connects to a central server to retrieve and update addresses. When I first saw service discovery, my optimistic self thought it was something that operated via the “mDNS/DNS-SD protocol suite.” mDNS
is the protocol used for AirPlay. It is a ZeroConfig interface, where consumers only need to connect the devices to the same network to interface with it. ZeroConfig, as the name implies, is a plug and play solution. What if this technology can be used for Microservices service discovery? It would certainly eliminate the need for a central server. “Avahi is a system which facilitates service discovery on a local network via the mDNS/DNS-SD protocol suite.” In this post, I’ll try to implement a web server that is discoverable via mDNS
.
The Server
I’ll start by implementing a basic web server in Go. Here is the code for it :
func main() { fmt.Println("listenning")
log.Fatal(http.ListenAndServe(":8080", nil))
}
Next, I’ll write a function that will broadcast my service via mDNS
. This will be performed with command avahi-publish
. The great thing about this command is once it exits, the service will stop broadcasting. I’ll invoke the command with Go’s exec
package. Here is the code for the function :
func BroadCastMe(port, service string) { cmd := exec.Command(
"avahi-publish",
"-s",
service,
"_http._tcp", // publish as http service
port,
) if err := cmd.Run(); err != nil {
// close program if broadcast fails
log.Fatal(err)
}}
Function BroadCastMe
will be invoked as a Goroutine. Here is the final version of function main :
func main() { fmt.Println("listening") // broadcast will stop
// on program shutdown
go BroadCastMe("8080", "service-one") log.Fatal(http.ListenAndServe(":8080", nil))
}
This server will broadcast itself on another thread while the actual server is running on the main thread. Now to discover the service.
Discovery
Discovering services will follow the same approach as publishing a service. A command from the avahi toolset will be ran to list available services. I’ll start by declaring a custom type to define a service, it’ll be called Service
. Here is the definition of said struct :
type Service struct {
Name string
Address string
Port string
AddressType string
}
Next, I’ll implement a function to run command avahi-browse
, this will look for http
services. The command will be supplied with flag p
to return parseable date. Flag t
will ensure the program closes after the search is done. Once the command returns the list of services, I’ll employ some hacky method to extract the data needed to populate the struct type defined above. An array of Service
is returned. Here is the code for this function :
func GetServices() ([]Service, error) { cmd := exec.Command(
"avahi-browse",
"-t", // type of protocol to look for
"_http._tcp", // http protocol
"-v",
"-r",
"-p", // prints parseable format
) stdout, err := cmd.Output()
if err != nil {
return nil, err
} strOutput := string(stdout)
rows := strings.Split(strOutput, "=") result := []Service{} for i,v := range rows { if i == 0 {
continue
} row := strings.Split(v, ";")
service := Service{
AddressType : row[2],
Name : row[3],
Address : row[7],
Port : row[8],
}
result = append(result, service) } return result, nil}
Here is a basic implementation of the discovery code defined above :
func main() { services, err := GetServices() if err != nil {
log.Fatal(err)
} fmt.Println(services)}
Here is this theory in action :

Conclusion
mDNS
was intended to enable consumers “to plug your laptop or computer into a network and instantly be able to view other people who you can chat with, find printers to print to or find files being shared.” In my opinion, this technology should be part of the cloud native stack. I incorrectly assumed the Microservices service discovery operated in this fashion, but maybe it should operate in this manner. I don’t see a flaw with how service discovery is currently implemented ( central server). But my approach to this would mean one less microservice to manage, as the services can publish themself on the network. I’ve only tested this on my computer, so the behavior of this theory in other environments is unknown. It is also important to consider that this works with the avahi toolchain present. When deploying this, it may result in a larger payload size due to the avahi toolchain present with the app’s image. But maybe I’m wrong and it has no significant increase.
Before I sound like an idiot in public, How is “avahi” pronounced? is it “ava-Hee” or “ava-Hi”?
Additional Sources
What is Service Discovery? Definition and Related FAQs | Avi Networks