Diferencia entre revisiones de «Integración Continua y Despliegue Continuo 21-22»

De Wiki de EGC
Saltar a: navegación, buscar
Línea 4: Línea 4:
 
* [https://videos.us.es/media/P7-+Integraci%C3%B3n+y+Despligue+continuo/1_20jojo0w Vídeo con los prerrequisitos]
 
* [https://videos.us.es/media/P7-+Integraci%C3%B3n+y+Despligue+continuo/1_20jojo0w Vídeo con los prerrequisitos]
 
* El archivo django.yml ha de situarse en la carpeta .github/worklflows y ha de tener este contenido:
 
* El archivo django.yml ha de situarse en la carpeta .github/worklflows y ha de tener este contenido:
<source>
+
<syntaxhighlight lang="YAML">
 
name: Python application
 
name: Python application
  
Línea 56: Línea 56:
 
           heroku_app_name: " <<your app name>>"
 
           heroku_app_name: " <<your app name>>"
 
           heroku_email: " <<your email>>"
 
           heroku_email: " <<your email>>"
</source>
+
</syntaxhighlight>
  
 
= GitHub Actions =
 
= GitHub Actions =
Línea 69: Línea 69:
 
El siguiente workflow tiene como nombre 'GitHub Actions Demo' y se dispara al hacer un push. Únicamente define un job llamado 'Explore-GitHub-Actions' dentro de un runner de tipo ubuntu-latest. Casi todos los pasos son de tipo shell salvo uno que utiliza la acción actions/checkout@v1.
 
El siguiente workflow tiene como nombre 'GitHub Actions Demo' y se dispara al hacer un push. Únicamente define un job llamado 'Explore-GitHub-Actions' dentro de un runner de tipo ubuntu-latest. Casi todos los pasos son de tipo shell salvo uno que utiliza la acción actions/checkout@v1.
  
<source>
+
<syntaxhighlight lang="YAML">
 
name: GitHub Actions Demo
 
name: GitHub Actions Demo
 
on: [push]
 
on: [push]
Línea 89: Línea 89:
 
       - name: Contains expresion in a step
 
       - name: Contains expresion in a step
 
         run: echo "Is this branch master or develop? ${{ contains('refs/heads/master refs/heads/develop',github.ref)}}"
 
         run: echo "Is this branch master or develop? ${{ contains('refs/heads/master refs/heads/develop',github.ref)}}"
</source>
+
</syntaxhighlight>
  
 
Añade un archivo con este contenido a tu proyecto en GitHub y comprueba su estado en la pestaña Actions:
 
Añade un archivo con este contenido a tu proyecto en GitHub y comprueba su estado en la pestaña Actions:
Línea 112: Línea 112:
 
# Crear una incidencia según las [[Gestión de incidencias | recomendaciones vistas en clase]] para el error que obtenemos al votar en heroku.
 
# Crear una incidencia según las [[Gestión de incidencias | recomendaciones vistas en clase]] para el error que obtenemos al votar en heroku.
 
# Asegurarse que la incidencia creada incluye, al menos, un título descriptivo, información de qué es lo que ocurre y cómo puede reproducirse el error.
 
# Asegurarse que la incidencia creada incluye, al menos, un título descriptivo, información de qué es lo que ocurre y cómo puede reproducirse el error.
 +
 +
-------------EJE1------------------------------------------------
 +
[[Página_Principal]] -> [[2021/2022]] -> [[Prácticas - 21/22]] -> [[Integración_Continua_y_Despliegue_Continuo_21-22]]
 +
 +
= Decide con GitHub Actions =
 +
 +
El archivo django.yml ofrecido prepara el entorno, prueba decide, reporta a Codacy y despliega en Heroku. Está compuesto por dos jobs.
 +
 +
En el job "build" se especifica que el servicio de base de datos tendrá que estar disponible en el runner de este job. Se le especifica información de healthchek para verificar que el servicio está correctamente levantado antes de continuar con los pasos del job. Para que este job funcione se tendrá que comprobar que:
 +
# La configuración completa ha de estar en el settings.py. Esto, normalmente, si hemos hecho la práctica de heroku lo tendremos bien.
 +
# Como no se está haciendo uso de local_settings, la configuración de la base de datos escrita en el django.yml deberá coincidir con la que esté puesta en el settings.py.
 +
# Hay un test que puede fallar llamado "test_multiple_auths_mock" dentro del módulo Mixnet. Si falla, debería anularse ese test.
 +
 +
El job "deploy" se lanza sin esperar a que termine build. Para que solo se lance si el job anterior acaba satisfactoriamente añadamos la clausula "need":
 +
<syntaxhighlight lang="YAML">
 +
deploy:
 +
    needs: build
 +
</syntaxhighlight>
 +
 +
Haz un push y observa la ejecución del workflow.
 +
* ¿Se lanzan los dos jobs?
 +
* ¿Está correctamente desplegada la aplicación en Heroku?
 +
 +
-------------EJE2------------------------------------------------
 +
[[Página_Principal]] -> [[2021/2022]] -> [[Prácticas - 21/22]] -> [[Integración_Continua_y_Despliegue_Continuo_21-22]]
 +
 +
= Build matrix en GitHub Actions  =
 +
 +
Al igual que hicimos en travis, podemos indicarle a GitHub que ciertos steps se ejecuten en paralelo. Para ello, hemos de hacer definir una "estrategria" a nivel de job.
 +
Para indicar varias versiones de python a utilizar en el step de "setup-python", incluiremos lo siguiente:
 +
 +
<syntaxhighlight lang="YAML">
 +
build:
 +
    strategy:
 +
      matrix:
 +
        pyversion: ['3.5','3.8']
 +
</syntaxhighlight>
 +
 +
Una vez hecho eso, podremos usar el contexto "matrix" en cualquiera de los steps de este job. En este caso lo usaremos en en el siguiente step:
 +
 +
<syntaxhighlight lang="YAML">
 +
- name: Set up Python ${{matrix.pyversion}}
 +
  uses: actions/setup-python@v1
 +
  with:
 +
    python-version: ${{matrix.pyversion}}
 +
</syntaxhighlight>
 +
 +
Haz un push y observa la ejecución del workflow.
 +
* ¿Cuántos jobs se ejecutan?
 +
* ¿Qué tendríamos que hacer para probar ampliar el build matrix con las versiones de postress 12 y 10.8? ¿Cuántos jobs se ejecutarían?
 +
-------------EJE3------------------------------------------------
 +
[[Página_Principal]] -> [[2021/2022]] -> [[Prácticas - 21/22]] -> [Integración_Continua_y_Despliegue_Continuo_21-22]
 +
 +
= Badge de worflows de GitHub Actions  =
 +
Al igual que hicimos en travis, podemos añadir badges a nuestro README.md relacionados con el estado de un worflow.
 +
Para ello:
 +
# Accede a la pestaña Actions.
 +
# Accede a uno de los Workflows.
 +
# Pulsa el botón ... y genera el badge.
 +
# Incluye el contenido de dicho badge en tu README.MD
 +
 +
Si tienes varios workflows:
 +
* ¿Puede generarse un badge general o tiene que generarse un badge para cada workflow?
 +
 +
--------- EJE4 ----------------------------------
 +
[[Página_Principal]] -> [[2021/2022]] -> [[Prácticas - 21/22]] -> [[Integración_Continua_y_Despliegue_Continuo_21-22]]
 +
 +
= Creación de superusuario de Django desde Action =
 +
 +
Al acceder a nuestra aplicación desplegada en Heroku no tendremos ningún usuario creado.
 +
Para automáticamente crear uno en nuestros despliegues añadamos un step nuevo a nuestro job "deploy".
 +
 +
<syntaxhighlight lang="YAML">
 +
- run: heroku run -a <Heroku app name> sh -c "python decide/manage.py shell -c \"from django.contrib.auth.models import User; User.objects.filter(username='admin') or User.objects.create_superuser('admin', 'admin@example.com', 'admin')\""
 +
</syntaxhighlight>
 +
 +
Haz push y, tras finalizar el workflow, accede a tu aplicación en heroku <app>.herokuapp.com/admin:
 +
* ¿Puede acceder con admin/admin?
 +
-----------EJE5-------------------------------------
 +
[[Página_Principal]] -> [[2021/2022]] -> [[Prácticas - 21/22]] -> [[Integración_Continua_y_Despliegue_Continuo_21-22]]
 +
 +
= Condiciones de jobs/steps en GitHub Actions =
 +
 +
En GitHub Actions, los workflows tienen la capacidad de definir el/los evento/s que los disparan con la clausua "on:".
 +
Puedes ver [[https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#onpushpull_requestbranchestags aquí]] más detalles de dicha cláusula.
 +
Sin embargo eso no se puede especificar a nivel de job o de step. 
 +
A esos niveles pueden expresarse sentencias "if" que permiten ejecutarlas condicionalmente.
 +
Puedes ver [[https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#jobsjob_idstepsif aquí]] más detalles de dicha cláusula.
 +
 +
Para hacer que solo se lance el job "deploy" cuando estemos en una rama concreta, por ejemplo, "master", incluiríamos lo siguiente:
 +
 +
<syntaxhighlight lang="YAML">
 +
deploy:
 +
    if: ${{github.ref == 'refs/heads/master' }}
 +
</syntaxhighlight>
 +
 +
Despues de hacer un push del django.yml, haz un push a otra rama.
 +
* ¿Se lanza el workflow?
 +
* ¿Se lanza el job "deploy"? ¿En que estado se queda?
 +
 +
 +
Modifica la clausula "on:" para que se lance el workflow solo cuando se hiciera push a la rama master.
 +
Despues de hacer un push del django.yml, haz un push a otra rama.
 +
* ¿Se lanza el workflow?
 +
 +
---------- EJE6 ----------------------------
 +
[[Página_Principal]] -> [[2021/2022]] -> [[Prácticas - 21/22]] -> [[Integración_Continua_y_Despliegue_Continuo_21-22]]
 +
 +
= Reutilización de workflows y creación de releases =
 +
 +
En GitHub puede hacerse crearse una Release de un repositorio en https://github.com/<tu org>/<tu repo>/releases.
 +
Para automatizar el proceso de generación de una release a partir de un tag (siempre y cuando dicho código haya pasado las pruebas) podemos combinar el workflow django.yml con un pasos posterior de release. Para ello:
 +
 +
# Cree un nuevo workflow en la carpeta de los workflows con el siguiente contenido:
 +
<syntaxhighlight lang="YAML">
 +
name: release
 +
 +
on:
 +
  push:
 +
    tags:
 +
      - '*'
 +
 +
jobs:
 +
  buildTest:
 +
    uses: <tu org>/<tu repo>/.github/workflows/django.yml@master
 +
    secrets:
 +
      CODACY_PROJECT_TOKEN: ${{secrets.CODACY_PROJECT_TOKEN}}
 +
      HEROKU_API_KEY: ${{secrets.HEROKU_API_KEY}}
 +
 +
  release:
 +
    needs: buildTest
 +
    runs-on: ubuntu-latest
 +
    steps:
 +
      - name: Checkout
 +
        uses: actions/checkout@v2
 +
      - name: Release
 +
        uses: softprops/action-gh-release@v1
 +
</syntaxhighlight>
 +
# Dado que las variables de entorno y secrets no se comparten entre workflows, hay que pasarlos explicitamente de un worflow al workflow reutilizable. Para convertir el workflow django.yml en reutilizable tenemos que modifcarlo añadiendo:
 +
<syntaxhighlight lang="YAML">
 +
...
 +
on:
 +
  push:
 +
    branches:
 +
  - master
 +
  workflow_call:
 +
    secrets:
 +
      CODACY_PROJECT_TOKEN:
 +
        required: true
 +
      HEROKU_API_KEY:
 +
...
 +
</syntaxhighlight>
 +
 +
Hagamos un push de los cambios.
 +
* ¿Cuántos workflows se dispara?
 +
* ¿Se observa algún comportamiento diferente en el workflow django.yml?
 +
 +
Para crear un nuevo tag hagamos:
 +
<syntaxhighlight language="bash">
 +
git tag -a v1.0.0 -m “mensaje para añadir al tag que también aparecerá en la release”
 +
git push origin v1.0.
 +
</syntaxhighlight>
 +
 +
* ¿Cuántos workflows se lanzan?
 +
* ¿Cuántos jobs se ejecutan del nuevo worflow?
 +
* ¿Se crea correctamente la release?

Revisión del 12:45 14 dic 2021

Página_Principal -> 2021/2022 -> Prácticas - 21/22

Prerrequisitos

name: Python application

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest

    services:
      postgres:
        image: postgres:10.8
        env:
          POSTGRES_USER: decide
          POSTGRES_PASSWORD: decide
          POSTGRES_DB: decide
        ports:
          - 5432:5432
        # needed because the postgres container does not provide a healthcheck
        options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5

    steps:
    - uses: actions/checkout@v1
    - name: Set up Python 3.8
      uses: actions/setup-python@v1
      with:
        python-version: 3.8
    - name: psycopg2 prerequisites
      run: sudo apt-get install libpq-dev
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
        pip install codacy-coverage
    - name: Run migrations
      run: cd decide;python manage.py migrate
    - name: Run tests     
      run: cd decide;coverage run --branch --source=. ./manage.py test census --keepdb; coverage xml;
    - name: Codacy Coverage Reporter
      uses: codacy/codacy-coverage-reporter-action@v1.1.0
      with:
          project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
          coverage-reports: decide/coverage.xml
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - uses: akhileshns/heroku-deploy@v3.12.12 # This is the action
      with:
          heroku_api_key: ${{secrets.HEROKU_API_KEY}}
          heroku_app_name: " <<your app name>>"
          heroku_email: " <<your email>>"

GitHub Actions

Nociones básicas sobre GitHub Actions

Dentro de cada .yml de la carpeta .github/worflows se define un:

  1. workflow el cuál se dispara al recibir un evento de GitHub.
  2. Estos eventos puede ser desde un push hasta la creación de una issue. Cada workflow permite correr jobs.
  3. Los 'jobs son secuencias de pasos. Cada uno de estos jobs se ejecutan dentro de un entorno llamado runner.
  4. Los runners son máquinas virtuales que se levantan para cada job. Todos los pasos de un job se ejecutan dentro del mismo runner, por lo que comparten recursos como los archivos y las carpetas.
  5. Los pasos de un job pueden ser simples instrucciones de shell, o utilizar funciones más concretas llamadas actions como, por ejemplo, hacer un clone.

El siguiente workflow tiene como nombre 'GitHub Actions Demo' y se dispara al hacer un push. Únicamente define un job llamado 'Explore-GitHub-Actions' dentro de un runner de tipo ubuntu-latest. Casi todos los pasos son de tipo shell salvo uno que utiliza la acción actions/checkout@v1.

name: GitHub Actions Demo
on: [push]
jobs:
  Explore-GitHub-Actions:
    runs-on: ubuntu-latest
    steps:
      - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
      - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!"
      - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."
      - name: Check out repository code
        uses: actions/checkout@v1
      - run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
      - run: echo "🖥️  The workflow is now ready to test your code on the runner."
      - name: List files in the repository
        run: |
          ls ${{ github.workspace }}
      - run: echo "🍏 This job's status is ${{ job.status }}."
      - name: Contains expresion in a step
        run: echo "Is this branch master or develop? ${{ contains('refs/heads/master refs/heads/develop',github.ref)}}"

Añade un archivo con este contenido a tu proyecto en GitHub y comprueba su estado en la pestaña Actions:

  • ¿Cuántos Worflows, jobs, steps se lanzan?
  • ¿Entiendes todo lo que hacen las expresiones ${{ <expresion> }}?

Para consultar la lista completa de expressiones, visita este [link].

Para consultar la lista completa de contextos (e.g., github.<>, job.<> o runner.<>), visita este otro [link].

Para consultar la lista completa de acciones, visita el [link].

Ejercicios de build

Ejercicios de deploy

Ejercicio de gestión de incidencias

  1. Al probar la app desplega en Heroku vemos un comportamiento anómalo.
  2. Crear una incidencia según las recomendaciones vistas en clase para el error que obtenemos al votar en heroku.
  3. Asegurarse que la incidencia creada incluye, al menos, un título descriptivo, información de qué es lo que ocurre y cómo puede reproducirse el error.

EJE1------------------------------------------------

Página_Principal -> 2021/2022 -> Prácticas - 21/22 -> Integración_Continua_y_Despliegue_Continuo_21-22

Decide con GitHub Actions

El archivo django.yml ofrecido prepara el entorno, prueba decide, reporta a Codacy y despliega en Heroku. Está compuesto por dos jobs.

En el job "build" se especifica que el servicio de base de datos tendrá que estar disponible en el runner de este job. Se le especifica información de healthchek para verificar que el servicio está correctamente levantado antes de continuar con los pasos del job. Para que este job funcione se tendrá que comprobar que:

  1. La configuración completa ha de estar en el settings.py. Esto, normalmente, si hemos hecho la práctica de heroku lo tendremos bien.
  2. Como no se está haciendo uso de local_settings, la configuración de la base de datos escrita en el django.yml deberá coincidir con la que esté puesta en el settings.py.
  3. Hay un test que puede fallar llamado "test_multiple_auths_mock" dentro del módulo Mixnet. Si falla, debería anularse ese test.

El job "deploy" se lanza sin esperar a que termine build. Para que solo se lance si el job anterior acaba satisfactoriamente añadamos la clausula "need":

deploy:
    needs: build

Haz un push y observa la ejecución del workflow.

  • ¿Se lanzan los dos jobs?
  • ¿Está correctamente desplegada la aplicación en Heroku?

EJE2------------------------------------------------

Página_Principal -> 2021/2022 -> Prácticas - 21/22 -> Integración_Continua_y_Despliegue_Continuo_21-22

Build matrix en GitHub Actions

Al igual que hicimos en travis, podemos indicarle a GitHub que ciertos steps se ejecuten en paralelo. Para ello, hemos de hacer definir una "estrategria" a nivel de job. Para indicar varias versiones de python a utilizar en el step de "setup-python", incluiremos lo siguiente:

build:
    strategy:
      matrix:
        pyversion: ['3.5','3.8']

Una vez hecho eso, podremos usar el contexto "matrix" en cualquiera de los steps de este job. En este caso lo usaremos en en el siguiente step:

- name: Set up Python ${{matrix.pyversion}}
  uses: actions/setup-python@v1
  with:
    python-version: ${{matrix.pyversion}}

Haz un push y observa la ejecución del workflow.

  • ¿Cuántos jobs se ejecutan?
  • ¿Qué tendríamos que hacer para probar ampliar el build matrix con las versiones de postress 12 y 10.8? ¿Cuántos jobs se ejecutarían?

EJE3------------------------------------------------

Página_Principal -> 2021/2022 -> Prácticas - 21/22 -> [Integración_Continua_y_Despliegue_Continuo_21-22]

Badge de worflows de GitHub Actions

Al igual que hicimos en travis, podemos añadir badges a nuestro README.md relacionados con el estado de un worflow. Para ello:

  1. Accede a la pestaña Actions.
  2. Accede a uno de los Workflows.
  3. Pulsa el botón ... y genera el badge.
  4. Incluye el contenido de dicho badge en tu README.MD

Si tienes varios workflows:

  • ¿Puede generarse un badge general o tiene que generarse un badge para cada workflow?

EJE4 ----------------------------------

Página_Principal -> 2021/2022 -> Prácticas - 21/22 -> Integración_Continua_y_Despliegue_Continuo_21-22

Creación de superusuario de Django desde Action

Al acceder a nuestra aplicación desplegada en Heroku no tendremos ningún usuario creado. Para automáticamente crear uno en nuestros despliegues añadamos un step nuevo a nuestro job "deploy".

- run: heroku run -a <Heroku app name> sh -c "python decide/manage.py shell -c \"from django.contrib.auth.models import User; User.objects.filter(username='admin') or User.objects.create_superuser('admin', 'admin@example.com', 'admin')\""

Haz push y, tras finalizar el workflow, accede a tu aplicación en heroku <app>.herokuapp.com/admin:

  • ¿Puede acceder con admin/admin?

EJE5-------------------------------------

Página_Principal -> 2021/2022 -> Prácticas - 21/22 -> Integración_Continua_y_Despliegue_Continuo_21-22

Condiciones de jobs/steps en GitHub Actions

En GitHub Actions, los workflows tienen la capacidad de definir el/los evento/s que los disparan con la clausua "on:". Puedes ver [aquí] más detalles de dicha cláusula. Sin embargo eso no se puede especificar a nivel de job o de step. A esos niveles pueden expresarse sentencias "if" que permiten ejecutarlas condicionalmente. Puedes ver [aquí] más detalles de dicha cláusula.

Para hacer que solo se lance el job "deploy" cuando estemos en una rama concreta, por ejemplo, "master", incluiríamos lo siguiente:

deploy:
    if: ${{github.ref == 'refs/heads/master' }}

Despues de hacer un push del django.yml, haz un push a otra rama.

  • ¿Se lanza el workflow?
  • ¿Se lanza el job "deploy"? ¿En que estado se queda?


Modifica la clausula "on:" para que se lance el workflow solo cuando se hiciera push a la rama master. Despues de hacer un push del django.yml, haz un push a otra rama.

  • ¿Se lanza el workflow?

EJE6 ----------------------------

Página_Principal -> 2021/2022 -> Prácticas - 21/22 -> Integración_Continua_y_Despliegue_Continuo_21-22

Reutilización de workflows y creación de releases

En GitHub puede hacerse crearse una Release de un repositorio en https://github.com/<tu org>/<tu repo>/releases. Para automatizar el proceso de generación de una release a partir de un tag (siempre y cuando dicho código haya pasado las pruebas) podemos combinar el workflow django.yml con un pasos posterior de release. Para ello:

  1. Cree un nuevo workflow en la carpeta de los workflows con el siguiente contenido:
name: release

on:
  push: 
    tags:
      - '*'

jobs:
  buildTest:
    uses: <tu org>/<tu repo>/.github/workflows/django.yml@master
    secrets: 
      CODACY_PROJECT_TOKEN: ${{secrets.CODACY_PROJECT_TOKEN}}
      HEROKU_API_KEY: ${{secrets.HEROKU_API_KEY}}

  release:
    needs: buildTest
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Release
        uses: softprops/action-gh-release@v1
  1. Dado que las variables de entorno y secrets no se comparten entre workflows, hay que pasarlos explicitamente de un worflow al workflow reutilizable. Para convertir el workflow django.yml en reutilizable tenemos que modifcarlo añadiendo:
...
on:
  push:
     branches:
	   - master
  workflow_call:
    secrets:
      CODACY_PROJECT_TOKEN:
        required: true
      HEROKU_API_KEY:
...

Hagamos un push de los cambios.

  • ¿Cuántos workflows se dispara?
  • ¿Se observa algún comportamiento diferente en el workflow django.yml?

Para crear un nuevo tag hagamos:

git tag -a v1.0.0 -m “mensaje para añadir al tag que también aparecerá en la release”
git push origin v1.0.
  • ¿Cuántos workflows se lanzan?
  • ¿Cuántos jobs se ejecutan del nuevo worflow?
  • ¿Se crea correctamente la release?