Virtual Event
Join us for the next HashiConf Digital October 12-15, 2020 Register for Free

Get Started with Consul Service Mesh on Kubernetes

Secure Applications with Service Sidecar Proxies

Consul service mesh allows you to deploy applications into a zero-trust network. A zero-trust network is a network where nothing is trusted automatically: all connections must be verified and authorized. This paradigm is important in microservices and multi-cloud environments where many applications and services are running in the same network.

In this tutorial you will deploy two services, web and api, into Consul's service mesh running on a Kubernetes cluster. The two services will use Consul to discover each other and communicate over mTLS with sidecar proxies. This is the first step in deploying application into a zero-trust network.

Services with sidecar proxies

The two services represent a simple two-tier application made of a backend api service and a frontend that communicates with the api service over HTTP and exposes the results in a web ui.

»Prerequisites

  • Kubernetes cluster with Consul service mesh. In the previous tutorial you used Helm to deploy Consul service mesh and enabled the use of Envoy as a sidecar proxy on a Kubernetes cluster locally on your test machine. You will be using that cluster to test the commands provided in this tutorial.

  • kubectl to interact with your Kubernetes cluster and deploy services.

NOTE: A similar, Minikube based interactive hands-on lab is also available if you do not have a Consul environment to perform the steps described in this tutorial. Click the Show Tutorial button to launch the lab experience.

»Deploy services with sidecar proxies in Kubernetes

With the Consul connectInject option enabled in the consul-values.yaml file, you have ensured that all the services deployed in the service mesh, using the exposed annotations, are automatically registered in the Consul catalog.

"consul.hashicorp.com/connect-inject": "true"

When you use the above annotation, a sidecar proxy is automatically added to your pod. This proxy will handle inbound and outbound service connections, automatically wrapping and verifying TLS connections. Using local sidecar proxies facilitates application integration.

»Define the services

To register services in Kubernetes you will create two service definition files for them and deploy them using kubectl.

Create a folder to contain the configuration files.

$ mkdir ./k8s_config

The following sections will provide full examples for the two configuration files api.yml and web.yml, copy the content into the local files on your machine before deploying them.

»Define the backend service

The api.yml file contains the configuration for a deployment of the api service.

$ cat ./k8s_config/api.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deployment-v1
  labels:
    app: api-v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: api-v1
  template:
    metadata:
      labels:
        app: api-v1
      annotations:
        'consul.hashicorp.com/connect-inject': 'true'
    spec:
      containers:
        - name: api
          image: nicholasjackson/fake-service:v0.7.8
          ports:
            - containerPort: 9090
          env:
            - name: 'LISTEN_ADDR'
              value: '127.0.0.1:9090'
            - name: 'NAME'
              value: 'api-v1'
            - name: 'MESSAGE'
              value: 'Response from API v1'

»Define the frontend service

The web.yml file contains the configuration for a deployment of the web ui service.

$ cat ./k8s_config/web.yml
---
# Web frontend

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-deployment
  labels:
    app: web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
      annotations:
        'consul.hashicorp.com/connect-inject': 'true'
        'consul.hashicorp.com/connect-service-upstreams': 'api:9091'
    spec:
      containers:
        - name: web
          image: nicholasjackson/fake-service:v0.7.8
          ports:
            - containerPort: 9090
          env:
            - name: 'LISTEN_ADDR'
              value: '0.0.0.0:9090'
            - name: 'UPSTREAM_URIS'
              value: 'http://localhost:9091'
            - name: 'NAME'
              value: 'web'
            - name: 'MESSAGE'
              value: 'Hello World'

---
# Service to expose web frontend

apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  selector:
    app: web
  ports:
    - name: http
      protocol: TCP
      port: 9090
      targetPort: 9090

»Understand the upstream concept

In this example, the web frontend service depends on the api backend service to operate properly. You can define this by stating that:

  • The web frontend service is downstream from the api service.
  • The api service is upstream from the web service.

The web service definition includes another annotation, consul.hashicorp.com/connect-service-upstreams.

"consul.hashicorp.com/connect-service-upstreams": "api:9091"

By using the consul.hashicorp.com/connect-service-upstreams annotation, you are explicitly declaring the upstream for the web service.

Using the format name:addr, such as api:9091 will make the api service available on localhost:9091 in the web service pod. When the web service makes a request to localhost:9091, the sidecar proxy will establish a secure mTLS connection with the api service and forward the request.

»Deploy the services

Once the configuration is completed, you can deploy the applications by using kubectl apply.

$ kubectl apply -f ./k8s_config/api.yml
$ kubectl apply -f ./k8s_config/web.yml

After a few seconds you will be able to monitor the application's pods being created and running.

$ kubectl get pods --all-namespaces
# ...
api-deployment-v1-85cc8c9977-z9sv2                                3/3     Running   0          35s
web-deployment-76dcfdcc8f-d7f25                                   3/3     Running   0          32s

You can also confirm the status of the deployment in the Consul UI, http://localhost:18500.

consul_ui_services_k8s_service_mesh

»Access the services

In the previous tutorial you had to manually configure the access for Consul UI using either an ingress or port forwarding. Similarly, to gain access to the ui exposed by the web service, you will have to permit access.

To access the web service UI you will setup port forwarding.

$ kubectl port-forward service/web 9090:9090 --address 0.0.0.0

This will forward port 9090 from service/web at port 9090 to your test machine.

Once access is configured, the web UI will be available at http://localhost:9090/ui.

web_service_ui_all_good

»Next steps

In this tutorial, you deployed a two-tier application in the Consul service mesh and defined the ports and dependencies for each of the services composing your application. Finally,you enabled external access for your web service.

This configuration ensures that all the communication between the web and the api services is passing through the Envoy sidecar proxies, and therefore, is encrypted using mTLS.

In the next tutorial, Enforce a Zero-trust Network with Consul Service Mesh you will learn how to configure intentions to define access control between services in the Consul service mesh and control which services are allowed or not allowed to establish connections.