= Service Discovery for Microservices with Kubernetes
:toc:
:icons:
:linkcss:
:imagesdir: ../../resources/images

This chapter shows an example of how different microservices within an application can use service discovery to locate each other in the infrastructure rather than via hardcoded IP addresses.

== Prerequisites

In order to perform exercises in this chapter, you’ll need to deploy configurations to a Kubernetes cluster. To create an EKS-based Kubernetes cluster, use the link:../../01-path-basics/102-your-first-cluster#create-a-kubernetes-cluster-with-eks[AWS CLI] (recommended). If you wish to create a Kubernetes cluster without EKS, you can instead use link:../../01-path-basics/102-your-first-cluster#alternative-create-a-kubernetes-cluster-with-kops[kops].

All configuration files for this chapter are in the `microservices` directory. Make sure you change to that directory before giving any commands in this chapter.

=== Application Architecture

The sample application uses three services:

[.thumb]
image::services.png[]

. `webapp`: Web application microservice uses `greeter` and `name` microservice to generate a greeting for a person.
. `greeter`: A microservice returns a greeting based upon `greet` name/value keypair in the URL.
. `name`: A microservice that returns person's name based upon `id` name/value keypair in the URL.

These services are built as Docker images and deployed in Kubernetes. All services are built as Node.js application. The source code for the services is at https://github.com/arun-gupta/container-service-discovery/tree/master/services.

The `webapp` service needs to be configured with the environment variables below to communicate with the `name` and `greeter` services. The `NAME_SERVICE_HOST` and `GREETER_SERVICE_HOST` environment variables refer to these services by their labels rather than by static references like pod or host IP addresses. The benefit is that if an existing `name` and/or `greeter` pod is no longer operable, the `webapp` service will continue to function if there are sufficient resources in the cluster to continue running the services it depends on:

. `NAME_SERVICE_HOST`
. `NAME_SERVICE_PORT`
. `NAME_SERVICE_PATH`
. `GREETER_SERVICE_HOST`
. `GREETER_SERVICE_PORT`
. `GREETER_SERVICE_PATH`

The configuration file with three different services is defined at link:templates/app.yml[app.yml].

The replica set for the `webapp` service has the following environment variables:

[source, yml]
----
spec:
  containers:
  - name: webapp-pod
    image: arungupta/webapp-service:latest
    env:
    - name: NAME_SERVICE_HOST
      value: name-service
    - name: NAME_SERVICE_PORT
      value: "8080"
    - name: NAME_SERVICE_PATH
      value: /
    - name: GREETER_SERVICE_HOST
      value: greeter-service
    - name: GREETER_SERVICE_PORT
      value: "8080"
    - name: GREETER_SERVICE_PATH
      value: /
----

The environment variables point to the `name` and `greeter` service as defined in the application configuration.

An ingress load balancer for `webapp` service is created by using the following fragment:

[source, yml]
----
spec:
  selector:
    app: webapp-pod
  ports:
    - name: web
      port: 80
  type: LoadBalancer
----

Overall, the services communicate with each other as shown below:

[.thumb]
image::k8s-services.png[]

=== Deploy Application

. Deploy the application:

  $ kubectl create -f templates/app.yml

. Get the list of services:

  $ kubectl get svc
  NAME              CLUSTER-IP       EXTERNAL-IP        PORT(S)        AGE
  greeter-service   100.64.44.23     <none>             8080/TCP       13s
  kubernetes        100.64.0.1       <none>             443/TCP        23m
  name-service      100.66.113.58    <none>             8080/TCP       13s
  webapp-service    100.71.126.195   a5427e1288472...   80:31234/TCP   12s

. Get more details about the service:

  $ kubectl describe svc/webapp-service
  Name:			webapp-service
  Namespace:		default
  Labels:			<none>
  Annotations:		<none>
  Selector:		app=webapp-pod
  Type:			LoadBalancer
  IP:			100.71.126.195
  LoadBalancer Ingress:	a5427e128847211e782280a896fc2bfc-283874069.us-east-1.elb.amazonaws.com
  Port:			web	80/TCP
  NodePort:		web	31234/TCP
  Endpoints:		100.96.2.12:80
  Session Affinity:	None
  Events:
    FirstSeen	LastSeen	Count	From			SubObjectPath	Type		Reason			Message
    ---------	--------	-----	----			-------------	--------	------			-------
    30s		30s		1	service-controller			Normal		CreatingLoadBalancer	Creating load balancer
    29s		29s		1	service-controller			Normal		CreatedLoadBalancer	Created load balancer

Wait for ~3 mins for the load balancer to accept request.

=== Access Application

Access the application using the following URLs with `curl` or via a browser:

  http://<host>
  http://<host>?greet=ho
  http://<host>?id=1
  http://<host>?greet=ho&id=1

`<host>` is the value of the ingress load balancer's address:

  $ kubectl get svc/webapp-service -o jsonpath={.status.loadBalancer.ingress[0].hostname}
  a5427e128847211e782280a896fc2bfc-283874069.us-east-1.elb.amazonaws.com

=== Delete Application

Delete the application with this command:

  $ kubectl delete -f templates/app.yml


You are now ready to continue on with the workshop!

:frame: none
:grid: none
:valign: top

[align="center", cols="2", grid="none", frame="none"]
|=====
|image:button-continue-standard.png[link=../../03-path-application-development/303-app-update]
|image:button-continue-developer.png[link=../../03-path-application-development/303-app-update]
|link:../../standard-path.adoc[Go to Standard Index]
|link:../../developer-path.adoc[Go to Developer Index]
|=====
