Mejora la productividad de tu equipo con un correo profesional adaptado a tu negocio. Facilita el día a día y protege tus comunicaciones con una solución accesible y gestionada por personas expertas.
Tus mensajes estarán siempre protegidos con autenticación robusta, cifrado y filtros antispam y antivirus de última generación. Minimiza el riesgo de pérdida, phishing o accesos no deseados, y mantén el control total sobre remitentes y destinatarios.
Accede a tu correo desde el navegador o desde clientes compatibles como Outlook, con total sincronización POP3 o IMAP. Disfruta de herramientas colaborativas integradas y accede a contactos, calendarios y archivos desde cualquier lugar.
Controla todo lo relacionado con el correo corporativo desde una consola central. Da de alta nuevas cuentas, configura alias o reglas de spam y personaliza políticas generales para toda la empresa.
Las empresas eligen los buzones de correo electrónico de Sarenet por prestaciones como estas.
Te proponemos estas dos vías para comenzar a trabajar con Sarenet
Para configurar tu cuenta, solo necesitas los datos básicos: tu dirección de correo completa (por ejemplo, usuario@dominio.com), tu contraseña y los servidores de entrada y salida, que serán: correo.sarenet.es. Cuando el gestor te pida el tipo de cuenta, selecciona “otros” e introduce la información manualmente. Asegúrate de activar la autenticación del servidor saliente e introduce de nuevo tu usuario y contraseña.
Te recomendamos activar la opción SSL para cifrar la conexión y reforzar la seguridad.
Es un sistema de seguridad que te alerta si detecta accesos a tu cuenta desde ubicaciones inusuales, como otro país. Si estás de viaje, puedes ignorar el aviso o desactivar las notificaciones temporalmente. Si no es tu caso, es posible que un gestor de correo (como Outlook) esté accediendo desde servidores externos.
Para comprobarlo, puedes verificar la IP desde servicios como cual-es-mi-ip.net y contrastarla con la IP que aparece en el aviso. Si confirmas que no has sido tú, cambia tu contraseña de inmediato desde saremail.com o ventana.sarenet.es, y pasa un antivirus por todos tus dispositivos. Nuestro equipo técnico también puede ayudarte.
Si recibes un aviso de que tu buzón está lleno o casi lleno, puedes liberar espacio fácilmente desde www.saremail.com. Accede con tu cuenta, entra en la bandeja de entrada y haz clic en el icono de la tuerca. Desde ahí, podrás ordenar los correos por tamaño y eliminar primero los más pesados. También puedes filtrar por remitente, asunto o fecha para borrar los que ya no necesites.
Si eres el contacto autorizado, puedes entrar en Ventana de Cliente con tu usuario y contraseña. Desde ahí podrás gestionar tus servicios: ver estadísticas de uso, acceder a los credenciales de tu servidor o realizar tareas habituales como modificar contenidos. Todo en un solo lugar.
Contamos con más de 30 años de experiencia y una sólida especialización en soluciones de correo para empresas. Fuimos pioneros en ofrecer buzones profesionales en España, y actualmente más del 95 % de nuestra clientela está satisfecha con el servicio. Además de nuestra trayectoria, destacamos por el soporte cercano, la seguridad, la flexibilidad y nuestra capacidad de adaptación a cada necesidad.
No hay problema. Puedes empezar con un único buzón y crecer sin límites: hasta miles de cuentas, alojadas en servidores compartidos o dedicados, sobre distintas plataformas y configuradas a medida. Tanto si tu empresa es pequeña como si necesitas una solución escalable, te ofrecemos un servicio que se adapta al ritmo de tu negocio.
Sí. Puedes crear tu propia lista de “remitentes denegados” para bloquear correos de direcciones no deseadas. También puedes configurar una lista de “remitentes permitidos” para asegurarte de recibir solo lo que te interesa. Así ganas control y tranquilidad en tu bandeja de entrada.
No, siempre que el servidor esté bien protegido. En Sarenet utilizamos filtros antispam y antivirus de última generación, y realizamos una supervisión técnica constante para evitar ataques o abusos que comprometan tu reputación como remitente. Así te ayudamos a mantener tu dominio fuera de las listas negras.
Un servidor que se encarga de gestionar los correos de tu empresa en exclusiva, y que solo tú podrás utilizar. Toda la potencia y ancho de banda estarán a tu servicio, para que solo tú los aproveches, mejorando así la velocidad y la independencia de tus comunicaciones.
Es posible que estés intentando recuperar una gran cantidad de datos y el sistema haya limitado la operación para proteger su estabilidad. En ese caso, contáctanos: nuestro equipo técnico puede ayudarte a recuperar los mensajes manualmente sin coste adicional.
Si quieres puedes hacerlo, pero nosotros te recomendamos alojarlo en nuestros Data centers donde nos encargaremos de tenerlo actualizado y bajo máximas medidas de seguridad, con servicio de vigilancia y mantenimiento las 24 horas los 365 días del año.
Desde el webmail, accede a la pestaña “Rastreador” y comprueba si el mensaje fue entregado. Si pasadas dos horas no aparece, es probable que no se haya enviado. Podemos ayudarte revisando los registros técnicos de nuestros servidores: guardamos los datos durante un año.
Claro que sí. Puedes acceder a tu correo desde tu iPhone, tu iPad, tu iBook, tu PDA, tu tablet, tu BlackBerry, tu pc portátil...Y siempre con los máximos niveles de seguridad y fiabilidad.
Tú mismo puedes hacerlo desde Saremail. Accede a Configuración, Recuperar elementos eliminados y seleccionando el día apropiado del borrado podrás recuperar tanto carpetas enteras como mensajes independientes.
Nuestro sistema limita el uso de recursos para garantizar la estabilidad del servicio. Si intentas recuperar demasiados elementos a la vez o su tamaño es muy grande, es posible que la recuperación no funcione automáticamente. Llámanos y te ayudaremos a recuperarlos manualmente, sin coste adicional.
Accede a la configuración del webmail, entra en “Desconexión” y solicita cerrar todos los accesos activos. Esto suele solucionar el error y desbloquear la cuenta.
Entra en el webmail y accede a la pestaña “Rastreador”. Si han pasado más de 2 horas y no ves el correo registrado, probablemente no se ha entregado. Si lo necesitas, podemos comprobar los registros del servidor: guardamos la información durante un año.
Para mejorar la entregabilidad, es necesario configurar correctamente los registros SPF y DMARC en tu dominio. Si lo deseas, te ayudamos a implementarlos paso a paso.
Sí. Por defecto, el sistema responde solo una vez al día a cada remitente para evitar saturar las bandejas de entrada.
Escríbenos con los detalles y recuperaremos la información tal como estaba antes del borrado. En próximas versiones podrás hacerlo tú mismo desde el webmail.
En Sarenet usamos IP dedicadas por cliente, lo que evita este tipo de problemas. Si te ocurre, revisamos el caso contigo y te damos las pautas para solucionarlo de forma definitiva.
Podemos ayudarte a restringir el acceso al correo por rangos de IP o direcciones concretas. Contáctanos y aplicaremos las medidas necesarias.
Sí, y además te orientamos sobre los requisitos legales y la mejor forma de hacerlo según tu caso.
Podemos ayudarte a configurar tu entorno para que tus usuarios sigan accediendo al correo incluso si se cae tu servidor principal.
Reinstala la última versión encima de la anterior, sin desinstalarla previamente y con Outlook cerrado. Eso suele resolverlo.
No aplicamos ese tipo de restricciones. Llámanos y te explicamos cómo enviar sin problemas, incluso con grandes volúmenes.
Sí, nuestro equipo técnico puede generar una configuración personalizada para facilitarte esa gestión.
Sí. Contacta con nuestro soporte (nivel 2) y te daremos la información: usuario, fecha, hora y ubicación del borrado.
La ubicación del centro de datos afecta directamente a la latencia porque determina la distancia que deben recorrer los paquetes de datos.
Si el servidor se encuentra muy lejos de la persona usuaria o de la infraestructura de la empresa, el tiempo necesario para que las solicitudes y respuestas viajen por la red aumenta.
Por este motivo, elegir infraestructuras cercanas o utilizar redes de distribución de contenidos (CDN) puede ayudar a reducir la latencia.

La latencia afecta directamente a la percepción de rapidez de una aplicación.
Por ejemplo, en aplicaciones web o APIs, una latencia elevada puede provocar:
Aunque las diferencias se midan en milisegundos, las personas usuarias perciben el resultado como lentitud o falta de respuesta del sistema.

La latencia tiene un impacto directo en el rendimiento y la usabilidad de las arquitecturas de teletrabajo o acceso remoto a recursos corporativos. Cuando las aplicaciones, escritorios virtuales o bases de datos están alojados en centros de datos lejanos, cada interacción de la persona usuaria implica múltiples intercambios de datos. En consecuencia, las pequeñas latencias pueden acumularse.
Esto puede provocar lentitud en la carga de aplicaciones, retrasos al escribir o interactuar con sistemas remotos, menor fluidez en escritorios virtuales y peor experiencia en videoconferencias o herramientas colaborativas.
Por este motivo, es habitual optimizar rutas de red, usar infraestructuras cercanas y aplicar técnicas de aceleración o compresión del tráfico.

Cuanto menor es la distancia entre la persona usuaria y el servidor que procesa sus solicitudes, menor es el tiempo que tardan los paquetes en viajar entre ambos puntos.
Esto reduce la latencia total de la comunicación y mejora la rapidez con la que las aplicaciones responden a las acciones de la persona usuaria.

La latencia influye directamente en el rendimiento de los procesos de sincronización y replicación de datos entre sistemas. En arquitecturas distribuidas, cada operación de replicación implica intercambios de mensajes entre nodos para enviar datos, confirmar su recepción o validar transacciones.
Cuando la latencia es elevada, estos intercambios tardan más en completarse, lo que puede provocar mayores tiempos de escritura, retrasos en la actualización de los datos replicados y menor velocidad en la sincronización entre sistemas.
Este efecto es especialmente relevante en bases de datos distribuidas, clústeres o sistemas que requieren consistencia entre nodos, donde cada confirmación remota añade tiempo adicional al proceso global.

La forma más recomendable de instalar python-openstackclient en entornos Linux es mediante un entorno virtual de Python, ya que permite aislar dependencias y evitar conflictos con paquetes del sistema.
El proceso comienza asegurando los requisitos: disponer de Python 3.8 o superior, acceso a terminal y permisos suficientes para instalar paquetes.
En distribuciones Debian/Ubuntu:
sudo apt update sudo apt install python3-pip python3-venv -y
Se crea un entorno aislado para OpenStack:
python3 -m venv openstack_env
Se activa el entorno virtual:
source openstack_env/bin/activate
A partir de este momento, cualquier paquete se instalará solo dentro de este entorno.
pip install --upgrade pip pip install python-openstackclient
Opcionalmente, se pueden añadir clientes específicos según servicios utilizados:
pip install python-octaviaclient python-barbicanclient
openstack --help
Si el comando responde correctamente, el cliente está operativo.
Para interactuar con la API, es imprescindible cargar las variables de entorno mediante un archivo OpenRC disponible en el panel de Sarenet:
source openrc.sh
Esto define credenciales, proyecto y endpoint.
![]()
El archivo OpenRC es el mecanismo estándar en OpenStack para inyectar credenciales y parámetros de conexión en la sesión de terminal, permitiendo que el cliente (openstack CLI) se autentique contra la API sin necesidad de introducir manualmente cada variable.
El proceso correcto consta de tres fases: obtención, carga y verificación.
Desde el panel de OpenStack (Horizon) facilitado por Sarenet, la persona usuaria debe descargar el archivo correspondiente a su proyecto y región. Este archivo contiene variables como:
Es importante usar el OpenRC adecuado para la región (por ejemplo, SpainNorth), ya que un desajuste provoca errores de autenticación.
En sistemas Linux o macOS, el archivo se carga con:
source openrc.sh
Durante la ejecución, se solicitará la contraseña de la persona usuaria de OpenStack. Esta no se almacena en el archivo por motivos de seguridad, sino que se inyecta en la variable OS_PASSWORD en tiempo de ejecución.
Este paso es crítico: las variables solo quedan disponibles en la sesión activa. Si se abre una nueva terminal, será necesario repetirlo.
Una vez cargado, se recomienda validar la conexión:
openstack server list
Si la respuesta devuelve recursos del proyecto, la autenticación es correcta.
![]()
La creación de una instancia en OpenStack desde la CLI se realiza mediante el comando openstack server create, que permite definir de forma explícita los parámetros clave del despliegue: imagen (OS base), flavor (recursos) y clave SSH (acceso seguro).
El flujo habitual consta de tres pasos: validación previa, creación y verificación.
Antes de lanzar la instancia, es recomendable listar los elementos necesarios:
openstack flavor list openstack image list openstack keypair list
Esto permite confirmar que el flavor (CPU/RAM), la imagen y la clave SSH existen y son accesibles en el proyecto.
El comando básico sería:
openstack server create \ --flavor m1.tiny \ --image "Ubuntu2404-SpainNorth" \ --key-name SSHKEY \ nombre-instancia
--flavor: define recursos (vCPU, RAM, disco).--image: sistema operativo base.--key-name: clave SSH previamente registrada para acceso seguro.nombre-instancia: identificador del servidor.Durante el proceso, el estado inicial será BUILD, indicando que la máquina está siendo provisionada.
Una vez lanzada:
openstack server list
Cuando el estado cambie a ACTIVE, la instancia está lista.
![]()
En OpenStack, el uso de pares de claves SSH (keypairs) es el mecanismo estándar para garantizar un acceso seguro a las instancias, evitando el uso de contraseñas y facilitando la autenticación basada en clave pública.
El proceso consiste en registrar previamente la clave pública en OpenStack para que pueda inyectarse automáticamente en las instancias durante su creación.
Si no se dispone de una clave, se puede generar en el sistema local:
Clave privada: ~/.ssh/id_rsa Clave pública: ~/.ssh/id_rsa.pub
Esto permite confirmar que el flavor (CPU/RAM), la imagen y la clave SSH existen y son accesibles en el proyecto.
Se utiliza el comando:
openstack keypair create --public-key ~/.ssh/id_rsa.pub NOMBRE_KEY --public-key: ruta al fichero de clave pública. NOMBRE_KEY: identificador dentro de OpenStack.
Este comando no sube la clave privada, únicamente la pública, manteniendo el modelo de seguridad.
openstack keypair list
O bien.
openstack keypair show NOMBRE_KEY
Esto permite comprobar que la clave está correctamente asociada a la persona usuaria y proyecto.
Al lanzar una VM, se referencia la clave:
openstack server create --key-name NOMBRE_KEY ...
OpenStack inyectará la clave en el usuario por defecto de la imagen (por ejemplo, ubuntu o debian).
![]()
Desplegar una aplicación en Kubernetes con Helm Charts permite estandarizar el empaquetado, parametrizar el despliegue y mantener coherencia entre entornos. El enfoque más sólido consiste en definir un chart con plantillas YAML personalizadas para los objetos que realmente necesita la aplicación: Deployment, Service, Ingress y PersistentVolumeClaim (PVC).
La estructura base suele incluir Chart.yaml, values.yaml, el directorio /templates y scripts auxiliares para instalación y validación. En el caso descrito en la documentación, dentro de /templates se eliminan los ficheros generados por defecto salvo _helpers.tpl, y se crean archivos específicos como [nombre_app]-app.yaml y [nombre_app]-db.yaml. Ahí se definen los recursos de Kubernetes y se parametrizan mediante expresiones Helm del tipo {{ .Values.xxx.yyy }}, lo que permite cambiar imágenes, URLs, namespaces o almacenamiento sin tocar la plantilla.
Antes de desplegar, conviene ajustar dos elementos críticos: el namespace y los parámetros de almacenamiento persistente, incluyendo el nodo si se está usando una definición concreta de PersistentVolume. Después, se actualiza el chart, se empaqueta con helm package . y se instala con helm install ... --namespace ....
Una buena práctica especialmente relevante es ejecutar antes ./install.sh debug, que genera un output.yaml con todos los manifiestos renderizados. Esto permite revisar configuraciones, detectar errores de interpolación y validar que el chart desplegará exactamente los objetos esperados antes de tocar el clúster.
![]()
Para que Kubernetes pueda descargar imágenes privadas desde un registro externo, es necesario crear un Secret de tipo kubernetes.io/dockerconfigjson y asociarlo al despliegue o al ServiceAccount que ejecuta los pods. Ese secreto almacena las credenciales que el clúster utilizará durante el image pull. En la documentación, este patrón aparece como registry-secret.yaml, cuya función es precisamente contener credenciales del registro Docker codificadas en base64 para permitir a Kubernetes hacer pull desde DockerHub o desde un registro privado.
La forma más práctica de crearlo es mediante CLI:
kubectl -n <namespace> create secret docker-registry registry-credentials \ --docker-server <url_registro> \ --docker-username <usuario> \ --docker-password <password>
Este comando genera el secreto con el formato correcto y evita errores manuales en la estructura JSON. La propia documentación lo recomienda como vía más sencilla cuando hay que autenticarse contra un repositorio privado.
Si se prefiere definirlo en YAML, el contenido debe incluir .dockerconfigjson con un bloque auths que contenga la URL del repositorio, username, password y el campo auth con el valor base64(usuario:contraseña). Ese manifiesto debe declararse con kind: Secret y type: kubernetes.io/dockerconfigjson.
Una vez creado, el secreto debe referenciarse en el workload mediante imagePullSecrets, o bien añadirse al ServiceAccount si se quiere reutilizar en varios despliegues del mismo namespace. Cuando esta parte falla, los síntomas habituales son ImagePullBackOff o errores del tipo pull access denied, normalmente asociados a credenciales inválidas, tokens caducados o permisos insuficientes en el registro. En esos casos, la práctica correcta es regenerar el token, actualizar el secret y verificar que la URL del repositorio coincide exactamente con la usada en la imagen.
![]()
El estado ImagePullBackOff indica que Kubernetes no puede descargar la imagen del registro. Cuando la causa está en las credenciales, el problema suele estar en un Secret mal formado, un token caducado, permisos insuficientes en el repositorio o una URL de registro que no coincide exactamente con la referencia de la imagen. La propia documentación recomienda empezar revisando el mensaje de estado del deployment o del pod afectado para ver el error concreto.
El primer paso práctico es inspeccionar el pod:
kubectl describe pod <nombre-pod> -n <namespace>
Ahí suelen aparecer mensajes como pull access denied, repository does not exist o referencias a docker login, que apuntan claramente a un fallo de autenticación. Según la guía, si el error está en las credenciales del registro, hay que regenerar el token en el repositorio de imágenes y actualizar el secret registryCredentials. Cuando se usan varias imágenes, conviene crear el token a nivel de grupo; si solo afecta a una, puede bastar un token a nivel de repositorio.
El secreto debe tener formato kubernetes.io/dockerconfigjson e incluir correctamente la URL del registro, el usuario, la contraseña y el campo auth codificado en base64 como usuario:contraseña. La forma más segura de recrearlo es mediante CLI:
kubectl -n <namespace> create secret docker-registry registry-credentials \ --docker-server <url_registro> \ --docker-username <usuario> \ --docker-password <password>
Esta es la opción más fiable para evitar errores manuales en el JSON.
Como buenas prácticas, conviene verificar que imagePullSecrets está referenciado en el deployment, que la imagen existe realmente en el registro y que el namespace contiene la versión actualizada del secret. En entornos operativos serios, este tipo de incidencias se resuelve rápido si se valida siempre el triángulo completo: nombre de imagen, permisos del token y secret aplicado en el namespace correcto.
![]()
Para limitar el acceso a un namespace concreto en Kubernetes, el enfoque correcto con RBAC consiste en combinar tres piezas: un ServiceAccount que actuará como identidad, un Role que define los permisos dentro de ese namespace y un RoleBinding que vincula ambos. Este modelo permite aplicar el principio de mínimo privilegio y evitar permisos excesivos a nivel de clúster.
El ServiceAccount se crea dentro del namespace objetivo y será la identidad que usará el acceso delegado. Después se define un Role con reglas específicas: recursos, grupos de API y verbos permitidos. La documentación recuerda que Role aplica solo a un namespace, mientras que ClusterRole afecta a todo el clúster, por lo que para este caso debe usarse Role. También detalla que las reglas se construyen con resources, apiGroups y verbs, por ejemplo para permitir operaciones sobre pods o ingresses.
Un ejemplo mínimo sería:
apiVersion: v1 kind: ServiceAccount metadata: name: app-user namespace: entorno-dev --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: app-user-role namespace: entorno-dev rules: - apiGroups: [""] resources: ["pods","services","configmaps"] verbs: ["get","list","watch"] - apiGroups: ["apps"] resources: ["deployments"] verbs: ["get","list","watch","update"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: app-user-binding namespace: entorno-dev subjects: - kind: ServiceAccount name: app-user namespace: entorno-dev roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: app-user-role
Una vez aplicado, ese ServiceAccount solo tendrá permisos dentro de entorno-dev. A partir de ahí, puede generarse un kubeconfig restringido a ese namespace, tal como muestra el script incluido en la documentación. En entornos profesionales, esta práctica es clave para segmentar accesos entre equipos, automatizaciones y aplicaciones sin exponer el clúster completo innecesariamente.
![]()
Cuando un namespace de Kubernetes queda atascado en estado Terminating, lo habitual es que exista algún recurso interno pendiente de limpieza o que uno o varios finalizers estén bloqueando el cierre definitivo. Un finalizer es un mecanismo de protección que impide que Kubernetes elimine un objeto hasta que se complete una tarea previa. Si esa tarea no termina correctamente, el namespace no desaparece.
El primer paso no debería ser borrar el finalizer a ciegas, sino comprobar que no quedan objetos activos dentro del namespace que justifiquen ese estado. Esta validación es importante porque forzar la eliminación puede dejar recursos huérfanos o estados inconsistentes si todavía hay dependencias vivas. La propia documentación insiste en verificar antes que no queda ningún objeto que mantenga el namespace en Terminating.
Una vez comprobado, el procedimiento recomendado es editar el YAML del namespace y eliminar el contenido de spec.finalizers. En el ejemplo de la guía, aparece un valor como - kubernetes, que debe borrarse para desbloquear la eliminación. Esto puede hacerse desde una herramienta visual como k9s o mediante edición desde CLI:
kubectl get namespace <namespace> -o yaml kubectl edit namespace <namespace>
Dentro del manifiesto, se elimina el bloque o el contenido de:
spec: finalizers: - kubernetes
Después de guardar los cambios, Kubernetes suele completar la eliminación.
Como buena práctica, este procedimiento debe tratarse como una acción de recuperación, no como una operación rutinaria. Si ocurre con frecuencia, conviene revisar controladores, CRDs, operadores o procesos de limpieza que estén dejando finalizers sin resolver, porque el problema real normalmente no está en el namespace, sino en el componente que no está cerrando correctamente su ciclo de vida.
![]()
La automatización de certificados TLS en Kubernetes mediante Cert-Manager permite gestionar de forma dinámica la emisión, renovación y almacenamiento de certificados, eliminando procesos manuales y reduciendo riesgos operativos.
El enfoque habitual consiste en definir un recurso Ingress con anotaciones que indiquen a Cert-Manager qué ClusterIssuer utilizar (por ejemplo, Let’s Encrypt). Cert-Manager monitoriza ese recurso y se encarga de solicitar el certificado, validarlo y almacenarlo en un Secret.
Un ejemplo básico sería:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
namespace: production
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- app.ejemplo.com
secretName: app-tls
rules:
- host: app.ejemplo.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-service
port:
number: 80En esta configuración:
cert-manager.io/cluster-issuer indica qué emisor usar.tls define el dominio y el Secret donde se almacenará el certificado.Si existe un ClusterIssuer por defecto configurado, puede simplificarse mediante la anotación kubernetes.io/tls-acme: "true", evitando repetir el emisor en cada Ingress.
Consideraciones clave en entornos reales
CertificateRequest, Order y Challenge en caso de fallo.Este modelo permite operar infraestructuras con TLS gestionado de forma automática, escalable y alineada con prácticas modernas de seguridad en entornos cloud.
![]()
Cuando el pipeline automático no está disponible o el repositorio de código no está correctamente preparado, es perfectamente válido ejecutar un proceso de CI/CD manual para construir y publicar una imagen Docker. El flujo básico se compone de tres pasos: preparar el Dockerfile, construir la imagen y autenticarse para hacer el push al registro. La documentación lo plantea precisamente como alternativa operativa cuando hay que empujar imágenes a otro repositorio o resolver despliegues fuera del flujo automatizado.
El primer paso es disponer del código fuente y de un Dockerfile correcto. En el ejemplo documentado, este fichero define la imagen base, variables de entorno, dependencias del sistema, clonado del proyecto y ENTRYPOINT final. Una vez validado, se genera la imagen con docker build, pasando argumentos como la fecha de build, el fichero exacto y la etiqueta de versión:
docker build --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \ --file "docker/image/pro/Dockerfile" \ --no-cache --pull --rm \ --tag repodeimagenes.com/ejemplo/proyecto:1.0.0 \ docker/image/pro
Este patrón es útil porque fuerza actualización de capas base, evita reutilizar caché y deja trazabilidad de versión.
Después, hay que autenticarse contra el repositorio privado:
docker login repodeimagenes.com/ejemplo/
Y finalmente publicar la imagen:
docker push repodeimagenes.com/ejemplo/proyecto:1.0.0
La guía también recuerda que, si el destino es un registro privado de GitLab, el docker login previo es obligatorio antes del push.
Como buena práctica, conviene mantener una nomenclatura clara de tags, separar entornos (dev, pre, pro) y verificar localmente la imagen antes de subirla. En operación real, este tipo de proceso manual no sustituye a un pipeline maduro, pero sí resulta muy útil como mecanismo de contingencia controlado.
![]()
La actualización manual de Kubernetes en un clúster gestionado con Rancher Kubernetes Engine (RKE) implica modificar la configuración declarativa del clúster y reprovisionarlo. Este proceso es crítico, ya que afecta directamente al plano de control y a los nodos, por lo que debe ejecutarse de forma controlada.
El procedimiento comienza en el directorio donde se encuentran los ficheros del clúster (cluster.yml y cluster.rkestate). El primer paso es identificar las versiones soportadas:
rke config --list-version --all
Esto permite seleccionar una versión compatible con la infraestructura actual. A continuación, se edita el archivo cluster.yml y se modifica el campo:
kubernetes_version: "vX.X.X"
Este cambio define la versión objetivo del clúster.
Una vez actualizado el fichero, se ejecuta el reprovisionado:
rke up --config cluster.yml
Este comando aplica los cambios, actualizando progresivamente los componentes del clúster (control plane, etcd y workers). Si el archivo se llama cluster.yml, el parámetro --config puede omitirse.
Consideraciones clave en entornos productivos
cluster.rkestate) y de etcd antes de actualizar.En entornos operados de forma profesional, este proceso suele integrarse en procedimientos controlados de cambio, ya que una actualización mal planificada puede afectar a la disponibilidad del servicio.
![]()
Cuando un helm upgrade falla por APIs deprecadas o eliminadas en una versión más reciente de Kubernetes, el problema no suele estar en Helm como tal, sino en que el release almacenado en el clúster sigue referenciando recursos con versiones antiguas de API. En ese escenario, el plugin helm mapkubeapis permite reescribir esas referencias para que Helm pueda seguir gestionando el despliegue sin quedar bloqueado. La documentación lo plantea precisamente como solución para upgrades que fallan por versiones de API deprecadas.
El flujo recomendado es muy directo. Primero se instala el plugin:
helm plugin install https://github.com/helm/helm-mapkubeapis
Después, se listan los deployments Helm del namespace afectado:
helm -n <namespace> list
Y, por último, se ejecuta la conversión sobre el release concreto:
helm -n <namespace> mapkubeapis <deployment_name>
Ese comando actualiza los metadatos del release para sustituir referencias obsoletas por APIs compatibles con la versión actual del clúster. Tras ello, ya se puede reintentar el helm upgrade con muchas más garantías.
A nivel operativo, esta herramienta es especialmente útil tras upgrades de Kubernetes en los que desaparecen versiones antiguas como ciertos extensions/v1beta1 o apps/v1beta1. Aun así, conviene entender su alcance: corrige el estado almacenado por Helm, pero no sustituye la revisión del chart. Si las plantillas siguen generando manifiestos con APIs obsoletas, el siguiente upgrade volverá a fallar. Por eso, la buena práctica es usar mapkubeapis como paso de recuperación o transición y, en paralelo, actualizar el chart para que renderice únicamente recursos compatibles con la versión actual del clúster.
![]()
Publicar un Helm Chart en el registro de paquetes de GitLab con el plugin cm-push permite distribuir charts de forma controlada y reutilizable, algo especialmente útil en entornos donde se quiere estandarizar despliegues entre equipos o entornos. El flujo combina autenticación contra GitLab, alta del repositorio en Helm y publicación del chart.
El primer paso es crear en GitLab un token de acceso con permisos de lectura y escritura sobre la API. Ese token será necesario para autenticar Helm contra el registro de paquetes. Después, se añade el repositorio remoto con helm repo add, indicando el nombre lógico del repo, el token y la URL del endpoint Helm del proyecto:
helm repo add --username <nombre-del-token> --password <token-de-acceso> \ <nombre-del-repo> \ https://dev2.purpleblob.net/api/v4/projects/<id-del-proyecto>/packages/helm/<canal>
El id del proyecto se obtiene en GitLab, y el canal suele ser algo como stable. Si aparece un error 403, la propia guía indica que una causa frecuente es que el registro de paquetes no esté habilitado para ese repositorio.
A continuación, se instala el plugin:
helm plugin install https://github.com/chartmuseum/helm-push
Y desde el directorio donde está el Chart.yaml, se publica el chart con:
helm cm-push . <nombre-del-repo>
Este comando empaqueta y sube el chart en un solo paso, aunque también puede hacerse antes manualmente con helm package .. Después conviene actualizar el repositorio y probar una instalación en modo dry-run:
helm repo update <nombre-del-repo> helm install --debug --dry-run <release> <nombre-del-repo>/<nombre-del-chart>
Ese último paso es importante porque valida que el chart recién publicado puede resolverse e instalarse correctamente. En entornos serios, esta verificación evita propagar charts rotos a otros equipos o a pipelines de despliegue.
![]()
Validar un despliegue Helm antes de instalarlo en Kubernetes es una práctica muy recomendable, sobre todo cuando el chart incluye múltiples objetos parametrizados y dependencias entre recursos. La idea no es solo comprobar que "renderiza", sino revisar exactamente qué manifiestos va a generar Helm con los valores actuales antes de tocar el clúster.
En la documentación, este proceso se realiza mediante ./install.sh debug, que genera un fichero output.yaml con todos los objetos y configuraciones que se desplegarían en Kubernetes. Se recomienda ejecutarlo justo antes del despliegue para comprobar que el chart contiene los valores esperados y que no hay errores en la parametrización.
El flujo sería:
./install.sh debug
Ese script, según la guía, ejecuta lógica definida en helmcommon.sh, donde la opción debug está pensada específicamente para generar el output.yaml y facilitar la revisión previa.
¿Qué conviene revisar en ese output.yaml?
values.yaml son correctos: imágenes, namespaces, URLs, secretos, volúmenes y recursos.{{ .Values... }}.La propia documentación insiste en revisar el chart renderizado antes de ejecutar ./install.sh para desplegar en el clúster.
En operación real, esta validación previa reduce bastante el riesgo de despliegues fallidos, especialmente en entornos donde un cambio pequeño en values.yaml puede alterar red, persistencia o exposición pública del servicio. Es una práctica sencilla, pero muy útil para mantener despliegues más predecibles y auditables.
![]()
Crear un kubeconfig limitado a un único namespace es una forma muy eficaz de delegar acceso en Kubernetes sin exponer permisos sobre todo el clúster. El enfoque correcto consiste en asociar una identidad técnica (ServiceAccount) a un conjunto de permisos acotados (Role) y enlazarlos mediante un RoleBinding. A partir de ahí, se genera un kubeconfig que usa ese token y fija además el namespace por defecto. La documentación describe precisamente este flujo con un script que automatiza la creación del acceso restringido.
El proceso arranca creando un ServiceAccount dentro del namespace objetivo. Después se define un Role con permisos sobre los recursos necesarios, por ejemplo pods, services, deployments, jobs o cronjobs, y se vincula con un RoleBinding. En el ejemplo documentado, el Role concede acceso total dentro del namespace, aunque se indica expresamente que los verbos pueden editarse para limitarlo según necesidad. Esa es la buena práctica real: no dar * si no es imprescindible.
Una vez creados esos objetos, se obtiene el token del ServiceAccount, el certificado CA del clúster y el endpoint del servidor Kubernetes. Con esos datos se construye un fichero kubeconfig que define:
certificate-authority-data,current-context.La ventaja operativa es clara: quien use ese kubeconfig quedará acotado al namespace definido, tanto a nivel de permisos como de contexto por defecto. Esto resulta especialmente útil para separar accesos entre equipos, proveedores, automatizaciones o aplicaciones. En entornos bien gobernados, esta técnica es mucho más segura que compartir credenciales administrativas o kubeconfigs globales.
![]()
Antes de definir permisos RBAC en Kubernetes, es fundamental identificar correctamente el apiGroup de cada recurso, porque un Role o ClusterRole mal definido no fallará siempre de forma evidente: simplemente no concederá acceso sobre el recurso esperado. En otras palabras, puedes tener una regla aparentemente correcta, pero inútil si el recurso pertenece a otro grupo de API.
La documentación recomienda hacerlo con kubectl api-resources, filtrando después el recurso que te interesa. El comando propuesto es:
kubectl api-resources | grep -Fi "<recurso>" | \
awk '{if ($5 == "") print $1, $2; else print $1, $3}'Este patrón permite listar los recursos disponibles y extraer el nombre del recurso junto con su apiGroup. La guía explica además el papel de cada parte: kubectl api-resources devuelve todos los recursos del clúster, grep -Fi filtra por el término buscado y awk extrae el recurso y su grupo de API.
Esto es importante porque no todos los recursos pertenecen al grupo base "". Por ejemplo, pods y services suelen ir en el grupo vacío, mientras que ingresses pertenecen a networking.k8s.io. La propia documentación lo refleja en su ejemplo de Role, donde mezcla recursos del grupo base con otros del grupo de networking.
A nivel práctico, este paso debería formar parte de cualquier definición RBAC mínimamente rigurosa. Antes de escribir reglas, conviene confirmar tres cosas: nombre exacto del recurso, apiGroup correcto y verbos realmente necesarios. Esa verificación previa evita permisos mal concedidos, acelera el troubleshooting y reduce el riesgo de terminar ampliando privilegios "porque no funciona", cuando en realidad el problema era solo un grupo de API incorrecto.
![]()
Generar un usuario cliente para Kubernetes mediante certificados es un enfoque clásico cuando se quiere dar acceso autenticado a una persona o sistema sin usar un ServiceAccount. El flujo consta de cuatro fases: generar la clave y el CSR, enviarlo al clúster, aprobar el certificado y construir manualmente el kubeconfig. La documentación describe este procedimiento dentro del apartado de RBAC y generación de usuarios.
El primer paso es crear una clave RSA y un Certificate Signing Request con el nombre del usuario y, opcionalmente, su grupo:
USER="test-user" GROUP="A" KEY="test-user.key" CSR="test-user.csr" openssl genrsa -out "$KEY" 2048 openssl req -new -key "$KEY" -out "$CSR" -subj "/CN=$USER/O=$GROUP"
Después, ese CSR se envía al clúster como un recurso CertificateSigningRequest, indicando el signerName y el uso client auth. La guía también recuerda que expirationSeconds no puede ser infinito y que algunos clústeres pueden ignorar ese valor.
Una vez creado, un administrador debe aprobarlo:
kubectl certificate approve "$USER" kubectl get certificatesigningrequests.certificates.k8s.io
Tras la aprobación, se recuperan el certificado firmado y el CA del clúster:
kubectl get certificatesigningrequests "$USER" -o jsonpath='{.status.certificate}' | base64 --decode > test-user.crt
kubectl get cm kube-root-ca.crt -o jsonpath="{['data']['ca\.crt']}" > ca.crtPor último, se construye el kubeconfig con kubectl config set-cluster, set-credentials y set-context, asociando el certificado cliente, la clave privada, el endpoint del clúster y el namespace por defecto. Ese fichero será el que use la persona usuaria para autenticarse.
A nivel operativo, este método ofrece más control que compartir credenciales globales, pero debe combinarse siempre con RoleBinding o ClusterRoleBinding adecuados. El certificado autentica; los permisos reales los define RBAC.
![]()
Cuando una aplicación publicada detrás de un NGINX Ingress Controller falla al subir ficheros grandes, una causa muy habitual es que el límite de tamaño lo esté imponiendo el propio Ingress y no la aplicación. El síntoma típico es que cargas relativamente grandes, como importaciones de bases de datos o adjuntos pesados, devuelvan error aunque el backend esté correctamente configurado.
La forma más directa de corregirlo es añadir en el Ingress la anotación nginx.ingress.kubernetes.io/proxy-body-size, indicando el tamaño máximo permitido. La documentación lo plantea precisamente para estos casos y muestra como ejemplo un valor de 8m.
Un ejemplo sería:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
namespace: produccion
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "8m"
spec:
...Ese valor controla el tamaño máximo del cuerpo de la petición HTTP que NGINX aceptará antes de reenviarla al servicio backend. Si el fichero supera ese umbral, el rechazo se produce en la capa de entrada, por lo que aumentar recursos del pod o parámetros internos de la aplicación no resolverá el problema por sí solo.
A nivel práctico, conviene dimensionar este valor según el caso de uso real. Un límite demasiado bajo bloqueará operaciones legítimas; uno excesivamente alto puede aumentar superficie de abuso o consumo innecesario de recursos. Por eso, la buena práctica en entornos profesionales es ajustar el tamaño al tipo de carga esperado y revisar también si la aplicación, el backend HTTP o el balanceador intermedio tienen sus propios límites configurados. En otras palabras, el Ingress suele ser el primer punto a revisar, pero no siempre el único.
![]()
Cuando Velero no logra restaurar correctamente un volumen persistente, una alternativa avanzada es realizar la recuperación manual con Restic, accediendo directamente al almacenamiento de backups. Este procedimiento se considera de último recurso y requiere intervenir sobre el clúster y los volúmenes de forma controlada.
El primer paso es asegurarse de que el volumen puede montarse en un pod. Si el pod original no tiene permisos suficientes o está en mal estado, se puede crear un pod temporal que monte el mismo PersistentVolumeClaim. En configuraciones ReadWriteOnce, este pod debe ejecutarse en el mismo nodo que el original, ya que solo un nodo puede montar el volumen simultáneamente.
Una vez montado el volumen (por ejemplo en /data), se instala o copia el binario de Restic dentro del pod. Si el backup está en un almacenamiento S3, es necesario definir variables de entorno como:
export AWS_ACCESS_KEY_ID=<clave> export AWS_SECRET_ACCESS_KEY=<secreto>
Después, se ejecuta la restauración:
restic -r s3:<endpoint>/<bucket>/restic/velero/<namespace> \ restore <snapshot> --target /data
Este comando recupera el contenido del snapshot directamente en el volumen montado. También es posible usar opciones como --include o --exclude para restaurar solo partes concretas del sistema de ficheros.
Un punto clave es la contraseña del repositorio Restic, que normalmente se encuentra en los secretos desplegados por Velero. Sin ella, la restauración no será posible.
En entornos productivos, este tipo de intervención debe ejecutarse con precaución: validar el snapshot, evitar sobrescribir datos activos y documentar el proceso. Aunque es una operación manual, proporciona un control granular cuando los mecanismos automáticos fallan.
![]()
Velero permite automatizar la protección de datos en Kubernetes mediante backups programados (schedules) basados en expresiones cron, lo que facilita mantener copias consistentes del estado del clúster sin intervención manual. Este enfoque es clave en entornos productivos donde se requiere una estrategia de disaster recovery continua.
Para programar un backup automático, se utiliza el comando:
velero schedule create nombre-schedule \ --schedule="0 0 * * *" \ --default-volumes-to-fs-backup
La expresión cron define la frecuencia (en este caso, diario a medianoche). El flag --default-volumes-to-fs-backup asegura que también se incluyan los volúmenes persistentes mediante backup a nivel de filesystem.
Una vez creado, Velero ejecutará automáticamente backups siguiendo esa programación. Es posible listar los schedules activos:
velero schedule get
Y también lanzar un backup manual a partir de un schedule existente:
velero backup create --from-schedule nombre-schedule \ --default-volumes-to-fs-backup
Esto resulta útil para generar una copia puntual antes de una intervención crítica.
Para restaurar desde un backup concreto:
velero restore create nombre-restore \ --from-backup nombre-backup
Velero recreará los recursos del clúster (pods, servicios, volúmenes, etc.) según el estado capturado en ese backup.
![]()
Los hooks pre y post de Velero permiten ejecutar comandos dentro de los pods antes del backup y después del restore, algo especialmente útil en cargas con estado como MySQL. La idea es sencilla: no basta con copiar volúmenes; en muchos casos conviene preparar la aplicación para que la copia sea consistente o reinyectar datos una vez restaurados. La documentación muestra este patrón mediante anotaciones directamente en el manifiesto del pod.
En el caso de MySQL, el hook pre se usa para generar un mysqldump antes de que Velero capture el volumen:
metadata:
annotations:
pre.hook.backup.velero.io/command: '["/bin/bash", "-c", "mysqldump -u root -p$MYSQL_ROOT_PASSWORD velero > /var/lib/mysql/backup.sql"]'
pre.hook.backup.velero.io/timeout: 50sCon esto, el pod crea un volcado lógico dentro del propio volumen persistente antes del backup. Así, aunque el filesystem snapshot no capture un estado transaccional perfecto, el dump queda disponible como mecanismo adicional de recuperación.
Después, durante la restauración, puede ejecutarse un hook post para reimportar ese dump en MySQL:
metadata:
annotations:
post.hook.restore.velero.io/command: '["/bin/bash", "-c", "mysql -u root -p$MYSQL_ROOT_PASSWORD velero < /var/lib/mysql/backup.sql"]'
post.hook.restore.velero.io/exec-timeout: 50s
post.hook.restore.velero.io/wait-timeout: 2mEl exec-timeout limita la ejecución del comando y wait-timeout controla cuánto espera Velero antes de dar el hook por fallido.
A nivel práctico, esta técnica es muy útil cuando se quiere reforzar la consistencia de backup en bases de datos. Eso sí, conviene validar bien rutas, credenciales y tiempos de ejecución. En entornos operativos maduros, los hooks no sustituyen a una estrategia de backup de base de datos, pero sí añaden una capa muy útil de control y recuperabilidad.
![]()
El tipo de Secret kubernetes.io/dockerconfigjson es el formato estándar que Kubernetes espera para autenticarse contra un registro privado de imágenes. Su función es almacenar, en un único objeto, la URL del registro, el usuario, la contraseña y el campo auth codificado en base64. Cuando este secreto no existe, está mal formado o contiene credenciales inválidas, los pods suelen fallar con errores como ImagePullBackOff o pull access denied.
La forma más segura y práctica de crearlo es mediante CLI, porque evita errores manuales en el JSON:
kubectl -n <namespace> create secret docker-registry registry-credentials \ --docker-server <url_repositorio_imagenes> \ --docker-username <usuario> \ --docker-password <contrasena>
La propia documentación lo señala como la opción más sencilla para generar este tipo de secreto. Kubernetes construye automáticamente el contenido .dockerconfigjson con el formato correcto.
Si se define manualmente en YAML, debe seguir esta estructura conceptual:
kind: Secrettype: kubernetes.io/dockerconfigjsondata:.dockerconfigjson: <contenido_base64>Dentro de ese contenido, el bloque auths debe incluir la URL del repositorio y las credenciales correspondientes. La guía muestra precisamente ese formato, incluyendo username, password y el campo auth con base64(usuario:contraseña).
Una vez creado, el secreto debe referenciarse en imagePullSecrets dentro del Deployment o asociarse al ServiceAccount del namespace. En operación real, esa segunda opción suele ser útil cuando varios workloads comparten el mismo registro privado. Como buena práctica, conviene revisar siempre tres puntos cuando hay fallos de pull: que la imagen exista, que la URL del registro coincida exactamente con la usada en el secreto y que el token o usuario sigan vigentes.
![]()
En Docker Compose, publicar un puerto como 5432:5432 no solo lo hace accesible para otros contenedores: también lo expone en todas las interfaces de red del host. En el caso de una base de datos, eso amplía innecesariamente la superficie de ataque, porque el servicio puede quedar accesible desde el exterior de la máquina si no hay controles adicionales a nivel de firewall o red. La documentación lo señala expresamente y recomienda restringir esa exposición usando binding a 127.0.0.1.
Por ejemplo, una configuración menos segura sería:
postgresql:
image: postgres:14
ports:
- "5432:5432"En ese formato, Docker publica el puerto del contenedor en todas las interfaces del host. La alternativa recomendada es:
postgresql:
image: postgres:14
ports:
- "127.0.0.1:5432:5432"Con ello, el puerto queda accesible solo desde la propia máquina host, no desde otras IP de la red. Esto es especialmente útil cuando la base de datos solo necesita ser consumida localmente, por ejemplo por un proxy, una aplicación que corre en el mismo host o tareas de administración realizadas desde esa misma máquina. La guía de buenas prácticas Docker incluida en la documentación usa precisamente este patrón como configuración correcta para no exponer innecesariamente servicios sensibles.
A nivel operativo, esta medida no sustituye otras capas de seguridad, pero sí elimina un error muy frecuente: publicar bases de datos al exterior "por comodidad" durante desarrollo o integración. En entornos profesionales, la buena práctica es clara: si un servicio no necesita acceso externo directo, no debe anunciarse más allá de localhost. Y si otros contenedores necesitan conectarse, normalmente es preferible hacerlo por red interna de Docker, sin publicar el puerto en absoluto.
![]()
Montar un volumen local en Docker es la forma habitual de habilitar un flujo de desarrollo donde los cambios en el código se reflejan en tiempo real dentro del contenedor, sin necesidad de reconstruir la imagen en cada modificación. Este patrón es clave en entornos de desarrollo porque desacopla el código de la imagen y acelera el ciclo de trabajo.
La forma más directa es utilizar un bind mount, que enlaza un directorio del host con una ruta dentro del contenedor:
docker run -v $(pwd):/app imagen:tag
En este ejemplo, el directorio actual del host se monta en /app dentro del contenedor. Cualquier cambio en los archivos locales se refleja inmediatamente en el contenedor.
En docker-compose.yml, el equivalente sería:
services:
app:
image: mi-app:dev
volumes:
- ./src:/appEsto permite editar el código en ./src desde el host y que la aplicación dentro del contenedor lo utilice directamente.
Aspectos clave en entornos reales
En entornos profesionales, este enfoque permite a los equipos trabajar con entornos reproducibles (Docker) sin renunciar a la agilidad del desarrollo local, combinando lo mejor de ambos mundos.
![]()
Los errores de compilación en Docker relacionados con ficheros como ft2build.h suelen indicar que faltan dependencias del sistema necesarias para compilar una librería Python o nativa durante la build. No es un problema de Docker en sí, sino del entorno que el Dockerfile está preparando: la imagen base no incluye por defecto los paquetes de desarrollo que ciertas dependencias necesitan para compilarse. La documentación pone precisamente este caso como ejemplo y señala que el mensaje de error suele indicar qué cabecera falta.
El enfoque correcto consiste en identificar qué paquete del sistema aporta esa librería y añadirlo al Dockerfile antes del paso que falla. En el ejemplo documentado, el error con ft2build.h se resuelve instalando freetype-dev en una imagen Alpine:
RUN apk update && \
apk add build-base gcc make python3-dev musl-dev libffi-dev openssl-dev git rust cargo freetype-dev && \
apk add postgresql-dev libpqLa guía también subraya una cuestión importante: no basta con pensar solo en la fase de build. Si la aplicación necesita esa librería también en tiempo de ejecución, puede ser necesario instalarla tanto en la etapa de compilación como en la imagen final. Por eso, en el ejemplo se añade igualmente freetype-dev en la fase FINAL del Dockerfile.
A nivel práctico, la secuencia recomendable es siempre la misma: leer el error exacto, identificar el paquete del sistema que aporta la cabecera o librería, ubicar en qué capa del Dockerfile ocurre el fallo y añadir la dependencia antes de ese punto. En entornos profesionales, esta trazabilidad evita "parches a ciegas" y permite mantener imágenes más estables, reproducibles y fáciles de depurar.
![]()
Un Dockerfile multi-stage permite separar claramente la fase de construcción de la aplicación y la imagen final que se ejecutará en producción. Esto es especialmente útil en proyectos Python o Node porque reduce el tamaño final, elimina herramientas de compilación innecesarias y mejora la seguridad del contenedor.
La lógica es simple: en una primera etapa se instalan dependencias, se compila o prepara la aplicación y, en una segunda, solo se copian los artefactos necesarios para ejecutar el servicio. En la documentación aparece un ejemplo de construcción por etapas donde se parte de una imagen base para build, se configuran dependencias, variables y código del proyecto, y después se utiliza una fase FINAL separada para generar un contenedor más limpio de ejecución.
Un patrón típico en Python sería:
FROM python:3.11-alpine AS builder WORKDIR /app COPY requirements.txt . RUN apk add --no-cache build-base python3-dev libffi-dev openssl-dev RUN pip install --upgrade pip && pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt FROM python:3.11-alpine WORKDIR /app COPY --from=builder /wheels /wheels COPY requirements.txt . RUN pip install --no-cache /wheels/* COPY . /app ENTRYPOINT ["./docker-entrypoint.sh"]
Y en Node, el mismo principio aplica: una primera etapa instala dependencias y genera el artefacto, y una segunda solo copia el resultado final.
La ventaja operativa es clara: la imagen final no necesita incluir compiladores, herramientas de build ni cachés temporales. En entornos profesionales, esto mejora tiempos de despliegue, reduce superficie de ataque y facilita la trazabilidad entre build y runtime. La buena práctica no es solo "hacer que funcione", sino construir imágenes mínimas, reproducibles y alineadas con el comportamiento real del servicio en producción.
![]()
Convertir un proyecto Django en una imagen Docker no consiste solo en "meter la app en un contenedor", sino en definir una estructura operativa completa que permita construir, arrancar y coordinar todos los componentes necesarios del servicio. La documentación identifica cinco piezas clave para hacerlo bien: Dockerfile, docker-entrypoint.sh, supervisor.conf, .dockerignore y docker-compose.yml.
El Dockerfile define cómo se construye la imagen: imagen base, instalación de dependencias, copia del código y configuración del entorno. La guía recomienda partir de un Dockerfile ya funcional y extenderlo solo con lo que el proyecto necesite. El docker-entrypoint.sh actúa como punto de arranque y sirve para inicializar variables, lanzar migraciones o preparar servicios auxiliares. Es especialmente importante revisarlo con detalle, porque incluso entre proyectos parecidos pueden cambiar bastante las necesidades de arranque.
supervisor.conf se utiliza para vigilar procesos dentro del contenedor y mantener operativos servicios que la aplicación necesite, como workers o procesos auxiliares. .dockerignore, por su parte, evita que entren en la imagen archivos innecesarios o sensibles, como entornos virtuales locales, bases de datos de desarrollo o artefactos temporales.
Finalmente, docker-compose.yml orquesta la aplicación junto con sus dependencias, como PostgreSQL o RabbitMQ. En la documentación se muestra cómo una imagen propia puede integrarse con otras imágenes de soporte, declarar puertos, variables de entorno y relaciones entre servicios, y levantarse con docker-compose up.
En términos prácticos, esta separación de responsabilidades hace que el proyecto sea más mantenible y reproducible. En entornos serios, Docker no solo encapsula Django: también formaliza cómo se construye, cómo arranca y con qué servicios convive.
![]()
Una vez que la imagen propia de la aplicación ya está construida con docker build, el siguiente paso es declararla dentro de docker-compose.yml junto con los servicios auxiliares que necesita, como PostgreSQL y RabbitMQ. El objetivo de docker-compose up no es solo arrancar contenedores, sino componer un entorno funcional completo donde la aplicación pueda resolver dependencias, conectarse a la base de datos y comunicarse con la cola de mensajes.
En la documentación se muestra un ejemplo en el que la aplicación web referencia una imagen propia, expone puertos y define variables de entorno para conectar con otros servicios:
webapp:
image: project:0.0.1
ports:
- "80:8080"
- "443:443"
environment:
- "ALLOWED_HOSTS='*'"
- "SECRET_KEY=ejemplo"
- "DB_HOST=ejemplo"
- "DB_USER=ejemplo"
- "DB_PASSWORD=ejemplo"
- "DB_NAME=ejemplo"
- "RABBITMQ_HOST=ejemplo"
- "RABBITMQ_USER=ejemplo"
- "RABBITMQ_PASS=ejemplo"
links:
- postgresql
- message-queueLa clave aquí es que la aplicación ya no se ejecuta de forma aislada: Compose la integra con el resto de componentes del stack. PostgreSQL y RabbitMQ deben estar definidos como servicios adicionales en el mismo fichero, con sus imágenes, puertos internos y variables necesarias. Después, basta con ejecutar:
docker-compose up
La propia guía señala que, ejecutado sin parámetros extra, este comando también muestra los logs en tiempo real, lo que resulta muy útil para depurar problemas de arranque, conexión o configuración entre servicios.
En entornos de desarrollo, este patrón permite reproducir fácilmente un entorno completo. En términos operativos, la buena práctica es mantener una configuración clara de variables, evitar exponer puertos sensibles innecesariamente y comprobar que los nombres de servicio usados en la aplicación coinciden con los declarados en Compose.
![]()
Gestiona tu identidad digital con facilidad. Registra, renueva y administra todos tus dominios desde una única plataforma, con soporte técnico experto y sin complicaciones.
Colabora mejor con soluciones integradas que permiten compartir agendas, contactos y documentos desde tus propios buzones de correo, sin herramientas adicionales.
Protege tus datos críticos con backups automáticos, fiables y adaptados a tu entorno. Recupera información en minutos ante cualquier incidente.