Desplegar nginx en Kubernetes
nginx es un servidor web/proxy inverso bastante ligero y de alto rendimiento de código abierto, que con el tiempo ha ido creciendo como caché de HTTP, balanceador de carga, y también como proxy de correo electrónico. Su potencial está en ser capaz de trabajar con gran cantidad de conexiones a gran velocidad, algo que hace que posea el 20% de la cuota de mercado de servidores web.
Su funcionamiento se basa en no crear procesos nuevos para cada solicitud web que recibe, sino que hace uso de un enfoque asincrónico basado en eventos, donde se trabaja con las solicitudes en un solo hilo.
Como podremos suponer, su interés es enorme, así que vamos a ver cómo podemos desplegar nginx mediante un contenedor de Kubernetes.
Elección de imagen Docker
Existen varias opciones disponibles, pero las dos más extendidas son las siguientes:
nginx
Esta imagen de Docker Hub es la genérica y principal. Si disponemos de un entorno con orquestación sobre Docker, ésta será la mejor opción para poder trabajar puesto que es la más sencilla de usar. En cambio, si usamos Kubernetes esta imagen puede darnos varios problemas, sobre todo por permisos trabajando en entornos Openshift.
En este último caso, ninguna imagen puede ejecutarse sobre usuarios root, y por defecto la imagen nginx se ejecuta sobre root. Aparte, su fichero de configuración inicial utiliza el puerto 80, el cual ya no estará disponible puesto que necesitamos permisos de usuario para poder utilizarlo.
bitnami/nginx
Esta imagen viene preconfigurada para poder ejecutar sobre entornos Kubernetes y gracias a su configuración por defecto, es perfecta para entornos Openshift.
Para esta entrada, vamos a centrarnos en esta imagen.
Configuración de bitnami/nginx
Partiremos de la imagen «bitnami/nginx:latest». Podemos ejecutarla de manera sencilla con el siguiente comando:
Docker run --name nginx -p 8080:8080 bitnami/nginx:latest
Al acceder a la url «http://localhost:8080» veremos nuestra página de inicio de nginx:
Para poder crear nuestras configuraciones, deberemos crear nuestro archivo «nginx.conf» y montarlo sobre nuestra contenedor. Tenemos varias opciones:
Modificando la configuración por defecto (nginx.conf)
Podemos modificar la configuración por defecto de nuestro servidor nginx modificando el fichero principal «nginx.conf» situado en «/opt/bitnami/nginx/conf/nginx.conf».
Este fichero por defecto tiene un contenido parecido a este:
# Based on https://www.nginx.com/resources/wiki/start/topics/examples/full/#nginx-conf
# user www www; ## Default: nobody
worker_processes auto;
error_log "/opt/bitnami/nginx/logs/error.log";
pid "/opt/bitnami/nginx/tmp/nginx.pid";
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log "/opt/bitnami/nginx/logs/access.log";
add_header X-Frame-Options SAMEORIGIN;
client_body_temp_path "/opt/bitnami/nginx/tmp/client_body" 1 2;
proxy_temp_path "/opt/bitnami/nginx/tmp/proxy" 1 2;
fastcgi_temp_path "/opt/bitnami/nginx/tmp/fastcgi" 1 2;
scgi_temp_path "/opt/bitnami/nginx/tmp/scgi" 1 2;
uwsgi_temp_path "/opt/bitnami/nginx/tmp/uwsgi" 1 2;
sendfile on;
tcp_nopush on;
tcp_nodelay off;
gzip on;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_proxied any;
gzip_types text/plain text/css application/javascript text/xml application/xml+rss;
keepalive_timeout 65;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
client_max_body_size 80M;
server_tokens off;
include "/opt/bitnami/nginx/conf/server_blocks/*.conf";
# HTTP Server
server {
# Port to listen on, can also be set in IP:PORT format
listen 8080;
include "/opt/bitnami/nginx/conf/bitnami/*.conf";
location /status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
}
}
Como podemos observar en el archivo, dentro de http tenemos la instrucción «include» de todos los fichero localizados en el path «/opt/bitnami/nginx/conf/server_blocks/*.conf» y también podemos incluir diferentes location automáticamente al server principal localizado en el puerto 8080 añadiendo los ficheros sobre la ruta «/opt/bitnami/nginx/conf/bitnami/*.conf».
Añadiendo location al server por defecto
Se pueden añadir diferentes location simplemente añadiendo ficheros a la ruta «/opt/bitnami/nginx/conf/bitnami/*.conf». Un ejemplo podría ser el siguiente:
my_server.conf
location /my-endpoint {
proxy_pass http://my-service:8080;
proxy_set_header X-request_uri "$request_uri";
proxy_set_header Host $http_host;
proxy_read_timeout 120;
}
Este archivo se colocaría en «/opt/bitnami/nginx/conf/bitnami/my_server.conf» y automáticamente al inicio nos redirigirá al servicio seleccionado al acceder a la url:
http://localhost:8080/my-endpoint
Añadiendo diferentes servidores (server_blocks)
Para poder añadir diferentes «server_blocks», si mantenemos el fichero de configuración original «nginx.conf», podemos crear los diferentes servidores creando diferentes archivo en la ruta «/opt/bitnami/nginx/conf/server_blocks/*.conf». Un ejemplo sería el siguiente:
my_server_block.conf
server {
listen 8443;
server_name "dev-caregiver.cwbyminsait.com";
add_header Strict-Transport-Security "max-age=31536000" always;
location /my-endpoint {
proxy_pass http://my-service:8080;
proxy_set_header X-request_uri "$request_uri";
proxy_set_header Host $http_host;
proxy_read_timeout 120;
}
}
Este archivo se colocaría en «/opt/bitnami/nginx/conf/server_blocks/my_server_block.conf» y automáticamente al inicio creará un nuevo puerto vinculado a este nuevo server. Ahora podríamos acceder a este nuevo endpoint a través de la ruta:
http://localhost:8443/my-endpoint
Como desplegar bitnami/nginx en Kubernetes
Primero necesitaremos crear un nuevo deployment:
kind: Deployment
apiVersion: apps/v1
metadata:
name: nginx-balancer
labels:
app: nginx-balancer
app.kubernetes.io/name: nginx-balancer
app.kubernetes.io/instance: nginx-balancer
app.kubernetes.io/component: nginx-proxy
app.kubernetes.io/part-of: nginx-balancer
spec:
replicas: 1
selector:
matchLabels:
app: nginx-balancer
template:
metadata:
labels:
app: nginx-balancer
spec:
containers:
- resources:
limits:
cpu: 100m
memory: 250Mi
requests:
cpu: 50m
memory: 50Mi
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 20
timeoutSeconds: 5
periodSeconds: 10
successThreshold: 2
failureThreshold: 3
livenessProbe:
httpGet:
path: /
port: 8080
scheme: HTTP
initialDelaySeconds: 20
timeoutSeconds: 5
periodSeconds: 10
successThreshold: 1
failureThreshold: 5
name: nginx-balancer
ports:
- name: 8443tcp84432
containerPort: 8443
protocol: TCP
- name: 8080tcp8080
containerPort: 8080
protocol: TCP
imagePullPolicy: Always
image: 'bitnami/nginx:latest'
restartPolicy: Always
De esta manera ya tenemos creado nuestro deployment original y podemos empezar a añadir nuestros bloques servidor y los diferentes location que queramos.
Para crear el bloque server debemos crear un volume y vincularlo hacia la ruta «/opt/bitnami/nginx/conf/server_blocks». Para ello, primero se creará un «Config Map» que después montaremos sobre el anterior deployment.
kind: ConfigMap
apiVersion: v1
metadata:
name: server-block-map
data:
my_server_block.conf: |
########################### SERVER BLOCK ####################
server {
listen 8443;
add_header Strict-Transport-Security "max-age=31536000" always;
location /my-endpoint {
proxy_pass http://my-service:8080;
proxy_set_header X-request_uri "$request_uri";
proxy_set_header Host $http_host;
proxy_read_timeout 120;
}
}
other_server_block.conf: |
######### OTHER SERVER #######....
Después deberemos realizar lo siguientes cambios sobre nuestro deployment original:
- Añadir nuestro volume desde el Config Map.
- Montar el volume sobre el directorio de servers.
...
spec:
...
template:
...
spec:
volumes:
- name: config-servers
configMap:
name: server-block-map
defaultMode: 484
containers:
...
volumeMounts:
- name: config-servers
mountPath: /opt/bitnami/nginx/conf/server_blocks
De esta manera ya tendremos configurado nuestro servicio nginx. Podremos comprobarlo accediendo al contenedor nginx y realizando una petición a:
http://localhost:8443/my-endpoint
Fácil y sencillo, ¿verdad? Si os surge alguna duda, dejadnos un comentario.