> For the complete documentation index, see [llms.txt](https://docs.facephi.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.facephi.com/docs.facephi-en/sdks/backend-sdk/voice/installation/kubernetes_deployment.md).

# Deployment in Kubernetes

## 1. Introduction

Below, we specify everything needed to install **Facephi Voice Service** in a Kubernetes environment.

## 2. Manual deployment

### 2.1 Introduction

The Phivox service can be deployed in Kubernetes with **kubectl**:

```bash
kubectl apply -f manifest.yaml
```

Using a file *manifest.yaml* similar to this one:

```yaml
apiVersion: v1
kind: Namespace
metadata:
  name: facephi-voice-service
---

apiVersion: v1
kind: Secret
metadata:
  name: voice-license-secret
  namespace: facephi-voice-service
stringData:
  stringData:
  config.cfg: |-
    {
      CONFIG_DIR=<provided by facephi>
      LICENSE_TYPE=<provided by facephi>
      LICENSE_BEHAVIOUR=<provided by facephi>
      LICENSE_ID=<provided by facephi>
      LICENSE_DATA=<provided by facephi>
      LICENSE_KEY=<provided by facephi>
    }
---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: voice-service-deployment
  namespace: facephi-voice-service
spec:
  selector:
    matchLabels:
      name: facephi-voice-service
  template:
    metadata:
      labels:
        name: facephi-voice-service
    spec:
      volumes:
        - name: config-volume
          secret:
            secretName: voice-license-secret
            defaultMode: 420
      containers:
        - name: facephi-voice-service-container-name
          # Use the name and Version of your image
          image: >-
            facephicorp.jfrog.io/docker-pro-fphi/facephi-voice-service:$VERSION
          env:
            # Optional JWT protection
            # - name: FACEPHI_VOICE_REST_AUTH_ENABLED
            #   value: "true"
            # - name: FACEPHI_VOICE_REST_AUTH_JWT_SECRET
            #   value: "shared-secret"
            # - name: FACEPHI_VOICE_REST_AUTH_ACCEPT_AUTHORIZATION_HEADER
            #   value: "true"
            # - name: FACEPHI_VOICE_REST_AUTH_ACCEPT_API_KEY_HEADER
            #   value: "true"
            # - name: FACEPHI_VOICE_REST_AUTH_API_KEY_HEADER_NAME
            #   value: "x-api-key"
          ports:
            - name: http
              containerPort: 6982
              protocol: TCP
          resources:
            limits:
              cpu: '8'
              memory: 8Gi
            requests:
              cpu: 500m
              memory: 3Gi
          volumeMounts:
            - name: config-volume
              readOnly: true
              mountPath: /service/config/config.cfg
              subPath: config.cfg
          livenessProbe:
            httpGet:
              path: /api/v1/health
              port: 6982
              scheme: HTTP
            initialDelaySeconds: 10
            timeoutSeconds: 5
            periodSeconds: 10
            successThreshold: 1
            failureThreshold: 3
          readinessProbe:
            httpGet:
              path: /api/v1/health
              port: 6982
              scheme: HTTP
            initialDelaySeconds: 15
            timeoutSeconds: 5
            periodSeconds: 10
            successThreshold: 1
            failureThreshold: 3
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          imagePullPolicy: IfNotPresent
      restartPolicy: Always
      terminationGracePeriodSeconds: 60
---

apiVersion: v1
kind: Service
metadata:
  name: voice-service
  namespace: facephi-voice-service
spec:
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 6982
  type: ClusterIP
---

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: voice-ingress
  namespace: facephi-voice-service
spec:
  ingressClassName: kong
  rules:
    - http:
        paths:
          - path: /api(/v1)?/(.*)
            pathType: Prefix
            backend:
              service:
                name: voice-service
                port:
                  number: 80
---
```

It is important to have previously logged in to Artifactory or obtain the image **facephicorp.jfrog.io/docker-pro-fphi/facephi-voice-service** and store it in a Docker image repository from which the cluster can download it.

### 2.2 Volumes

You must add the volume with the configuration file so that the service works correctly; this configuration file contains the license information and the service configuration. By default, the path where the configuration file is stored is `/service/config/config.cfg`.

```yaml
apiVersion: v1
kind: Secret
metadata:
  name: config-secret
  namespace: facephi-voice-service
stringData:
  config.cfg: |-
    {
      CONFIG_DIR=<provided by facephi>
      LICENSE_TYPE=<provided by facephi>
      LICENSE_BEHAVIOUR=<provided by facephi>
      LICENSE_ID=<provided by facephi>
      LICENSE_DATA=<provided by facephi>
      LICENSE_KEY=<provided by facephi>
    }
```

Once that secret has been created, the deployment will associate the volume at the corresponding path with the following lines:

```yaml
...
spec:
  ...
  template:
    ...
    spec:
      volumes:
        - name: config-volume
          secret:
            secretName: config-secret
            defaultMode: 420
        ...
      containers:
        ...
        - volumeMounts:
            - name: config-volume
              readOnly: true
              mountPath: /service/config/config.cfg
              subPath: config.cfg
```

`spec.volumes[0].secret.secretName` searches the namespace for the previously generated secret and stores it in a volume with the name `config-volume`. When mounting the `config-volume`, the associated Secret is searched for, and `mountPath` is set to the path where the file is stored; moreover, we can specify a specific object from the secret using `subPath`, in this case the key `config.cfg`.

When JWT authentication is enabled, `GET /api/v1/health` and `GET /api/v1/version` remain public and protected endpoints require a valid JWT. The JWT startup settings are not exposed through `GET /api/v1/config` nor can they be updated through `POST /api/v1/config`.

### 2.3 Resources

After running the performance tests, the following results were obtained:

* For **Enrollment** with **three audio files** (`/api/v1/enrollment/`):

| CPU   | Memory | Average time |
| ----- | ------ | ------------ |
| 4096m | 10Gi   | 2511 ms      |
| 8192m | 10Gi   | 1407 ms      |

* For **Authentication** (`/api/v1/authentication/`):

| CPU   | Memory | Average time |
| ----- | ------ | ------------ |
| 4096m | 10Gi   | 240 ms       |
| 8192m | 10Gi   | 220 ms       |

With these tests, the following configuration is established at the requests and limits level.

```yaml
spec:
  ...
  template:
    ...
    spec:
      ...
      containers:
        ...
        - resources
            limits:
              cpu: 4096m  # 4 cores
              memory: 8Gi
            requests:
              cpu: 500m # 0.5 cores
              memory: 3Gi
```

### 2.4 Service

#### 2.4.1 LoadBalancer

Keep in mind that we will configure a LoadBalancer with Kong in front to access Facephi Voice Service. Note that the service is exposed on port `80` and points to the Pod on port `6982`.

```yaml
apiVersion: v1
kind: Service
metadata:
  name: facephi-voice-service
  namespace: facephi-voice-service
spec:
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 6982
  selector:
    name: facephi-voice-service
  type: ClusterIP
```

### 2.5 Ingress

We configure an Ingress in front to redirect Kong requests to the service inside the Pod that we previously exposed on port 80.

```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: facephi-voice-service
  namespace: facephi-voice-service
spec:
  ingressClassName: kong
  rules:
    - http:
        paths:
          - path: /api(/v1)?/(.*)
            pathType: Prefix
            backend:
              service:
                name: facephi-voice-service
                port:
                  number: 80
```

## 3 Instance Types

The recommended instance types for using Facephi Voice Service in production would be the following, where the Facephi Voice Service Pods that fit are shown according to the instance type used.

| Instance type | CPU | Memory | Service Pod capacity |
| ------------- | --- | ------ | -------------------- |
| c5.xlarge     | 4   | 8      | 2                    |
| c5.2xlarge    | 8   | 16     | 4                    |
| c5.4xlarge    | 16  | 32     | 9                    |
