--- title: "Cómo instalar un ensemble ZooKeeper en Ubuntu 24.04" description: "Instala Apache ZooKeeper en tres servidores Ubuntu 24.04 como ensemble replicado, gestiónalo con systemd, trabaja con znodes y protégelos con ACLs." category: "Descubrimiento de Servicios" language: es source: https://cubepath.com/es/docs/descubrimiento-de-servicios/instalacion-y-configuracion-de-zookeeper updated: 2026-09-25 --- # Cómo instalar un ensemble ZooKeeper en Ubuntu 24.04 Apache ZooKeeper es un servicio de coordinación distribuida: guarda pequeños datos en un árbol de nodos (*znodes*) replicado en varios servidores y ofrece primitivas como nodos efímeros, nodos secuenciales y notificaciones (*watches*), sobre las que se construyen la elección de líder, el registro de servicios o los bloqueos distribuidos. Lo usan Apache HBase, Solr, Hadoop y muchas aplicaciones propias. En este tutorial instalarás un *ensemble* de tres servidores ZooKeeper en Ubuntu 24.04, lo gestionarás con systemd y aprenderás a trabajar con znodes y ACLs. ## Requisitos previos Para seguir esta guía necesitas: - Tres servidores con Ubuntu 24.04 LTS, por ejemplo tres VPS de CubePath, con al menos 2 GB de RAM cada uno. - Un usuario no root con privilegios `sudo` en cada servidor. - Una red privada entre los tres. En los ejemplos se usan estas direcciones, sustitúyelas por las tuyas: | Nombre | IP privada | ID de ZooKeeper | |---|---|---| | zk-01 | 10.0.1.10 | 1 | | zk-02 | 10.0.1.11 | 2 | | zk-03 | 10.0.1.12 | 3 | Un ensemble necesita que la mayoría de servidores estén activos para funcionar. Con tres servidores tolera la caída de uno; con cinco, de dos. Salvo que se indique lo contrario, ejecuta cada paso en los tres servidores. > Nota: Apache Kafka 4.0 y posteriores ya no usan ZooKeeper (funcionan solo en modo KRaft). Si instalas ZooKeeper únicamente para un Kafka nuevo, no lo necesitas. ## Paso 1: Instalar Java ZooKeeper es una aplicación Java. Instala el entorno de ejecución de OpenJDK 17 sin componentes gráficos: ```bash sudo apt update sudo apt install -y openjdk-17-jre-headless java -version ``` ```output openjdk version "17.0.x" ... OpenJDK Runtime Environment (build 17.0.x+...-Ubuntu-...) OpenJDK 64-Bit Server VM (build 17.0.x+..., mixed mode, sharing) ``` ## Paso 2: Descargar e instalar ZooKeeper Usarás el paquete binario oficial de Apache. Consulta la versión estable actual en la [página de releases de ZooKeeper](https://zookeeper.apache.org/releases.html) y ajusta la variable. El archivo de Apache (`archive.apache.org`) conserva todas las versiones, así que la URL no deja de funcionar cuando sale una nueva: ```bash ZK_VERSION=3.9.3 cd /tmp curl -fsSLO "https://archive.apache.org/dist/zookeeper/zookeeper-${ZK_VERSION}/apache-zookeeper-${ZK_VERSION}-bin.tar.gz" curl -fsSLO "https://archive.apache.org/dist/zookeeper/zookeeper-${ZK_VERSION}/apache-zookeeper-${ZK_VERSION}-bin.tar.gz.sha512" sha512sum "apache-zookeeper-${ZK_VERSION}-bin.tar.gz" cat "apache-zookeeper-${ZK_VERSION}-bin.tar.gz.sha512" ``` Los dos comandos deben mostrar el mismo hash. Si no coinciden, borra el archivo y vuelve a descargarlo. Extrae el paquete en `/opt` y crea un enlace simbólico estable, para que las actualizaciones consistan en cambiar el enlace: ```bash sudo tar -xzf "apache-zookeeper-${ZK_VERSION}-bin.tar.gz" -C /opt sudo ln -sfn "/opt/apache-zookeeper-${ZK_VERSION}-bin" /opt/zookeeper ``` Crea un usuario de sistema sin shell y el directorio de datos: ```bash sudo useradd --system --home-dir /var/lib/zookeeper --shell /usr/sbin/nologin zookeeper sudo install -d -o zookeeper -g zookeeper -m 0750 /var/lib/zookeeper /var/lib/zookeeper/data /var/log/zookeeper ``` Los binarios quedan como propiedad de root; el usuario `zookeeper` solo necesita escribir en su directorio de datos y de logs. ## Paso 3: Configurar el ensemble Crea el archivo de configuración principal: ```bash sudo nano /opt/zookeeper/conf/zoo.cfg ``` El contenido es idéntico en los tres servidores: ```ini tickTime=2000 initLimit=10 syncLimit=5 dataDir=/var/lib/zookeeper/data clientPort=2181 maxClientCnxns=60 autopurge.snapRetainCount=5 autopurge.purgeInterval=24 4lw.commands.whitelist=ruok,srvr,stat,mntr,conf admin.serverAddress=127.0.0.1 admin.serverPort=8080 server.1=10.0.1.10:2888:3888 server.2=10.0.1.11:2888:3888 server.3=10.0.1.12:2888:3888 ``` Qué hace cada bloque: - `tickTime` es la unidad de tiempo en milisegundos. `initLimit` y `syncLimit` son los ticks que un seguidor puede tardar en conectarse al líder y en mantenerse sincronizado (20 y 10 segundos). - `dataDir` guarda los snapshots y el registro de transacciones. - `autopurge.*` borra cada 24 horas los snapshots antiguos y conserva los 5 últimos. Sin esto, el disco se llena con el tiempo. - `4lw.commands.whitelist` habilita los comandos de diagnóstico de cuatro letras. Por defecto solo está permitido `srvr`. - `admin.serverAddress` limita la AdminServer HTTP a `127.0.0.1`. Por defecto escucha en todas las interfaces en el puerto 8080. - Cada línea `server.N` define un miembro: su ID, su IP, el puerto por el que los seguidores hablan con el líder (2888) y el de elección de líder (3888). Usa IP y no nombres de host: en Ubuntu, el nombre propio del servidor suele resolver a `127.0.1.1` y ZooKeeper escucharía solo en local. Cada servidor necesita saber cuál es su ID. Escríbelo en el archivo `myid` del directorio de datos, con el valor que corresponda a cada nodo (1 en zk-01, 2 en zk-02, 3 en zk-03): ```bash echo 1 | sudo tee /var/lib/zookeeper/data/myid sudo chown zookeeper:zookeeper /var/lib/zookeeper/data/myid ``` ## Paso 4: Crear el servicio systemd Crea la unidad systemd. `zkServer.sh start-foreground` mantiene el proceso en primer plano, que es lo que espera systemd, y los logs van directamente al journal: ```bash sudo nano /etc/systemd/system/zookeeper.service ``` ```ini [Unit] Description=Apache ZooKeeper Documentation=https://zookeeper.apache.org Wants=network-online.target After=network-online.target [Service] Type=simple User=zookeeper Group=zookeeper Environment=ZOO_LOG_DIR=/var/log/zookeeper Environment="SERVER_JVMFLAGS=-Xms1g -Xmx1g" ExecStart=/opt/zookeeper/bin/zkServer.sh start-foreground Restart=on-failure RestartSec=10 LimitNOFILE=65536 [Install] WantedBy=multi-user.target ``` `SERVER_JVMFLAGS` fija la memoria de la JVM. Un valor fijo (mismo `-Xms` y `-Xmx`) de la mitad de la RAM del servidor es un buen punto de partida; ZooKeeper guarda todo el árbol en memoria, pero con datos de coordinación rara vez necesita más de unos pocos GB. ## Paso 5: Abrir los puertos y arrancar Permite el tráfico de ZooKeeper solo desde la red privada: 2181 para clientes, 2888 y 3888 entre servidores. Si UFW no está activo, permite antes SSH: ```bash sudo ufw allow OpenSSH sudo ufw allow from 10.0.1.0/24 to any port 2181 proto tcp sudo ufw allow from 10.0.1.0/24 to any port 2888 proto tcp sudo ufw allow from 10.0.1.0/24 to any port 3888 proto tcp sudo ufw enable ``` Arranca el servicio en los tres servidores: ```bash sudo systemctl daemon-reload sudo systemctl enable --now zookeeper sudo systemctl status zookeeper ``` Cuando los tres estén en marcha, comprueba el rol de cada uno: ```bash /opt/zookeeper/bin/zkServer.sh status ``` ```output ZooKeeper JMX enabled by default Using config: /opt/zookeeper/bin/../conf/zoo.cfg Client port found: 2181. Client address: localhost. Client SSL: false. Mode: follower ``` Uno de los tres servidores mostrará `Mode: leader` y los otros dos `Mode: follower`. Si ves `Mode: standalone`, las líneas `server.N` no se han leído; si el comando no puede conectarse, revisa los logs con `sudo journalctl -u zookeeper -e`. Comprueba también la salud con un comando de cuatro letras: ```bash echo ruok | nc 127.0.0.1 2181 ``` ```output imok ``` ## Paso 6: Trabajar con znodes El cliente `zkCli.sh` permite explorar y modificar el árbol. Conéctate al ensemble indicando los tres servidores; si uno cae, el cliente se reconecta a otro: ```bash /opt/zookeeper/bin/zkCli.sh -server 10.0.1.10:2181,10.0.1.11:2181,10.0.1.12:2181 ``` Los siguientes comandos se escriben dentro del shell de ZooKeeper. Crea un znode persistente con datos y léelo: ```text create /app "" create /app/config "log_level=info" get /app/config ``` ```output Created /app Created /app/config log_level=info ``` Actualiza el valor y consulta los metadatos. El campo `dataVersion` aumenta con cada cambio, lo que permite actualizaciones condicionales: ```text set /app/config "log_level=debug" stat /app/config ``` Los nodos efímeros desaparecen cuando se cierra la sesión del cliente que los creó. Son la base del registro de servicios: cada instancia crea el suyo y, si se cae, desaparece solo. Los nodos secuenciales reciben un sufijo numérico creciente, útil para colas y elección de líder: ```text create /app/workers "" create -e /app/workers/worker-01 "10.0.2.10:8080" create -s /app/workers/job- "tarea" ls /app/workers ``` ```output [job-0000000001, worker-01] ``` Para recibir una notificación cuando cambie un nodo, registra un *watch*. Ejecuta esto, cambia el valor desde otra sesión de `zkCli.sh` y verás el aviso `WatchedEvent`: ```text get -w /app/config ``` Sal del shell con `quit`. Puedes comprobar desde otro servidor que los datos se han replicado: ```bash /opt/zookeeper/bin/zkCli.sh -server 10.0.1.12:2181 get /app/config ``` ## Paso 7: Proteger znodes con ACLs Por defecto cualquier cliente que llegue al puerto 2181 puede leer y modificar todo el árbol. Las ACLs se definen por znode con el formato `esquema:id:permisos`, donde los permisos son `c` (crear hijos), `d` (borrar hijos), `r` (leer), `w` (escribir) y `a` (administrar ACLs). El esquema `digest` autentica con usuario y contraseña. Conéctate con `zkCli.sh` y, dentro del shell, autentícate y crea un znode que solo ese usuario pueda usar. El esquema `auth` aplica la ACL a los usuarios autenticados en la sesión actual. Sustituye `your_strong_password` por una contraseña real: ```text addauth digest appuser:your_strong_password create /secretos "dato-privado" auth::cdrwa getAcl /secretos ``` ```output Created /secretos 'digest,'appuser:... : cdrwa ``` Abre una segunda sesión de `zkCli.sh` sin autenticarte e intenta leerlo: ```text get /secretos ``` ```output Insufficient permission : /secretos ``` Tras ejecutar `addauth digest appuser:your_strong_password` en esa sesión, la lectura funciona. Para un znode que todos puedan leer pero solo el usuario autenticado pueda modificar, combina dos ACLs: `setAcl /app world:anyone:r,auth::cdrwa`. > Importante: las credenciales `digest` viajan en claro por la red. Mantén el puerto 2181 limitado a la red privada, como en el paso 5, o configura TLS entre clientes y servidores. ## Paso 8: Monitorizar el ensemble El comando `mntr` devuelve métricas en formato clave-valor, fáciles de recoger con cualquier sistema de monitorización: ```bash echo mntr | nc 127.0.0.1 2181 | grep -E 'zk_server_state|zk_avg_latency|zk_outstanding_requests|zk_synced_followers' ``` ```output zk_server_state leader zk_avg_latency 0.4 zk_outstanding_requests 0 zk_synced_followers 2 ``` Vigila especialmente: - `zk_server_state`: debe haber exactamente un `leader` en el ensemble. - `zk_synced_followers` (solo en el líder): debe ser el número de servidores menos uno. - `zk_outstanding_requests`: si crece de forma sostenida, el ensemble no da abasto. - `zk_avg_latency`: latencia media en milisegundos; valores altos suelen indicar disco lento. La AdminServer ofrece la misma información en JSON a través de HTTP, solo en local: ```bash curl -s http://127.0.0.1:8080/commands/ruok ``` ```output { "command" : "ruok", "error" : null } ``` ## Solución de problemas - **El servidor muestra `Mode: standalone`:** falta el archivo `myid` o las líneas `server.N` no están en `zoo.cfg`. Revisa ambos y reinicia con `sudo systemctl restart zookeeper`. - **No se elige líder (`Error contacting service` en todos los nodos):** los servidores no se ven por el puerto 3888. Prueba `nc -zv 10.0.1.11 3888` y revisa las reglas de UFW. Comprueba también que cada `myid` coincide con su línea `server.N`. - **`ruok is not executed because it is not in the whitelist`:** añade el comando a `4lw.commands.whitelist` en `zoo.cfg` y reinicia. - **`Address already in use` en el puerto 8080:** otra aplicación usa ese puerto. Cambia `admin.serverPort` o desactiva la AdminServer con `admin.enableServer=false`. - **Disco lleno en `/var/lib/zookeeper`:** falta la purga automática. Comprueba los valores `autopurge.*`. ## Conclusión Tienes un ensemble de tres servidores ZooKeeper replicado, gestionado con systemd, con purga automática de snapshots, comandos de diagnóstico habilitados y ACLs para proteger los znodes. Como siguientes pasos, recoge las métricas de `mntr` en tu sistema de monitorización, configura TLS para las conexiones de clientes si salen de la red privada y conecta tus aplicaciones al ensemble con la cadena `10.0.1.10:2181,10.0.1.11:2181,10.0.1.12:2181`.