Zobaczmy dzisiaj jak zbudować prosty Continuous Deployment i pracować z platformami w chmurze na przykładzie Heroku:
flowchart LR
Dev(Programista\nTester\nSystem Eng) -- git\npush --> Github(Repozytorium\nGithub) -- wyzwala --> GAction(Automatycznie:\n1. linter\n2. testy\n3. buduje pakiet\n<b>4. Deployment</b>) -- deployment --> Heroku(<b>Heroku</b>\nPaaS)
W drugiej części poznamy Gitlaba oraz wciąż popularnego Jenkinsa.
W czasie tego ćwiczenia, będziemy korzystali z kodu źródłowego z ostatnich zajęć (aplikacja se_hello_world
.
Proszę zweryfikować, że wszystko działa. Wykorzystaj Makefile
oraz wskazówki w README.md
.
Pamiętaj o wirtualnym środowisku Pythona.
W tym ćwiczeniu pokażemy, jak możemy wykorzystać platformę typu PaaS do hostowania naszej aplikacji. Budżet jest, terminy gonią, decydujemy się na platformę PaaS – heroku.
Flask ma wbudowany serwer WWW, ale, w domyślnej konfiguracji, ten serwer może obsłużyć tylko jedno żądanie. Dlatego w naszym przykładzie wykorzystamy gunicorn.
-
Załóż konto na heroku.com
-
Zainstalujmy
gunicorn
:# dodaj jako ostatnią linie # mozesz to zrobic rownie dobrze w Atomie echo 'gunicorn' >> requirements.txt pip install -r requirements.txt
Sprawdźmy czy działa:
# uruchom aplikację za pomocą gunicorna PYTHONPATH=$PYTHONPATH:$(pwd) gunicorn hello_world:app # w drugim oknie terminala curl 127.0.0.1:8000
-
Będziemy korzystać z PaaS - Heroku, musimy poinformować jak nasza aplikacja powinna być uruchomiona. Służy do tego plik
Procfile
. Utwórz plik Procfile o następującej treśći:web: gunicorn hello_world:app
Jeśli chcesz się dowiedzieć więcej, skorzystaj z dokumentacji.
-
A czy jest możliwość przetestowania lokalnie? Jest - Heroku CLI. Zainstaluj to narzędzie, korzystając z instrukcji (wskazówka: wykorzystaj
snap
). -
Teraz z pomocą Heroku CLI, możemy sprawdzić czy komenda w
Procfile
jest poprawna:# w jednym oknie terminala heroku local # w drugim oknie terminala curl 127.0.0.1:5000
-
Umieśćmy aplikację na platformie Heroku, zanim to zrobisz wrzuć wszystkie pliki na githuba:
# sprawdź czy Procfile # i requirements.txt jest dodany git status
# zaloguj sie do heroku heroku login -i # poinformuj Heroku # ze masz nowa aplikacje heroku create # aplikacja pojawi się w heroku dashboard po odświeżeniu przeglądarki internetowej. # zauważ # heroku uzywa gita git remote -v # sprawdz czy nie zapomnialas/es # o Procfile i requirements.txt git status # deploy git push heroku master # sprawdz logi heroku logs
Ilustracja jak lokale repozytorium git jest podłączone do githuba i heroku (
git remote -v
):flowchart BT l(local\ngit) -- master --> H(remote\nheroku) l -- master --> G(remote\ngithub)
Czyli jeśli chcesz umieścić zmiany w:
# github to: git push # a heroku to: git push heroku master
-
Otwórz swoja aplikację z interfejsu webowego Heroku. URl znajdziesz również w logach Heroku (
heroku logs
). -
Ciekawostka. Heroku to PaaS, który upraszcza wiele aspektów obsługi aplikacji na przykład skalowanie. Na Heroku to jedna komenda:
# zeskalujmy do zera # nasza aplikacja nie bedzie dzialac heroku ps:scale web=0 # spowrotem do 1 # z kartą kredytową moglibysmy # skalowac ile budzet by nam pozwolil heroku ps:scale web=1
Jeśli, chciałabyś/chciałbyś, możesz wykorzystać wiedzę z poprzednich zajęć i zaimplementować ciągły deployment z pomocą dokumentacji.
W tym ćwiczeniu przygotowujemy do produkcji naszą aplikację, w tym celu musimy przygotować monitoring. Budżet jest niski, terminy gonią, decydujemy się na prosty monitoring, który wykryje, kiedy jesteśmy offline - statuscake.com.
-
Przejdź do statuscake.com
-
Utwórz konto.
-
Dodaj grupę kontaktową ze swoim emailem.
-
Dodaj Uptime Monitoring test:
- URL: url Twojej aplikacji
- Nazwa: dowolna
- Contact Group: zdefiniowana w 3.
-
Uaktualnij README.md o informację o monitoringu.
-
Dodaj do końca URLa
xyz
. Zaobserwuj jak zmieni się status testu. -
Popraw URL na właściwy, zaobserwuj co się dzieje.
-
Omów z instruktorem:
- Oncall
- SLA
- Postmortem
- Technika 5x Why i Blameless Postmortem
- MTTR i MTTF
- Technical Debt
-
Zweryfikuj ocenę certyfikatu SSL dla kilku przykładowych domen z pomocą: https://www.ssllabs.com/ssltest/
-
Dodaj badge, który mówi o stanie naszej automatyzacji na Github Action, korzystając z ich dokumentacji.
-
Dodaj Badge z StatusCake, kod do niego znajdziesz po prawej stronie "UPTIME BUTTON".
Projekt okazuje się sporym sukcesem, dostaliśmy kilka dni, aby poprawić kod, zmniejszyć dług techniczny. Naszym zadaniem będzie dodać informacji o test coverage.
-
Dodaj pytest-cov, plugin do pytest, do analizy pokrycia testami kodu, do test_requirements.txt:
echo 'pytest-cov' >> test_requirements.txt pip install -r test_requirements.txt
-
Teraz możemy wywołać
py.test
z aktywowanym pytest-cov (i wygenerować coverage.xml).coverage.xml
będziemy wykorzystywać później do wizualizacji pokrycia testami.PYTHONPATH=. py.test --verbose -s --cov=. # czym się różni poniższa komenda: PYTHONPATH=. py.test --verbose -s --cov=hello_world
Zamiast na ekran możemy przekierować raport do raportu XML:
PYTHONPATH=. py.test --verbose -s --cov=. --cov-report xml
Albo i do terminala i do XMLa (sprawdź też :
--cov-report term-missing
):PYTHONPATH=. py.test --verbose -s --cov=. --cov-report xml \ --cov-report term
O innych opcjach możesz się dowiedzieć z dokumentacji.
-
Dodatkowo, jeśli chcemy wizualizować informację o naszych testach (w ramach ćwiczeń o Jenkinsie) upewnijmy się, że generujemy również junit XML:
PYTHONPATH=. py.test -s --cov=. \ --cov-report xml \ --cov-report term \ --junit-xml=test_results.xml
-
Teraz, dodaj dwa nowe targety do pliku Makefile:
- test_cov – komenda dla uruchomienia testy z informacją o pokryciu kodu testami
- test_xunit – Komenda wygenerująca plik junit xml i coverage.xml
-
Zmodyfikuj .gitignore, aby git (git status) ignorował pliki: test_results.xml, coverage.xml i .coverage.
-
Wykorzystaj make test_xunit w Github Actions. Sprawdź, czy działa. Możliwe, że musisz przypiąć wersję pytest w
test_requirements.txt
, np.:pytest>=4.6
Zauważ: moglibyśmy dodać kod do wysyłania wyników testów z Github Actions do zewnętrznego serwisu.
Jedną z metryk jest również code complexity, zobaczmy jak możemy ją przeanalizować z użyciem narzędzia radon (patrz: https://pypi.python.org/pypi/radon) :
pip install radon
radon cc hello_world
Alternatywa: Możesz również skorzystać z mccabe z pomocą komendy flake8, zobacz: https://github.com/PyCQA/mccabe .
Zobacz również: https://github.com/mre/awesome-static-analysis#python
Koniecznie zapoznaj się z: https://github.com/psf/black - kiedy będziesz twoje umiejętności Pythona będą solidne, warto używać black
zamiast flake8
.
Wyszukaj w Googlu i znajdź różnice między następującymi licencjami:
- Apache
- GPL
- BSD
Nie musisz poświęcać na to wiele czasu, tylko, żebyś zrozumiał ich główną różnicę, które mają mniejsze konsekwencje na twój projekt.
Częścią pipeline-u w dużych firmach jest też wykrywanie licencji, które mogą nie są legalne w danej kombinacji (e.g., MIT with no military usage) czy pociągać za sobą poważne konsekwencje prawne, np., firmy raczej unikają GPL, niektóre kombinacje licencji nie są legalne.
-
Prostym narzędziem dostępnym jest pip-licenses (https://pypi.org/project/pip-licenses/). Zainstaluj i wyświetl licencje w swoim projekcie według powyższej instrukcji.
-
Bardziej rozbudowanym narzędziem jest LicenseFinder aby uniknąć konfiguracji i instalacji wymaganych bibliotek, skorzystajmy z oficjalnego obrazu Dockera (hub.docker.com/r/licensefinder/license_finder/) :
docker run -v $(pwd):/scan licensefinder/license_finder \ bash -c "source ~/.profile && \ cd /scan && pip3 install -r requirements.txt && \ license_finder report --python-version=3"
Uwaga: obraz Dockera ma duży rozmiar, pond 2.5Gb.
-
Zanotuj licencje komponentów, które używamy w naszej aplikacji.
Popularnym narzędziem do monitorowania licencji jest fossa.com, https://www.mend.io/, czy anchore.com.
Każda z często wykonywanych operacji związanych z rozwojem oprogramowania powinna być wykonywany automatycznie, aby jak najszybciej wykryć jakiekolwiek błędy. Jednym z popularnych narzędzi jest Jenkins (inne popularne narzędzie to GitlabCI). W tym ćwiczeniu wykorzystamy Jenkins-a do testowania naszego programu.
-
Utwórz fork z repozytorium: github.com/wojciech11/se_teaching_jenkins
-
Sklonuj swoje repozytorium dla Jenkinsa:
git clone https://github.com/TWÓJ UZYTK GITHUB/se_teaching_jenkins
-
Uruchom Jenkins-a według instrukcji w
README.md
. -
Wybierz opcję Install suggested plugins, a potem Skip and Continue as Admin.
-
Kiedy zostaniesz poproszony o podanie URLa, wciśnij SKIP and Finish.
-
Zobaczysz co poniżej, wybierz utwórz nowe zadanie:
XYZ
patrz instrukcja 10 CI/CD.
Już dość popularny Gitlab, w momencie, kiedy Github został kupiony przez Microsoft bierze sztormem rynek.
-
Załóż konto, nie loguj się przez githuba, na gitlab.com/users/sign_in
-
Utwórz nowy projekt
-
Wybierz import Repo by URL
-
Wklej URL twojego repozytorium git z hello_world_printer app na githubie.
-
Po imporcie, powinieneś zobaczyć:
-
Zapoznaj się z sekcjami: Project, Repository, Registry
-
Wybierz CI/CD – zapoznaj się z instrukcją
-
Dodaj kolejny remote do Twojego lokalnego repozytorium git, efektem tego będzie:
flowchart BT l(local\ngit) -- master --> H(remote\ngithub) l -- master --> G(remote\ngitlab)
# dodać nowe remote git remote add gitlab https://gitlab.com/TWÓJ_UŻYTK/se_hello_printer_app.git # wciaz bedziesz mogl wysylac # zmiany na githuba git push # # gitlab git push gitlab master
-
Gitlab ma inny format definiowania workflowów CI/CD
.gitlab-ci.yml
(patrz dokumentacja). Poznajmy ten format bliżej.Dodaj plik
.gitlab-ci.yml
, aby każdy nowy kod, który znajdzie się w repozytorium github był przetestowany:test: image: "python:3" stage: test script: - pip install -r requirements.txt - pip install -r test_requirements.txt - PYTHONPATH=. py.test --verbose -s
-
Zobacz w sekcji CI/CD, co się stanie po wrzuceniu go do naszego repozytorium na gitlabie. Umieść ten plik również na githubie.
-
Testy przechodzą? Warto zapakować naszą aplikację w pakiet. W naszym przypadku, wykorzystujemy dockera. Rozbudujmy nasz
.gitlab-ci.yml
:stages: - test - docker_build test: image: "python:3" stage: test script: - pip install -r requirements.txt - pip install -r test_requirements.txt - PYTHONPATH=. py.test --verbose -s docker: image: docker:stable services: - docker:dind stage: docker_build script: - docker build -t myapp .
Do czego służy sekcja stages
? Co daje nam services
?
- Zastąp komendy
docker
ipip
wywołaniem wcześniej przygotowanych targetów Makefile-a. Podpowiedź. Zauważ, musisz doinstalować make w dockerze w którym budujemy dockera:
script:
- apk add --update make
- make docker_build
- [Dodatkowe] Dodaj deployment docker image do repozytorium repository.gitlab.com.
Po długich dyskusjach na temat wyglądu naszego kodu, doszliśmy do wniosku, że może nie warto tracić czasu i zgodzić się na jakąś istniejącą konwencję. Proponujesz black, wszyscy się zgadzają i proszę Ciebie, abyś wprowadził odpowiednie zmiany. Zacznij od Makefile.
-
Zastępując target lint wywołaniem blacka oraz dodaj dodatkowy target dla sprawdzania czy kod jest dobrze sformatowany. Dodatkowy target, będzie kończy błędem, jeśli kod nie ma właściwego formatu.
# formatuje kod wedlug blacka # oczekujemy, ze dev/tester to uzyje przed pushem do gita fmt: black hello_world test # do użycia w CI/CD lint: black --check hello_world test
-
Przetestuj lokalnie, nie zapomnij dodać zależność do blacka w
test_requirements.txt
-
Przejrzyj wszystkie skrypty CI/CD i zastosuj we właściwych miejscach:
make lint_check
. -
Przetestuj czy właściwie CI/CD wyłapuje błędy w kodzie.
Uwaga: ucząc się Pythona, w swoich projektach wykorzystuj flake8, ponieważ poprawianie samemu błędów uczy nas właściwego pisania kodu Pythona. W dalszej części swojej przygody z Pythonem, rozważ częstsze stosowanie blacka lub podobnego narzędzia.