Utiliser NGINX comme d'un proxy de base de données
Tags: devops, sre, kubernetes
Published: 2023-03-06 16:23:00

Dans notre quotidien, il se peut que l'on perde l'accès direct à une base de données et qu'elle ne soit qu'accessible que par les services dans le cluster Kubernetes.

Du coup, dans ce genre de situations, être capable d'utiliser un proxy peut vous permettre de résoudre ce problème de connectivité. Donc aujourd'hui, je vais vous présenter comment le faire avec Nginx.

## Qu'est-ce que NGINX ?
Pour ceux qui n'auraient pas encore eu l'occasion de découvrir ce qu'est [**Nginx**](https://www.nginx.com/). C'est un logiciel open source pouvant servir de load balancer, de serveur web ou de proxy.

---

## Configurer NGINX 
La configuration de Nginx ressemble à ça

```yaml
user  nginx;
worker_processes  auto;
error_log /dev/stdout info;
pid        /var/run/nginx.pid;
events {
  worker_connections  1024;  ## Default: 1024
}
http {
  access_log /dev/stdout combined;
  log_format logger-json escape=json '{"source": "nginx", "time": $msec, "resp_body_size": $body_bytes_sent, "host": "$http_host", "address": "$remote_addr", "request_length": $request_length, "method": "$request_method", "uri": "$request_uri", "status": $status,  "user_agent": "$http_user_agent", "resp_time": $request_time, "upstream_addr": "$upstream_addr"}';
    server {
         listen 8080 so_keepalive=on;
        location = /health {
          auth_basic off;
          return 200;
        }
    }
}
stream {
    upstream database {
        server [endpoint base de données]:[port base de données];
    }
    server {
        listen [port base de données] so_keepalive=on;
            proxy_connect_timeout 60s;
            proxy_socket_keepalive on;
            proxy_pass database;
    }
}
```

Ici, il y a quelques éléments à remplacer : 
- `[endpoint base de données]` : L'url pour accéder à la base de données
- `[port base de données]` : Le port pour accéder à la base de données

### Détail de la configuration
#### http
La partie HTTP est pour exposer un simple endpoint `/health` pour s'assurer de la présence et disponibilité du service.

#### stream
Dans notre cas, c'est la partie qui nous intéresse le plus. 

La partie `upstream` est pour créer un groupe de serveurs *(ici on n'en a qu'un qui s'appelle `database`, mais ça facilite un peu la lecture)*.

La partie `server` va, elle, définir :
- sur quelle port Nginx va écouter pour rediriger le trafic -> `listen`
- où il va rediriger le trafic -> `proxy_pass`
Ainsi que d'autres configurations comme `so_keepalive=on` et `proxy_socket_keepalive on;` qui sont importantes pour éviter que la connexion soit coupée au milieu des opérations qui sont faites sur la base de données.

---
## Déploiement sur Kubernetes
Une fois que la configuration est prête, vous pouvez alors le déployer sur votre cluster.

Voici un template pour pouvoir créer la configmap, le deployment et le service.

```yaml
apiVersion: v1
data:
  nginx.conf: "user  nginx;\r\nworker_processes  auto;\r\nerror_log /dev/stdout info;\r\npid
    \ /var/run/nginx.pid;\r\nevents {\r\n  worker_connections  1024;  ## Default:
    1024\r\n}\r\n\r\nhttp {\r\n  access_log /dev/stdout combined;\r\n  log_format
    logger-json escape=json '{\"source\": \"nginx\", \"time\": $msec, \"resp_body_size\":
    $body_bytes_sent, \"host\": \"$http_host\", \"address\": \"$remote_addr\", \"request_length\":
    $request_length, \"method\": \"$request_method\", \"uri\": \"$request_uri\", \"status\":
    $status,  \"user_agent\": \"$http_user_agent\", \"resp_time\": $request_time,
    \"upstream_addr\": \"$upstream_addr\"}';\r\n\r\n\r\n    server {\r\n         listen
    8080 so_keepalive=on;\r\n\r\n        location = /health {\r\n          auth_basic
    off;\r\n          return 200;\r\n        }\r\n    }\r\n}\r\nstream {\r\n    upstream
    postgres {\r\n        server database:port;\r\n
    \ }\r\n\r\n    server {\r\n        listen port so_keepalive=on;\r\n            proxy_connect_timeout
    60s;\r\n            proxy_socket_keepalive on;\r\n            proxy_pass postgres;\r\n
    \ }\r\n}"
kind: ConfigMap
metadata:
  name: nginx-config
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  ports:
    - port: 8080
      protocol: TCP
      targetPort: 8080
      name: http
    - port: port
      protocol: TCP
      targetPort: port
      name: database
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
      name: nginx
    spec:
      containers:
        - args:
            - nginx
            - -g
            - daemon off;
            - -c
            - /nginx/etc/config/nginx.conf
          image: nginx:1.23.3
          imagePullPolicy: IfNotPresent
          livenessProbe:
            httpGet:
              path: /health
              port: nginx
              scheme: HTTP
            initialDelaySeconds: 10
          name: nginx
          ports:
            - containerPort: 8080
              name: nginx
              protocol: TCP
            - containerPort: port
              name: database
              protocol: TCP
          readinessProbe:
            httpGet:
              path: /health
              port: nginx
              scheme: HTTP
            initialDelaySeconds: 10
          resources:
            limits:
              memory: 200Mi
            requests:
              cpu: 50m
              memory: 200Mi
          volumeMounts:
            - mountPath: /nginx/etc/config
              name: nginx-config-volume
      volumes:
        - configMap:
            name: nginx-config
          name: nginx-config-volume
```
Avant de l'utiliser, assurez-vous de mettre les bonnes informations dans la configmap, ainsi que de définir le port dont vous avez besoin pour exposer votre base de données dans votre déploiement et votre service!

---

## Utilisation
Une fois déployé sur votre cluster, vous pouvez l'exposer au travers d'un `Ingress` ou simplement faire un port forward du service afin de pouvoir effectuer vos manipulations depuis votre machine!

---

C'est tout pour cette semaine, j'espère que ça vous aidera! 🍺

---

<center><h3>Vous voulez me supporter?</h3></center>
<a href="https://www.buymeacoffee.com/mxguilbert7" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174"></a>