CI/CD con Github Actions y Docker

Si alguna escuchaste el termino de DevOps y aun no conoces como puede impactar de manera positiva tu proceso de desarrollo especialmente si trabajas para una pequeña empresa o tienes tu propia empresa de desarrollo. Déjame te explico que es un flujo de DevOps y como esto puede facilitar tus procesos internos o de tu empresa, al finalizar este tutorial podrás implementar un flujo sencillo utilizando Docker, Docker Hub y Github Actions para poder automatizar tu proceso de publicación por medio de un flujo CI/CD (Integración y distribución continua)

¿Qué es CI/CD y en que me beneficia?

El CI/CD o Integración y distribución continua permite que puedas desarrollar nuevas funcionalidades de tu aplicación y distribuirlas de forma continua e inmediata, si estas familiarizado con los métodos convencionales de publicar aplicaciones a producción sabrás de lo que estoy hablando, ¿Qué pasaría si de alguna manera existiera algo que se encargara de publicar nuestro código a producción sin que nosotros levantemos un solo dedo? Afortunadamente para todos nosotros aquí es donde entra Github Actions.

¿Qué es Github Actions?

Github Actions son acciones que pueden correr sobre tus repositorios que nos permite realizar flujos de trabajo de manera automática al momento de realizar una acción dentro del repositorio de Github, como por ejemplo correr una prueba rápida cada vez que haga un commit a mi rama de desarrollo. ¿Vez por donde va esto? ¡Exacto! Si seguimos la misma lógica podríamos crear un flujo de trabajo que publique nuestro código en producción cuando realizo un commit en mi rama principal, y eso es exactamente lo que aprenderemos a realizar el día de hoy. Así que acompáñame en este pequeño tutorial para crear un flujo atreves de Github para publicar tu código a producción, pero no te quedes únicamente con esto, Github Action permite una infinidad de posibilidades e implementación para que puedas construir y personalizar tus propios flujos.

Antes de iniciar

Para poder completar este tutorial necesitaras un servidor con Docker y Docker Compose instalado, si no cuentas con uno puedes adquirirlo en Digital Ocean, también necesitaras un repositorio de Github, conocimientos básicos de Docker y una cuenta de Docker Hub, esta ultima es totalmente opcional si deseas utilizar imágenes públicas, como por ejemplo WordPress y MySQL.

Primer Paso: configuración de Github

Antes de iniciar con nuestro flujo de trabajo, crearemos nuestro repositorio y nos iremos a la sección de Actions en la parte superior de nuestro repositorio. Acá tendremos a disposición varios flujos creados que podemos utilizar como plantilla, pero en nuestro caso que haremos un flujo personalizado presionaremos en la opción de ¨Configure un flujo de trabajo usted mismo¨ esto nos abrirá un archivo de YAML.
Github Actions utiliza un archivo. yml al igual que Docker Compose para poder seguir las instrucciones de ejecución paso por paso. Sabiendo esto nos enfocaremos en cada área de nuestro flujo, recuerda que nuestro flujo contempla crear una imagen de Docker subirla a Docker Hub y desplegarla en nuestro servidor de producción.
Como primer paso configuraremos nuestro archivo de YAML para que se ejecute nuestra acción al momento de hacer un commit a nuestra rama Master, esto lo haremos de la siguiente manera:
name: Crear Imagen y publicarla
on:
  push:
    branches: [ master ]

Luego nos enfocaremos en lo siguiente, necesitamos que Github Cree nuestra imagen de Docker, la suba a nuestra cuenta de Docker Hub para luego poder instalarla en nuestro servidor de producción. Si seguimos los pasos necesitaremos dos partes en nuestro flujo, Crear y Publicar. Esto lo lograremos con la función de Jobs, donde le podemos especificar a nuestro archivo de YAML que tiene que realizar varios trabajos uno tras otro o en paralelo.

Como segundo paso crearemos nuestro “Job” para crear nuestra imagen y lo nombraremos publish, tambien vamos a especificar que correra en una instancia de Ubuntu.
jobs:
  publish:
    runs-on: ubuntu-latest
Luego agregaremos los pasos a ejecutar, primero utilizaremos algunas librerías para poder copiar nuestro código a la instancia de Ubuntu y poder ingresar a nuestra cuenta de Docker Hub.
 steps:
    - name: Checkout
      uses: actions/checkout@v2
      
    - name: Login to DockerHub
      uses: docker/login-action@v1 
      with:
          username: ${{ secrets.DOCKER_USER }}
          password: ${{ secrets.DOCKER_PASSWORD }}
          logout: true
Por último, vamos a crear nuestra imagen de Docker por medio de nuestro Docker File y vamos a subirla a nuestra cuenta de Docker Hub.
    - name: Extract metadata (tags, labels) for Docker
      id: meta
      uses: docker/metadata-action@v3
      with:
          images: ejemplo/docker-image
          
    - name: Build and push
      id: docker_build
      uses: docker/build-push-action@v2
      with:
          context: .
          file: ./Dockerfile
          push: true
          tags: ejemplo/docker-image:latest
Como segundo paso vamos a necesitar crear nuestro Job que publique automáticamente nuestra imagen en nuestro servidor de producción, para esto tendremos que crear un Self Hosted Runner, esto lo que hace es decirle a Github que esta parte de nuestra acción va a correr en nuestros servidores. Exploraremos a mas detalle los Self Hosted Runners mas adelante en el tutorial.
Procederemos a crear nuestro “Job” para descargar nuestra imagen en nuestro propio servidor de manera automática, a este “Job” lo nombraremos deploy.
deploy: 
    runs-on: self-hosted
    needs: publish
Luego agregaremos los pasos para ejecutar dentro de nuestra acción, dentro de estos pasos vamos a agregar, para el contenedor existente y remover la imagen antes de cualquier cosa, luego vamos a ingresar a nuestra cuenta de Docker Hub y descargar la nueva imagen y por último ejecutaremos el comando para poder crearla, en nuestro caso lo haremos atreves de Docker Compose.
steps: 
      - name: Clean Container
        run: |
          docker stop container || true
          docker rm container || true
         
      - name: Copy Files Over
        uses: actions/checkout@v2
        
      - name: Login To Docker Hub
        run: echo "${{secrets.DOCKER_PASSWORD}}" | docker login -u "${{secrets.DOCKER_USER}}" --password-stdin
          
      - name: Pull New Image
        run: docker pull ejemplo/docker-image:latest
        
      - name: Compose
        run: docker-compose up -d
¡Listo! Terminamos con nuestro archivo que define nuestro flujo de acciones, ahora nos toca configurar nuestro servidor.

Segundo Paso: configuración de nuestro servidor

Antes de iniciar debemos revisar que Docker y Docker Compose se encuentren instalados en nuestro servidor, de lo contrario debemos de instalarlos. Podemos revisar ambos con los siguientes comandos:
docker --version
docker-compose -v
Al corroborar que tengamos ambos componentes instalados, procederemos a crear un usuario ya que Github Actions por seguridad no correrá en nuestro usuario root. Para esto seguiremos el siguiente comando:
sudo adduser newuser
Luego le daremos permisos de sudo a nuestro usuario con el siguiente comando:
usermod -aG sudo newuser
Luego le agregaremos nuestro nuevo usuario al grupo de Docker con el siguiente comando:
usermod -aG docker newuser
¡Listo! Por el momento hemos terminado con nuestra configuración del servidor de producción.

Tercer Paso: configuración del Self Hosted Runner

Antes de poder ver nuestra creación operar, necesitamos hacer un ultimo paso, decirle a Github cual será nuestro servidor de producción para que pueda correr la segunda parte de nuestra acción dentro de este servidor. A continuación, vamos a crear nuestro Self-Hosted Runner y configurarlo para poder ejecutar nuestra acción.
Primero iremos dentro de nuestro repositorio a las configuraciones, luego a la opción de Actions y por último a la opción de Runners, acá presionaremos el botón verde para crear un nuevo Runner.
Para crear correctamente nuestro Runner debemos de seleccionar primero Ubuntu y luego iremos a nuestro servidor, recuerda que las acciones no correrán sobre el usuario root así que primero tienes que ingresar en el usuario que creamos con anterioridad y luego ya puedes seguir los pasos que brinda Github para poder crear el nuevo Runner, podemos cambiar a nuestro nuevo usuario con el siguiente comando:
sudo su - newuser
Tras haber seguido los pasos que Github nos brinda para crear nuestro runner finalizaremos iniciando el runner con el siguiente comando:
./run.sh
¡Listo! Ahora solo nos queda realizar un commit en nuestra rama Master y ver como la acción replica nuestro contenedor automáticamente.

Pasos adicionales

En conclusión, hemos logrado crear un pequeño flujo dentro de nuestro repositorio y así decirle adiós al proceso de publicación de aplicación en producción. Github action nos brinda muchas más opciones así que te invito a agregar mas pasos y crear acciones para realizar Unit Testing en tu aplicación antes de ser publicada ¡El cielo es el límite!
sudo ./svc.sh install

Conclusión

En conclusión, hemos logrado crear un pequeño flujo dentro de nuestro repositorio y así decirle adiós al proceso de publicación de aplicación en producción. Github action nos brinda muchas más opciones así que te invito a agregar mas pasos y crear acciones para realizar Unit Testing en tu aplicación antes de ser publicada ¡El cielo es el límite!

Leave a Comment

Scroll to Top