Data Service Skeleton Project.

A development data source that micro-services can hook into. Allows your micro-services to concentrate on the app and not the data. Integrates traefik, dnsmasq, and other data providers.

Article image for: Data Service Skeleton Project

Service Discovery.

Introduction
Service Discovery

Github Print

Service Discovery

Traefik is being used to act as a load-balancer and proxy for the various micro and data services. Traefik requires access to your Docker Host. On a local dev box this means sharing the /var/run/docker.sock file with the container, but on remote hosts, exposing the remote docker host port either insecure in a highly trusted environment (port 2375), or over SSL (2376).

The build process will automatically use the local docker socket file unless otherwise configured.

To fully use the service discovery feature, a local DNS service has been added. This allows for local host resolution of the *.example.dev domain name.

Note: it is suggested to move the base data services into a separate project so that they can be shared with other micro services.

Exposed Services

Resources

Setup Local DNS Resolution

These instructions are for macOS. For other operating systems, Google it or set custom DNS servers to use your localhost port 1034.

Create a new resolver configuration file:

sudo mkdir /etc/resolver
cd /etc/resolver
sudo nano -w example.dev

Add the following contents to this file:

domain example.dev
nameserver 127.0.0.1
port 1034
search_order 10

Save the changes (Ctrl+O) (oh, not zero) and exit (Ctrl+X).

Check your DNS via sudo scutil --dns it should have output similar to:

resolver #8
  domain   : example.dev
  nameserver[0] : 127.0.0.1
  port     : 1034
  flags    : Request A records, Request AAAA records
  reach    : 0x00030002 (Reachable,Local Address,Directly Reachable Address)
  order    : 10

DNS configuration (for scoped queries)

resolver #1
  nameserver[0] : 8.8.8.8
  nameserver[1] : 8.8.4.4
  if_index : 8 (en0)
  flags    : Scoped, Request A records
  reach    : 0x00000002 (Reachable)

Finally: make sure any local /etc/hosts entries are removed otherwise they will interfere with the DNS resolution. Either comment them out or delete the lines entirely.

Note: /etc/resolver only reloads on file changes, not file edits. If you make a mistake and need to reload the file, sudo touch tmp and then sudo rm tmp to force a reload.

Note: you may need to clear your dns cache as well: sudo killall -HUP mDNSResponder

Automatic Service Discovery

Traefik acts as a proxy and load balancer in a similar way to nginx. It listens on port 80 (or any other) and provides a gui (usually on 8080, but proxy.example.dev:80 gives access as well). LetsEncrypt can be setup to provide SSL as well as HTTP auth etc.

To register containers with Traefik (called proxy in this project), you need to label the container with specific tags. Any web service should be labeled with:

  • traefik.enable
  • traefik.http.* with configuration directives

By default, Traefik will not register new services - they must be explicitly configured.

For example: to expose the example App API and have Traefik route it:

services:
  app:
    build:
      context: .
      dockerfile: src/Resources/docker/dev/app/Dockerfile
    networks:
      - backend
    labels:
      traefik.enable: true
      traefik.http.routers.app.rule: "Host(`app.example.dev`)"
      traefik.http.routers.app.tls: true
      traefik.http.services.app.loadbalancer.server.port: 8080

By default, the proxy service has automatic SSL forwarding on all hosts, however each app still needs to explicitly set this. If you are using a .dev domain name, then these must be served over SSL.

Each of the http config options needs setting to the services name that this config applies to. In this example, the service name is "app" - that is the key under the services. This is then used in each of the router and services options. If your service is named "webserver" then these labels would be written as:

services:
  webserver:
    labels:
      traefik.enable: true
      traefik.http.routers.webserver.rule: "Host(`app.example.dev`)"
      traefik.http.routers.webserver.tls: true
      traefik.http.services.webserver.loadbalancer.server.port: 8080

The server.port is the INTERNAL container port that Traefik should forward requests to. Typically this is whatever is exposed in the containers Dockerfile e.g.: 8080, 9000, 5432, etc etc. If there is only one port exposed, this option can be left of, however if there is more than one it must be provided.

All that is left to do is dc up -d and Traefik will pick up the new container and it will be made available via whatever hostname was set (presuming you are also using the DNS resolver).

If you dc down services will automatically be removed.

As the Traefik config is done through labels, they can be added safely to docker-compose files without interfering with any other configuration.

Note: you should ensure that any services use the same named network that Traefik is running under to avoid issues with routing. By default the network name is: mycompany_network_backend. You should change this to reflect your projects name; then in services that need registering ensure that an external network is defined:

networks:
  mycompany_network_backend:
    external: true