En fechas recientes, debido a la retirada de la infraestructura existente de zbpack v1, Zeabur está distribuyendo a todos los usuarios la nueva generación del sistema de construcción (zbpack v2). Durante el proceso de actualización han surgido problemas de compatibilidad. En esta entrada explicamos las causas, cómo los hemos abordado y qué puedes hacer para mitigar el problema si te afecta.
Así funciona la infraestructura de compilación detrás de Zeabur:
El «registry v1» estaba basado en el registro de distribution/distribution. Los diversos problemas que ocasionaba nos impulsaron a migrar a un «registry v2» diseñado por nosotros:
blob unknown
y a rechazar la subida del manifiesto, impidiendo el pull de la imagen al arrancar.distribution/distribution
favorece la desduplicación global de blobs, lo que impide saber qué blobs son prescindibles sin leer todos los manifiestos. La herramienta oficial de garbage collection exige detener el servicio (stop-the-world) y, a la escala del registro de Zeabur, es inviable; R2 acumuló una gran cantidad de blobs, causando problemas serios de rendimiento.Diseñamos el registry v2 para que, tras construir una imagen OCI, se suba directamente a un bucket de R2. Luego, mediante Cloudflare Workers, implementamos una API de solo lectura que transforma la estructura OCI del bucket en un Pull API conforme a la Especificación de Distribución de OCI. Con ello logramos grandes mejoras de rendimiento, maximizamos la eficiencia de las subidas multipart y evitamos los problemas del registro anterior. A la vez, limitamos la desduplicación de blobs al interior de cada repositorio, permitiendo que «al eliminar un repositorio se pueda hacer GC de sus blobs asociados», simplificando enormemente el mantenimiento sin necesidad de stop-the-world.
Sin embargo, como se deduce de lo anterior, el flujo de push en el registry v2 cambia sustancialmente. Esta parte ya está implementada en zbpack v2, pero en zbpack v1, debido a su flujo de push más complejo y a la fuerte dependencia del CLI de buildkit para construir imágenes, resultaba difícil. Por ello, durante el último mes dejamos que los proyectos que seguían en zbpack v1 (registry v1) continuaran compilando con v1 y solo migrábamos manualmente a zbpack v2 cuando un usuario informaba que v1 no podía arrancar.
Cuando el registry v1 comenzó a resentirse cada vez más y la frecuencia de errores aumentó, el volumen de tickets creció tanto que nos vimos obligados a mover la parte de imágenes de zbpack v1 hacia zbpack v2.
Quizá hayas notado que el repositorio de zbpack (v1) pasó de archivado a activo y recibió muchos cambios relacionados con Dockerfile. En realidad, esto era la preparación de una capa de compatibilidad para conectar zbpack v1 con zbpack v2.
Queríamos mantener la generación de Dockerfile de zbpack v1, pero sin usar su lógica de construcción integrada después, sino pasar a zbpack v2. Por ello, convertimos la generación de Dockerfile de v1 en una función pública y dejamos que el servicio de construcción la usara para producir el Dockerfile, que luego se envía a las máquinas de compilación que ejecutan zbpack v2.
No obstante, zbpack v1 fue concebido inicialmente para funcionar dentro de la máquina de compilación y había muchas piezas que implementar o adaptar:
Implementamos la capa de compatibilidad de zbpack v1, portando el manejo que hacía la máquina de compilación al invocar a v1. La mayoría de los problemas evidentes (como la lectura de código) se resolvieron antes del despliegue global, y en pruebas internas en máquinas de test no observamos falsos positivos. También hubo ingenieros on-call monitorizando el impacto. Aun así, al desplegar en todo el parque surgieron problemas no contemplados. Por ejemplo:
ZBPACK_
.ZBPACK_DOCKERFILE_NAME
no coincidía con el previo.Como algunos escenarios no tenían entorno de pruebas equivalente y retroceder podía tener un impacto mayor, durante las guardias optamos por corregir, probar y desplegar con rapidez, ofreciendo a la vez workarounds a los clientes. Entre el 26 y el 27 de agosto implementamos rápidamente la capa de compatibilidad completa de zbpack, añadimos la visualización de plan type y plan meta, y diseñamos una CDN específica para China continental para acelerar las descargas del registry v2.
Agradecemos a todos los clientes que reportaron problemas: nos ayudaron a descubrir casos límite no cubiertos por la capa de compatibilidad y nos empujaron a investigarlos y corregirlos.
Los problemas mencionados arriba ya están implementados o corregidos en la capa de compatibilidad. Si encuentras otros huecos, abre un ticket y nuestros ingenieros lo revisarán.
Los problemas conocidos a día de hoy son:
PORT=<puerto externo>
(por ejemplo, PORT=8080
).En retrospectiva, las causas principales del incidente fueron:
Si te viste afectado por este incidente, podemos ofrecer créditos como compensación proporcional al tiempo de impacto. Seremos más cautelosos en futuros despliegues de esta funcionalidad y, nuevamente, gracias a todos quienes nos ayudaron a detectar problemas en la capa de compatibilidad.