Skip to main content

4.12 Integraci贸n continua

Es muy com煤n que usemos un sistema de control de versiones para mantener los cambios de nuestros proyectos y sus releases de una forma estable y predecible.

Las im谩genes de Docker no son una excepci贸n a esta regla, lo que a su vez nos brinda la oportunidad de hacer uso de los diversos sistemas de integraci贸n continua para automatizar muchas de nuestras tareas como por ejemplo la publicaci贸n de im谩genes en registros p煤blicos o privados, revisi贸n autom谩tica de las dependencias, etc...

Las posibilidades son infinitas, a su vez nos permite una gesti贸n m谩s 贸ptima de los tokens, api keys y secretos que manejamos a nivel de la organizaci贸n, evitando as铆 la necesidad de compartir tokens con personas individuales, facilitando as铆 la rotaci贸n de los mismos.

Veamos unos ejemplos

En esta ocasi贸n usaremos Github Actions, pero f谩cilmente podr铆a portarse a otros sistemas de CI sin mucho esfuerzo.

Imaginemos que tenemos un simple "Hola mundo" en un fichero ./src/server.js y su correspondiente package.json con las dependencias y t铆picos scripts de Npm (start, test, lint...)

const express = require('express')

const app = express()

const PORT = 8080;
const HOST = '0.0.0.0';

app.get('/', (req, res) => {
res.send('Hola mundo!')
})

app.listen(PORT, HOST () => {
console.log('Listening on port ${PORT}}...')
})

Luego hacemos un Dockerfile siguiendo las buenas pr谩cticas (multi-stage, gesti贸n de privilegios, crear una imagen final liviana, metadatos...)

# Fase 1: dependencies

FROM node:14.15.5 as dependencies
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm i --only=production

# Fase 2: Imagen final
FROM node:14.15.5-alpine

# Distribution details.
ARG BUILD_DATE
ARG VCS_REF
ARG BUILD_VERSION

# Labels.
LABEL org.label-schema.schema-version="1.0"
LABEL org.label-schema.build-date=$BUILD_DATE
LABEL org.label-schema.name="ulisesgascon/hello-world-sample"
LABEL org.label-schema.description="Simple Hello World Sample in Nodejs with Express"
LABEL org.label-schema.url="https://github.com/ulisesgascon/hello-world-sample"
LABEL org.label-schema.vcs-url="https://github.com/ulisesgascon/hello-world-sample"
LABEL org.label-schema.vcs-ref=$VCS_REF
LABEL org.label-schema.vendor="Ulises Gascon"
LABEL org.label-schema.version=$BUILD_VERSION
LABEL org.label-schema.docker.cmd="docker run -p 8080:8080 -d ulisesgascon/hello-world-sample"

WORKDIR /app
RUN chown -R node:node /app
USER node
COPY --from=dependencies /usr/src/app/node_modules ./node_modules
COPY package*.json ./
COPY /src ./src
EXPOSE 8080
CMD [ "npm", "start" ]

Revisar los cambios

Un flujo bastante com煤n se producir铆a se crear谩 una nueva pull request. Disparando un workflow que valide espec铆ficamente que nuestro Dockerfile est谩 pasando un linter como Hadolint y que es capaz de hacer una build sin romperse (incluyendo metadatos).

name: Check Dockerfile
on: [pull_request]

jobs:
check-dockerfile:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v2

- name: Get current time
uses: josStorer/get-current-[email protected]
id: current-time

- name: Linting with hadolint
uses: reviewdog/action-hadolint@v1
with:
reporter: github-pr-review

- name: Build the Docker image
env:
RELEASE_VERSION: ${{ steps.vars.outputs.tag }}
BUILD_DATE: ${{ steps.current-time.outputs.time }}
RELEASE_VERSION: "PR${{github.event.number}}"
run: |
docker build .
--build-arg BUILD_DATE=${{ env.BUILD_DATE }}
--build-arg VCS_REF=${{ github.sha }}
--build-arg BUILD_VERSION=${{ env.RELEASE_VERSION }}
--tag ulisesgascon/hello-world-sample:$RELEASE_VERSION
--tag ulisesgascon/hello-world-sample:latest

Publicar en un registro p煤blico

Con unas pocas modificaciones sobre el c贸digo anterior podemos hacer la publicaci贸n de la imagen de manera p煤blica en Docker Hub cuando creamos una release en el proyecto.

name: Publish Docker Image
on: [pull_request]

jobs:
check-dockerfile:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v2

- name: Set RELEASE_VERSION
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV

- name: Get current time
uses: josStorer/get-current-[email protected]
id: current-time

- name: Linting with hadolint
uses: reviewdog/action-hadolint@v1
with:
reporter: github-pr-review

- name: Build the Docker image
env:
RELEASE_VERSION: ${{ steps.vars.outputs.tag }}
BUILD_DATE: "${{ steps.current-time.outputs.time }}"
run: |
docker build .
--build-arg BUILD_DATE=${{ env.BUILD_DATE }}
--build-arg VCS_REF=${{ github.sha }}
--build-arg BUILD_VERSION=${{ env.RELEASE_VERSION }}
--tag ulisesgascon/hello-world-sample:$RELEASE_VERSION
--tag ulisesgascon/hello-world-sample:latest

- name: Docker Hub Login
env:
DOCKER_USER: ${{secrets.DOCKER_USER}}
DOCKER_PASSWORD: ${{secrets.DOCKER_PASSWORD}}
run: |
docker login -u $DOCKER_USER -p $DOCKER_PASSWORD

- name: Docker Hub Publish
run: docker push --all-tags ulisesgascon/hello-world-sample
Informaci贸n

Debemos incluir los secretos que solicitamos en la configuraci贸n del repositorio de Github (DOCKER_USER y DOCKER_PASSWORD para Docker Hub)