> 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/sdks/backend-sdk/voice/installation/kubernetes_deployment.md).

# Despliegue en Kubernetes

## 1. Introducción

A continuación, especificamos todo lo necesario para instalar **Facephi Voice Service** en un entorno Kubernetes.

## 2. Despliegue manual

### 2.1 Introducción

El servicio Phivox puede desplegarse en Kubernetes con **kubectl**:

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

Utilizando un archivo *manifest.yaml* similar a este:

```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
          # Usa el nombre y la versión de tu imagen
          image: >-
            facephicorp.jfrog.io/docker-pro-fphi/facephi-voice-service:$VERSION
          env:
            # Protección JWT opcional
            # - 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
---
```

Es importante haber iniciado sesión previamente en Artifactory u obtener la imagen **facephicorp.jfrog.io/docker-pro-fphi/facephi-voice-service** y almacenarla en un repositorio de imágenes Docker desde el que el clúster pueda descargarla.

### 2.2 Volúmenes

Debes añadir el volumen con el archivo de configuración para que el servicio funcione correctamente; este archivo de configuración contiene la información de la licencia y la configuración del servicio. Por defecto, la ruta en la que se almacena el archivo de configuración es `/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>
    }
```

Una vez creado ese secret, el deployment asociará el volumen en la ruta correspondiente con las siguientes líneas:

```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` busca en el namespace el secret generado previamente y lo almacena en un volumen con el nombre `config-volume`. Al montar el `config-volume`, se busca el Secret asociado, y `mountPath` se establece con la ruta donde se almacena el archivo; además, podemos especificar un objeto concreto del secret mediante `subPath`, en este caso la clave `config.cfg`.

Cuando la autenticación JWT está habilitada, `GET /api/v1/health` y `GET /api/v1/version` siguen siendo públicos y los endpoints protegidos requieren un JWT válido. Los ajustes de arranque del JWT no se exponen mediante `GET /api/v1/config` ni pueden actualizarse mediante `POST /api/v1/config`.

### 2.3 Recursos

Tras ejecutar las pruebas de rendimiento, se obtuvieron los siguientes resultados:

* Para **Enrollment** con **tres audios** (`/api/v1/enrollment/`):

| CPU   | Memoria | Tiempo medio |
| ----- | ------- | ------------ |
| 4096m | 10Gi    | 2511 ms      |
| 8192m | 10Gi    | 1407 ms      |

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

| CPU   | Memoria | Tiempo medio |
| ----- | ------- | ------------ |
| 4096m | 10Gi    | 240 ms       |
| 8192m | 10Gi    | 220 ms       |

Con estas pruebas, se establece la siguiente configuración a nivel de requests y limits.

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

### 2.4 Servicio

#### 2.4.1 LoadBalancer

Tenemos en cuenta que configuraremos un LoadBalancer con Kong por delante para acceder a Facephi Voice Service. Ten en cuenta que el servicio se expone en el puerto `80` y apunta al Pod en el puerto `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

Configuramos un Ingress por delante para redirigir las peticiones de Kong al servicio dentro del Pod que expusimos previamente en el puerto 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 Tipos de instancia

Los tipos de instancia recomendados para usar Facephi Voice Service a nivel de producción serían los siguientes, donde se muestran los Pods de Facephi Voice Service que caben según el tipo de instancia utilizado.

| Tipo de instancia | CPU | Memoria | Capacidad de Pods del servicio |
| ----------------- | --- | ------- | ------------------------------ |
| c5.xlarge         | 4   | 8       | 2                              |
| c5.2xlarge        | 8   | 16      | 4                              |
| c5.4xlarge        | 16  | 32      | 9                              |
