Saltar al contenido principal

Construcción

La construcción de imágenes en Docker es el proceso de crear una imagen de contenedor que contiene todo lo necesario para ejecutar una aplicación: desde el sistema operativo base hasta las dependencias y configuraciones específicas de la aplicación.

Kaniko

Kaniko es una herramienta diseñada para construir imágenes de contenedores en entornos donde no se dispone de acceso a privilegios de root ni a un demonio de Docker en ejecución. Esto la hace especialmente útil en sistemas de integración continua (CI) y en entornos controlados donde la seguridad y la portabilidad son prioritarias.

Características principales

  • Construcción sin privilegios de root: Kaniko permite construir imágenes de contenedor sin requerir acceso de superusuario, lo que reduce la superficie de ataque y mejora la seguridad en entornos restringidos.
  • Compatibilidad con Dockerfile: Utiliza el archivo Dockerfile estándar para definir los pasos de construcción, aceptando la misma sintaxis y comandos que Docker, lo que facilita la migración y reutilización de configuraciones existentes.
  • Cacheado de capas: Emplea un sistema de cacheado de capas que acelera los tiempos de construcción al reutilizar capas previamente generadas para instrucciones del Dockerfile que no han cambiado.
  • Ejecución como contenedor: Kaniko se ejecuta como un contenedor, lo que proporciona aislamiento, portabilidad y facilidad de integración en diferentes plataformas y sistemas de CI/CD.
  • Compatibilidad con repositorios privados: Puede autenticarse y acceder a repositorios privados para obtener capas de imágenes base durante el proceso de construcción, facilitando la gestión de imágenes protegidas.
  • Soporte multiplataforma: Permite la construcción de imágenes para diferentes arquitecturas, adaptándose a las necesidades de despliegue en distintos entornos.

Beneficios:

  • Seguridad mejorada: Al no requerir privilegios elevados ni acceso directo al demonio de Docker, Kaniko reduce los riesgos asociados a la construcción de imágenes en entornos compartidos o automatizados.
  • Portabilidad: Facilita la construcción de imágenes en cualquier entorno compatible con contenedores, sin depender de la infraestructura local o de servicios específicos.
  • Optimización de recursos: Permite distribuir la carga de trabajo de construcción en diferentes sistemas o agentes de CI, aprovechando los recursos disponibles de manera eficiente.
  • Integración sencilla: Se integra fácilmente en pipelines de CI/CD, permitiendo la automatización completa del proceso de construcción y publicación de imágenes.

GitLab

.gitlab-ci.yml
.docker_build:
stage: build
dependencies: ['composer_prod', 'npm']
extends: .dependencies_cache
image:
name: gcr.io/kaniko-project/executor@sha256:e935bfe222bc3ba84797e90a95fcfb1a63e61bcf81275c2cac5edfb0343b2e85
entrypoint: [""]
script:
- mkdir tar_images
- /kaniko/executor
--context "${CI_PROJECT_DIR}"
--dockerfile "${CI_PROJECT_DIR}/deployment/php/Dockerfile"
--destination "${DOCKER_REGISTRY_URL}/osdo/osdo-app:${CI_COMMIT_TAG}" --no-push --tar-path tar_images/osdo_app.tar
artifacts:
paths:
- tar_images
when: on_success
  • stage: Define la fase del pipeline en la que se ejecuta este job, en este caso build, indicando que corresponde al proceso de construcción de la imagen de contenedor.
  • dependencies: Especifica que este job depende de los jobs composer_prod y npm, asegurando que las dependencias PHP y JavaScript estén instaladas antes de construir la imagen.
  • extends: Hereda la configuración de .dependencies_cache, lo que permite reutilizar reglas de caché y otras configuraciones comunes definidas previamente en el pipeline.
  • image: Utiliza una imagen de contenedor específica de Kaniko, identificada por un hash sha256, que contiene las herramientas necesarias para construir imágenes de contenedor de forma segura y reproducible.
  • entrypoint: Sobrescribe el punto de entrada por defecto de la imagen, estableciéndolo como vacío para permitir la ejecución personalizada de comandos en el script.
  • script: Lista los comandos principales que se ejecutan en el job:
    • Crea el directorio tar_images para almacenar la imagen generada en formato tar.
    • Ejecuta Kaniko con los parámetros necesarios:
      • --context: Define el directorio raíz del proyecto como contexto de construcción.
      • --dockerfile: Especifica la ubicación del Dockerfile a utilizar.
      • --destination: Indica el destino de la imagen en el registro de contenedores, utilizando la URL y el tag del commit.
      • --no-push: Indica que la imagen no se subirá automáticamente al registro, sino que se almacenará localmente.
      • --tar-path: Define la ruta donde se guardará la imagen como archivo tar.
  • artifacts: Especifica que el directorio tar_images debe conservarse como artefacto tras la ejecución del job, permitiendo su descarga o uso en etapas posteriores del pipeline. El artefacto se guarda solo si el job finaliza correctamente (when: on_success).

GitHub

.github/workflows/ci.yml
docker_build:
name: Docker Build
id: docker_build
runs-on: ubuntu-latest
needs: [composer, npm]
steps:
- name: Clonar repositorio
uses: actions/checkout@v4
- name: Recuperar artifacts
uses: actions/download-artifact@v4
- name: Crear directorio tar_images
run: mkdir -p tar_images
- name: Build Docker image with Kaniko
uses: docker://gcr.io/kaniko-project/executor:latest
with:
entrypoint: ""
args: >
--context .
--dockerfile docker/nginx/Dockerfile
--destination harbor.opensecdevops.com/osdo/osdo-app:${{ github.sha }}
--tar-path tar_images/osdo_app.tar
--no-push

- name: Upload Docker image tar
uses: actions/upload-artifact@v4
with:
name: docker_image
path: tar_images/
retention-days: 1
  • name: Define el nombre del job como Docker Build, facilitando su identificación dentro del workflow de GitHub Actions.
  • runs-on: Especifica el sistema operativo del runner donde se ejecutará el job, en este caso ubuntu-latest, asegurando un entorno limpio y consistente para cada ejecución.
  • needs: Indica que este job depende de los jobs composer y npm, por lo que no se ejecutará hasta que la instalación de dependencias PHP y JavaScript haya finalizado correctamente.
  • steps: Lista los pasos que se ejecutarán en el job:
    • Clonar repositorio: Usa la acción actions/checkout@v4 para clonar el repositorio en el runner y disponer del código fuente necesario para la construcción de la imagen.
    • Recuperar artifacts: Usa la acción actions/download-artifact@v4 para descargar los artefactos generados en jobs previos, como dependencias o archivos de compilación.
    • Crear directorio tar_images: Ejecuta el comando mkdir -p tar_images para crear el directorio donde se almacenará la imagen de contenedor en formato tar.
    • Build Docker image with Kaniko: Utiliza la imagen de Kaniko (gcr.io/kaniko-project/executor:latest) para construir la imagen de contenedor sin requerir privilegios de root ni demonio de Docker. Se especifican los siguientes argumentos:
      • --context .: Define el directorio raíz del repositorio como contexto de construcción.
      • --dockerfile docker/nginx/Dockerfile: Especifica la ubicación del Dockerfile a utilizar.
      • --destination harbor.opensecdevops.com/osdo/osdo-app:${{ github.sha }}: Indica el destino de la imagen en el registro de contenedores, utilizando el hash del commit como tag.
      • --tar-path tar_images/osdo_app.tar: Define la ruta donde se guardará la imagen como archivo tar.
      • --no-push: Indica que la imagen no se subirá automáticamente al registro, sino que se almacenará localmente.
    • Upload Docker image tar: Usa la acción actions/upload-artifact@v4 para subir el archivo tar generado como artefacto del workflow, permitiendo su descarga o uso en etapas posteriores. Se especifica el nombre del artefacto (docker_image), la ruta (tar_images/) y el tiempo de retención (retention-days: 1).

Jenkins

Jenkinsfile
stage('Build Image with Kaniko') {
environment {
DOCKER_REGISTRY_URL = 'harbor.opensecdevops.com'
}
steps {
unstash 'deps'
script {
if (env.TAG_NAME) {
env.IMAGE_TAG = env.TAG_NAME
} else {
def sha = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
env.IMAGE_TAG = "${env.BRANCH_NAME}-${sha}"
}

sh 'mkdir -p tar_images'
sh """
docker run --rm \
-v /workspace/${JOB_NAME}:/app \
-w /app \
gcr.io/kaniko-project/executor:latest \
--context /app \
--dockerfile /app/docker/nginx/Dockerfile \
--destination ${DOCKER_REGISTRY_URL}/osdo/osdo-app:\${IMAGE_TAG} \
--no-push \
--tar-path tar_images/osdo_app.tar
"""
}
}
post {
success {
archiveArtifacts artifacts: 'tar_images/**', fingerprint: true
stash name: 'docker-image', includes: 'tar_images/osdo_app.tar'
}
}
}
  • environment:
    Define variables de entorno necesarias para el proceso:

    • DOCKER_REGISTRY_URL: URL del registro de contenedores donde se almacenará la imagen generada.
  • unstash 'deps':
    Recupera las dependencias previamente almacenadas en una etapa anterior del pipeline, asegurando que estén disponibles para la construcción de la imagen.

  • script:
    Ejecuta un bloque de instrucciones en Groovy para preparar y construir la imagen:

    • Comprueba si existe una variable TAG_NAME (por ejemplo, para releases); si existe, la usa como tag de la imagen. Si no, genera un tag basado en el nombre de la rama y el hash corto del commit actual, asegurando la trazabilidad de la imagen.
    • Ejecuta mkdir -p tar_images para crear el directorio donde se almacenará la imagen en formato tar.
    • Ejecuta el comando docker run con la imagen de Kaniko para construir la imagen de contenedor:
      • Monta el workspace del job en el contenedor (-v /workspace/${JOB_NAME}:/app).
      • Establece el directorio de trabajo (-w /app).
      • Usa Kaniko (gcr.io/kaniko-project/executor:latest) para construir la imagen con los siguientes argumentos:
        • --context /app: Define el contexto de construcción.
        • --dockerfile /app/docker/nginx/Dockerfile: Especifica la ubicación del Dockerfile.
        • --destination ${DOCKER_REGISTRY_URL}/osdo/osdo-app:${IMAGE_TAG}: Indica el destino y tag de la imagen.
        • --no-push: Indica que la imagen no se subirá automáticamente al registro, sino que se almacenará localmente.
        • --tar-path tar_images/osdo_app.tar: Define la ruta donde se guardará la imagen como archivo tar.
  • post > success:
    Acciones a ejecutar si el stage finaliza correctamente:

    • archiveArtifacts artifacts: 'tar_images/**', fingerprint: true: Guarda la imagen generada como artefacto del build y asegura la trazabilidad mediante fingerprint.
    • stash name: 'docker-image', includes: 'tar_images/osdo_app.tar': Almacena el archivo tar generado en el stash de Jenkins para su uso en etapas posteriores del pipeline.