Commit dac22920 authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Initial commit

parents
Pipeline #1934 passed with stage
in 29 seconds
dist/
*.pdf
pages:
stage: deploy
tags:
- docker
image: node:15
script:
- npm install -g reveal-md
- reveal-md slides.md --theme white --css style.css --title "Introduzione a GitLab CI" --static public
artifacts:
paths:
- public
# Introduzione a GitLab CI
Sonia Zorba
---
### DevOps?
[https://www.ict.inaf.it/gitlab](https://www.ict.inaf.it/gitlab)
![gitlab-home](img/gitlab-home.jpg)
DevOps = Development + Operations
---
### "Oldschool" Operations
Seguo "la guida scritta dal collega" per installare la sua applicazione sul server di produzione:
> * installare pacchetto X
> * copiare file Y in /usr/local/pippo
> * commentare riga Z nel file di configurazione
> * ...
---
### Problemi
* ripetitivo
* time consuming
* error prone
* la guida va mantenuta costantemente aggiornata
---
### Soluzione
Sostituisco la guida con un processo automatico:
![deploy-job](img/deploy-job.jpg)
---
### CI/CD
Associare delle operazioni automatiche ad alcuni "eventi" di un repository (es: push, merge).
* CI: Continuous Integration
* CD:
* Continuous Delivery
* Continuous Deployment
---
### Pipeline CI/CD
Insieme di job eseguiti in degli stage (stadi):
![pipeline](img/pipeline.jpg)
---
### Esempio 1
[https://www.ict.inaf.it/gitlab/ci-intro/coords-library](https://www.ict.inaf.it/gitlab/ci-intro/coords-library)
Release di un pacchetto Python che usa Astropy per calcolare delle coordinate
----
### Modulo Python di esempio
```txt
python3
```
```txt
>>> import coords
>>> coords.get_coords('m31', 'lbt')
{'alt': '47d 13m 43.8866s', 'az': '62d 25m 55.5019s'}
>>> coords.get_coords('m31', 'ekar')
{'alt': '41d 59m 31.3084s', 'az': '290d 28m 01.2741s'}
>>> coords.get_location_name('ekar')
'Mt. Ekar 182 cm. Telescope'
```
---
### Obiettivo 1
Definire una pipeline che:
* testi il nostro modulo Python
* crei un pacchetto distribuibile (in modo che chiunque possa installarla con pip).
---
### Ci serve un Runner
Runner = Esecutore di job
Richiede l'installazione del pacchetto `gitlab-runner` su una macchina dedicata.
Disponibili pacchetti installabili con apt-get, yum e simili.
----
### GitLab Runner
Settings -> CI/CD -> Runners
![runner](img/runner1.jpg)
----
### Runner registration (shell executor)
sudo gitlab-runner register
```txt
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
https://www.ict.inaf.it/gitlab/
Please enter the gitlab-ci token for this runner:
XXXXXXX
Please enter the gitlab-ci description for this runner:
[server.ia2.inaf.it]: CI Intro Shell Runner
Please enter the gitlab-ci tags for this runner (comma separated):
intro-shell
Registering runner... succeeded runner=_TxB1qbX
Please enter the executor: docker+machine, kubernetes, parallels, ssh, docker-ssh, shell, virtualbox, docker-ssh+machine, custom, docker:
shell
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
```
----
### Configurazione della pipeline su GitLab
Si aggiunge un file .gitlab-ci.yml nella root del repository:
```yaml
test_job:
stage: test
tags: # associano runner e job
- intro-shell
script:
- python3 -m venv venv
- source ./venv/bin/activate
- python3 -m pip install -r requirements.txt
- python3 -m unittest tests/coords_test.py
```
[Keyword reference](https://docs.gitlab.com/ee/ci/yaml/)
----
### Risultato dell'esecuzione
![job1](img/job1.jpg)
----
### Problema
Se aggiorniamo le dipendenze all'ultima versione di astropy...
![job2](img/job2.jpg)
Soluzione: far girare il job dentro un container Docker
----
### Runner registration (Docker executor)
```txt
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
https://www.ict.inaf.it/gitlab/
Please enter the gitlab-ci token for this runner:
XXXXXXX
Please enter the gitlab-ci description for this runner:
[server.ia2.inaf.it]: CI Intro Docker Runner
Please enter the gitlab-ci tags for this runner (comma separated):
intro-docker
Registering runner... succeeded runner=RzFiuF97
Please enter the executor: custom, docker, ssh, virtualbox, docker+machine, docker-ssh, parallels, shell, docker-ssh+machine, kubernetes:
docker
Please enter the default Docker image (e.g. ruby:2.6):
python:3.9-buster
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
```
----
### Aggiorniamo la configurazione
```yaml
test_job:
stage: test
tags:
- intro-docker
script:
- pip install -r requirements.txt
- python -m unittest tests/coords_test.py
```
---
### Creiamo un pacchetto distribuibile
GitLab ha un Package Registry interno che supporta vari linguaggi e vari tipi di pacchetti (Composer, Maven, npm, PyPI, Ruby gems, ...).
PyPI: [https://docs.gitlab.com/ee/user/packages/pypi_repository](https://docs.gitlab.com/ee/user/packages/pypi_repository)
----
### Configurazione per PyPI
```yaml
deploy_job:
stage: deploy
tags:
- intro-docker
script:
- pip install twine
- python setup.py sdist bdist_wheel
- TWINE_PASSWORD=${CI_JOB_TOKEN} TWINE_USERNAME=gitlab-ci-token python -m twine upload --repository-url https://www.ict.inaf.it/gitlab/api/v4/projects/${CI_PROJECT_ID}/packages/pypi dist/*
```
[Predefined variables reference](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html)
----
### Pacchetto rilasciato
![Pacchetto PyPI](img/pypi-package.jpg)
Il pacchetto è disponibile nel
[Package Registry di GitLab](https://www.ict.inaf.it/gitlab/ci-intro/coords-library/-/packages).
---
### Esempio 2
[https://www.ict.inaf.it/gitlab/ci-intro/coords-service](https://www.ict.inaf.it/gitlab/ci-intro/coords-service)
Un servizio web che usa la libreria del primo esempio.
----
### Servizio web di esempio
python3 server.py 8080 lbt
![pipeline](img/demo-app-lbt.jpg)
python3 server.py 8081 ekar
![pipeline](img/demo-app-ekar.jpg)
---
### Obiettivo 2
Definire una pipeline che:
* crei un'immagine Docker del servizio che usa la nostra libreria
* faccia il deploy del servizio
----
### Creazione immagine Docker
```yaml
dockerize:
stage: build
tags:
- intro-shell
script:
- docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}"
- docker build -t "${CI_REGISTRY_IMAGE}" --no-cache .
- docker push "${CI_REGISTRY_IMAGE}"
```
**Nota**: l'opzione `--no-cache` servirà per questo esempio specifico ma in genere **non** va utilizzata.
L'immagine è disponibile nel
[Container Registry di GitLab](https://www.ict.inaf.it/gitlab/ci-intro/coords-service/container_registry)
----
### Usiamo l'immagine
Container sulla porta 8080 che visualizza le coordinate per "Large Binocular Telescope":
docker run -it -p 8080:8000 git.ia2.inaf.it:5050/ci-intro/coords-service 8000 lbt
Container sulla porta 8081 che visualizza le coordinate per "Mt. Ekar 182 cm. Telescope":
docker run -it -p 8081:8000 git.ia2.inaf.it:5050/ci-intro/coords-service 8000 ekar
----
### Configurazione variabili CI/CD
Settings -> CI/CD -> Variables
![variabili](img/variabili-ci.jpg)
----
### Job per il deploy
```yaml
deploy_staging:
stage: deploy
tags:
- shell-staging
when: manual
script:
- docker stop coords-service || true
- docker rm coords-service || true
- docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}"
- docker pull git.ia2.inaf.it:5050/ci-intro/coords-service
- docker run -d -p 9999:8000 --name coords-service git.ia2.inaf.it:5050/ci-intro/coords-service 8000 $location_id
```
---
### Rules
Permettono di eseguire un job in maniera condizionale.
Vengono valutate in sequenza finché non viene trovata una regola valida. Il risultato dipende anche dai valori dell'opzione `when` (se presente).
**Nota**: sostituiscono la vecchia sintassi `only`/`except`.
---
### Semplice regola per twine
**Problema**: twine (utility per i pacchetti PyPI) non permette di sovrascrivere un pacchetto già rilasciato.
**Soluzione**: associamo una regola al job in modo che parta solo quando viene rilevato un nuovo tag (release)
```yaml
rules:
- if: $CI_COMMIT_TAG
```
---
### Multi-project pipelines
Quando aggiorno coords-library posso far aggiornare automaticamente anche coords-service:
```yaml
update_service:
stage: .post
trigger:
project: ci-intro/coords-service
rules:
- if: $CI_COMMIT_TAG
```
----
### Spiegazione di --no-cache
Abbiamo usato `--no-cache` per fare la build dell'immagine Docker perché dentro il file requirements.txt specifichiamo coordslib senza versione. Docker non ha modo di sapere che c'è una nuova versione disponibile e se esiste già un'immagine in cache usa quella, saltando la build.
Soluzione migliore ma più complessa: passare il numero di versione ai job.
---
### Job artifacts
File e cartelle generate come output da un job vengono detti artefatti. È possibile specificare i path di alcuni artefatti che saranno poi disponibili per il download e accessibili ai job degli stadi successivi (vedi anche keyword `dependencies`):
```yaml
generate_pdf_job:
script: latex paper.tex
artifacts:
paths:
- paper.pdf
```
---
### Ereditarietà tra job
* Definisco un job il cui nome inizia per "." (hidden job: non viene mai eseguito)
* Uso la keyword `extends` per ereditare dall'hidden job
Alternativa: YAML anchors (costrutto intrinseco a YAML), che però non funzionano tra file diversi
----
### Altre feature interessanti
* **Dynamic child pipelines** (pipeline generate): definisco un job che genera un file YAML che definisce una nuova pipeline che viene poi eseguita da un job successivo.
* **Parallel matrix jobs**: esegue in parallelo lo stesso job usando ogni volta un insieme di variabili diverse
---
### Utilizzo in IA2
* CI configurata per circa 30 repository
* Utilizzo di Docker Compose per il deploy in staging
* Utilizzo di Ansible per il deploy in produzione
[Technical Report su DevOps in IA2](http://hdl.handle.net/20.500.12386/30951)
---
# Domande?
.reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6 {
text-transform: none;
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment