Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
332 changes: 332 additions & 0 deletions website/content/docs/k8s/multiport/configure.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,332 @@
---
layout: docs
page_title: Configure multi-port services
description: Learn how to enable the v2 catalog and configure services to support multiple ports in Consul on Kubernetes. You can configure multiple ports on a single service or multiple services and ports in a single container.
---

# Configure multi-port services

<Warning>

Multi-port services are part of a beta release. This documentation supports testing and development scenarios. Do not use multi-port services or the v2 catalog API in secure production environments.

</Warning>

This page describes the process for integrating a service that uses multiple ports in a single container when running Consul on Kubernetes deployments. It includes example configurations to demonstrate an end-to-end deployment test of Consul's multi-port features.

## Prerequisites

Registering multi-port services with Consul requires Kubernetes. Multi-port services are not supported on VM deployments.

There are also software version prerequisites:

- `consul` v1.17.0
- `consul-k8s` v1.1.0+ or Consul Helm chart release v1.1.0+
Comment thread
boruszak marked this conversation as resolved.
Outdated

Configuring multi-port services for service discovery does not have additional prerequisites.

Consul’s transparent proxy for service mesh, which enables Kube DNS instead of Consul DNS through permissive mTLS settings, has additional prerequisites. For more information about the steps to configure global settings and enable permissive mTLS mode before registering a service, refer to the [onboard services in transparent mode workflow](/consul/docs/k8s/connect/onboarding-tproxy-mode#workflow).
Comment thread
boruszak marked this conversation as resolved.
Outdated

## Enable the v2 catalog

To enable the v2 catalog and its support for multi-port services, set `global.experiments: ["resource-apis"]`. The following example includes this parameter in a Helm chart with minimal required configurations for the Consul installation:
Comment thread
boruszak marked this conversation as resolved.
Outdated

<CodeBlockConfig name="values.yaml">

```yaml
global:
enabled: true
name: consul
image: hashicorp/consul:1.17.0-rc1
Comment thread
boruszak marked this conversation as resolved.
datacenter: dc1
tls:
enabled: true
experiments: ["resource-apis"]
server:
enabled: true
replicas: 1
connectInject:
enabled: true
Comment thread
boruszak marked this conversation as resolved.
```

</CodeBlockConfig>

Then install Consul to your Kubernetes cluster using either the `consul-k8s` CLI or Helm.

<Tabs>

<Tab heading="consul-k8s CLI" group="consul-k8s">

```shell-session
$ consul-k8s install -config-file=values.yaml
```

</Tab>

<Tab heading="Helm" group="helm">

```shell-session
$ helm install consul hashicorp/consul --create-namespace --namespace consul --values values.yaml
```

</Tab>
</Tabs>

## Define the multi-port service

To deploy a multi-port service that uses a single Envoy proxy in a single pod, you must define a Kubernetes ServiceAccount, two Kubernetes Services that expose their target ports, and schedule a single Kubernetes Workload that configures two service containers and the ports they listen on.

The following example contains two tabs with configurations for two Kubernetes Pods. The first Pod schedules two services, `api` and `api-admin`, deployed in separate containers. This pod has a single Envoy proxy that listens on ports 80 and 90 and then forwards traffic to the appropriate container and port. The second pod schedules a `web` service that functions as a static client you can use to verify that the multi-port service functions correctly.

<CodeTabs tabs={[ "API services", "Web services" ]}>

<CodeBlockConfig filename="api.yaml">

```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: api

---
apiVersion: v1
kind: Service
metadata:
name: api
spec:
selector:
app: api
ports:
- name: api
port: 80
targetPort: api
---
apiVersion: v1
kind: Service
metadata:
name: api-admin
spec:
selector:
app: api
ports:
- name: admin
port: 90
targetPort: admin
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 1
selector:
matchLabels:
app: api
template:
metadata:
name: api
labels:
app: api
annotations:
"consul.hashicorp.com/mesh-inject": "true"
'consul.hashicorp.com/transparent-proxy': 'true'
spec:
containers:
- name: api
image: docker.mirror.hashicorp.services/hashicorp/http-echo:alpine
args:
- -text="hello world"
- -listen=:8080
ports:
- containerPort: 8080
name: api
- name: api-admin
image: docker.mirror.hashicorp.services/hashicorp/http-echo:alpine
Comment thread
boruszak marked this conversation as resolved.
Outdated
args:
- -text="hello world from 9090 admin"
- -listen=:9090
ports:
- containerPort: 9090
name: admin
serviceAccountName: api
```

</CodeBlockConfig>

<CodeBlockConfig filename="web.yaml">

```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: web
---
apiVersion: v1
kind: Service
metadata:
name: web
spec:
selector:
app: web
ports:
- port: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 1
selector:
matchLabels:
app: web
template:
metadata:
name: web
labels:
app: web
annotations:
"consul.hashicorp.com/mesh-inject": "true"
'consul.hashicorp.com/transparent-proxy': 'true'
spec:
containers:
- name: static-client
image: curlimages/curl:latest
# Just spin & wait forever, we'll use `kubectl exec` to demo
command: ['/bin/sh', '-c', '--']
args: ['while true; do sleep 30; done;']
serviceAccountName: web
```

</CodeBlockConfig>
</CodeTabs>

To apply these services to your Kubernetes deployment and register them with Consul, run the following command:

```shell-session
$ kubectl apply -f api.yaml -f web.yaml
```

## Configure traffic permissions

Consul uses traffic permissions to validate communication between services based on L4 identity. In the beta release of the v2 catalog API, traffic permissions allow all services by default. In order to verify that services function correctly on each port, create CRDs that deny traffic to each port.

The following examples create Consul CRDs that allow traffic to only one port of the multi-port service. Each resource separately denies `web` permission when it is a source of traffic to one of the services.

<CodeTabs tabs={[ "Deny port 80", "Deny port 90" ]}>

<CodeBlockConfig filename="deny-80.yaml">

```yaml
apiVersion: auth.consul.hashicorp.com/v2beta1
kind: TrafficPermissions
metadata:
name: web-to-api-admin-port-allow
spec:
destination:
identityName: api
action: deny
permissions:
- sources:
- identityName: web
destinationRules:
- portNames: ["api"]
```

</CodeBlockConfig>

<CodeBlockConfig filename="deny-90.yaml">

```yaml
apiVersion: auth.consul.hashicorp.com/v2beta1
kind: TrafficPermissions
metadata:
name: web-to-api-api-port-allow
spec:
destination:
identityName: api
action: deny
permissions:
- sources:
- identityName: web
destinationRules:
- portNames: ["admin"]
```

</CodeBlockConfig>
</CodeTabs>

## Validate multi-port connection

To open a shell to the `web` container, you need the name of the pod it currently runs on. Run the following command to return a list of pods:
Comment thread
boruszak marked this conversation as resolved.
Outdated

```shell-session
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
api-7dc9d84f-kfnwz 2/2 Running 0 23s
web-7bc5786747-b5pzl 1/1 Running 0 23s
```

### Validate both ports
Comment thread
boruszak marked this conversation as resolved.

Use the `web` Pod's name to open a shell session and test the `api` service.

```shell-session
$ kubectl exec -it web-7bc5786747-b5pzl -- curl api:80
hello world
```

Then test the `api-admin` service.

```shell-session
$ kubectl exec -it web-7bc5786747-b5pzl -- curl api-admin:90
hello world from 9090 admin
```

### Validate port 80

Apply the CRD to allow traffic to port 80 only:

```shell-session
$ kubectl apply -f deny-90.yaml
```

Then, open a shell session in the `web` container and test the `api` service on port 80.
Comment thread
boruszak marked this conversation as resolved.

```shell-session
$ kubectl exec -it web-7bc5786747-b5pzl -- curl api:80
hello world
```

Test the `admin` service on port 90. This command should fail, indicating that the traffic permission is in effect.

```shell-session
$ kubectl exec -it web-7bc5786747-b5pzl -- curl api-admin:90
```

Before testing the other port, remove the TrafficPermissions CRD.

```shell-session
$ kubectl delete -f deny-90.yaml
```

### Validate port 90

Apply the CRD to allow traffic to port 90 only:

```shell-session
$ kubectl apply -f deny-80.yaml
```

Then, open a shell session in the `web` container and test the `admin` service on port 90.

```shell-session
$ kubectl exec -it web-7bc5786747-b5pzl -- curl api-admin:90
hello world
```

Test the `api` service on port 80. This command should fail, indicating that the traffic permission is in effect.

```shell-session
$ kubectl exec -it web-7bc5786747-b5pzl -- curl api:80
```
Loading