Zephyrnet-Logo

Automatisieren Sie jeden Aspekt Ihres Python-Projekts

Datum:

Automatisieren Sie jeden Aspekt Ihres Python-Projekts

Jedes Python-Projekt kann von der Automatisierung mit Makefile, optimierten Docker-Images, gut konfiguriertem CI / CD, Code Quality Tools und vielem mehr profitieren.


By Martin Heinz, DevOps Engineer bei IBM

Bild für Beitrag

Jedes Projekt - unabhängig davon, ob Sie an einer Web-App, Data Science oder AI arbeiten - kann von gut konfigurierten CI / CDs, Docker-Images, die sowohl in der Entwicklung debuggbar als auch für die Produktionsumgebung optimiert sind, oder einigen zusätzlichen Tools für die Codequalität profitieren CodeKlima or SonarCloud. All dies sind Dinge, die wir in diesem Artikel behandeln werden, und wir werden sehen, wie diese zu Ihrem hinzugefügt werden können Python Projekt!

Dies ist eine Fortsetzung des vorherigen Artikels zum Erstellen "Ultimatives" Python-Projekt-SetupVielleicht möchten Sie das überprüfen, bevor Sie dieses lesen.

TL; DR: Hier ist mein Repository mit vollständigem Quellcode und Dokumenten: https://github.com/MartinHeinz/python-project-blueprint

Debuggbare Docker-Container für die Entwicklung

 
Manche Leute mögen es nicht Docker weil es schwierig sein kann, Container zu debuggen, oder weil die Erstellung ihrer Images lange dauert. Beginnen wir also hier mit der Erstellung von Images, die sich ideal für die Entwicklung eignen - schnell zu erstellen und einfach zu debuggen.

Um das Image leicht debuggbar zu machen, benötigen wir ein Basis-Image, das Folgendes enthält alle die Tools, die wir jemals beim Debuggen benötigen könnten - Dinge wie bash, vim, netcat, wget, cat, find, grep usw. python:3.8.1-buster scheint ein idealer Kandidat für die Aufgabe zu sein. Es enthält standardmäßig viele Tools und wir können alles, was fehlt, ziemlich einfach installieren. Dieses Basisbild ist hübsch rubens, aber das spielt hier keine Rolle, da es nur für die Entwicklung verwendet wird. Auch wie Sie wahrscheinlich bemerkt haben, habe ich ein sehr spezifisches Bild gewählt - beide Versionen von sperren Python und auch der Debian - das ist beabsichtigt, da wir die Wahrscheinlichkeit minimieren wollen "Bruch" verursacht durch neuere, möglicherweise inkompatible Version von beiden Python or Debian.

Als Alternative könnten Sie verwenden Alpine basiertes Bild. Dies kann jedoch zu Problemen führen musl libc statt glibc welche Python beruht auf. Denken Sie also daran, wenn Sie sich für diese Route entscheiden.

In Bezug auf die Geschwindigkeit von Builds werden wir mehrstufige Builds nutzen, um so viele Ebenen wie möglich zwischenzuspeichern. Auf diese Weise können wir das Herunterladen von Abhängigkeiten und Tools wie vermeiden gcc sowie alle für unsere Anwendung benötigten Bibliotheken (ab requirements.txt).

Um die Arbeit weiter zu beschleunigen, erstellen wir ein benutzerdefiniertes Basis-Image aus dem zuvor genannten python:3.8.1-busterDies schließt alle Tools ein, die wir benötigen, da wir die zum Herunterladen und Installieren dieser Tools erforderlichen Schritte nicht in das endgültige Runner-Image zwischenspeichern können.

Genug geredet, mal sehen Dockerfile:

Oben sehen Sie, dass wir 3 Zwischenbilder durchgehen, bevor wir final erstellen Läufer Bild. Der erste von ihnen wird benannt builder. Es werden alle erforderlichen Bibliotheken heruntergeladen, die zum Erstellen unserer endgültigen Anwendung benötigt werden gcc und Python virtuelle Umgebung. Nach der Installation wird auch eine tatsächliche virtuelle Umgebung erstellt, die dann von den nächsten Images verwendet wird.

Als nächstes kommt die builder-venv Bild, das die Liste unserer Abhängigkeiten kopiert (requirements.txt) in das Image und installiert es dann. Dieses Zwischenabbild wird für das Caching benötigt, da wir nur dann Bibliotheken installieren möchten, wenn requirements.txt Änderungen, sonst verwenden wir nur Cache.

Bevor wir unser endgültiges Image erstellen, möchten wir zunächst Tests für unsere Anwendung ausführen. Das passiert in der tester Bild. Wir kopieren unseren Quellcode in ein Bild und führen Tests durch. Wenn sie vorbei sind, gehen wir weiter zum runner.

Für das Runner-Image verwenden wir ein benutzerdefiniertes Image, das einige Extras wie enthält vim or netcat das sind im normalen nicht vorhanden Debian Bild. Sie finden dieses Bild auf Docker-Hub hier und Sie können auch das sehr einfache überprüfen Dockerfile in base.Dockerfile hier. Also, was wir in diesem endgültigen Image tun - zuerst kopieren wir die virtuelle Umgebung, die alle unsere installierten Abhängigkeiten enthält tester Bild, als nächstes kopieren wir unsere getestete Anwendung. Nachdem wir alle Quellen im Bild haben, wechseln wir in das Verzeichnis, in dem sich die Anwendung befindet, und setzen sie dann ENTRYPOINT Damit wird unsere Anwendung ausgeführt, wenn das Image gestartet wird. Aus Sicherheitsgründen setzen wir auch USER zu 1001, wie Best Practices uns sagen, sollten Sie niemals Container unter laufen lassen root Benutzer. Die letzten 2 Zeilen setzen Beschriftungen des Bildes. Diese werden ersetzt / gefüllt, wenn der Build mit ausgeführt wird make Ziel, das wir etwas später sehen werden.

Optimierte Docker-Container für die Produktion

 
Wenn es um Bilder in Produktionsqualität geht, sollten wir sicherstellen, dass sie klein, sicher und schnell sind. Mein persönlicher Favorit für diese Aufgabe ist Python Bild von Distrolos Projekt. Was ist Distrolosaber?

Lassen Sie es mich so sagen - in einer idealen Welt würde jeder sein Image mit aufbauen FROM scratch als ihr Basisbild (das heißt - leeres Bild). Dies ist jedoch nicht das, was die meisten von uns gerne tun würden, da Sie Ihre Binärdateien usw. statisch verknüpfen müssen Distrolos kommt ins Spiel - es ist FROM scratch für alle.

Okay, jetzt um tatsächlich zu beschreiben, was Distrolos ist. Es ist eine Reihe von Bildern von Google Diese enthalten das Nötigste, das für Ihre App benötigt wird. Dies bedeutet, dass es keine Shells, Paketmanager oder andere Tools gibt, die das Bild aufblähen und Signalrauschen für Sicherheitsscanner erzeugen könnten (z CVE) erschweren die Feststellung der Einhaltung.

Jetzt, da wir wissen, womit wir es zu tun haben, wollen wir uns das ansehen Produktion Dockerfile… Nun, eigentlich werden wir hier nicht so viel ändern, es sind nur zwei Zeilen:

Alles, was wir ändern mussten, sind unsere Basisimages zum Erstellen und Ausführen der Anwendung! Aber der Unterschied ist ziemlich groß - unser Entwicklungsimage hatte 1.03 GB und dieses ist nur 103 MB groß ganz ein Unterschied! Ich weiß, ich kann dich schon hören - "Aber Alpine kann noch kleiner sein!" - Ja, das stimmt, aber die Größe spielt keine Rolle so viel. Sie werden die Bildgröße immer nur beim Herunterladen / Hochladen bemerken, was nicht so häufig der Fall ist. Wenn das Bild ausgeführt wird, spielt die Größe keine Rolle. Was wichtiger als die Größe ist, ist die Sicherheit und diesbezüglich Distrolos ist sicherlich überlegen, wie Alpine (was eine großartige Alternative ist) hat viele zusätzliche Pakete, die die Angriffsfläche erhöhen.

Das Letzte, was es wert ist, erwähnt zu werden Distrolos sind debuggen Bilder. Bedenkt, dass Distrolos enthält nicht jedem Muschel (nicht einmal sh) wird es ziemlich schwierig, wenn Sie debuggen und herumstöbern müssen. Dafür gibt es debug Versionen von allen Distrolos Bilder. Wenn also Poop auf den Fan trifft, können Sie Ihr Produktionsimage mit erstellen debug Markieren und implementieren Sie es neben Ihrem normalen Image, führen Sie es aus und führen Sie beispielsweise einen Thread-Dump durch. Sie können die Debug-Version von verwenden python3 Bild wie folgt:

Einzelbefehl für alles

 
Mit all den Dockerfiles fertig, lass uns das verdammt noch mal automatisieren Makefile! Als erstes möchten wir unsere Anwendung mit erstellen Docker. Also können wir ein Dev-Image erstellen make build-dev welches läuft folgendes Ziel:

Dieses Ziel erstellt das Bild, indem zuerst die Beschriftungen am unteren Rand von ersetzt werden dev.Dockerfile mit Bildname und Tag, die durch Ausführen erstellt werden git describe und dann rennen docker build.

Als nächstes Gebäude für die Produktion mit make build-prod VERSION=1.0.0:

Dieses ist dem vorherigen Ziel sehr ähnlich, aber anstatt es zu verwenden git Tag als Version verwenden wir die Version, die im obigen Beispiel als Argument übergeben wurde 1.0.0.

Wenn Sie alles einlaufen lassen Docker, dann müssen Sie es irgendwann auch debuggen DockerDafür gibt es folgendes Ziel:

Aus dem obigen können wir sehen, dass der Einstiegspunkt von überschrieben wird bash und der Befehl container wird durch ein Argument überschrieben. Auf diese Weise können wir entweder einfach den Container betreten und herumstöbern oder einen einmaligen Befehl ausführen, wie im obigen Beispiel.

Wenn wir mit dem Codieren fertig sind und das Bild verschieben möchten Docker Registrierung, dann können wir verwenden make push VERSION=0.0.2. Mal sehen, was das Ziel macht:

Es läuft zuerst build-prod Ziel haben wir uns vorher angesehen und laufen dann einfach docker push. Dies setzt voraus, dass Sie angemeldet sind Docker Registrierung, bevor Sie dies ausführen, müssen Sie ausführen docker login.

Das letzte Ziel ist das Aufräumen Docker Artefakte. Es verwendet name Etikett, das ersetzt wurde Dockerfiles So filtern und finden Sie Artefakte, die gelöscht werden müssen:

Hier finden Sie eine vollständige Codeliste Makefile in meinem Repository hier: https://github.com/MartinHeinz/python-project-blueprint/blob/master/Makefile

CI / CD mit GitHub-Aktionen

 
Lassen Sie uns nun all diese praktischen Funktionen verwenden make Ziele für die Einrichtung unserer CI / CD. Wir werden verwenden GitHub-Aktionen und GitHub-Paketregistrierung um unsere Pipelines (Jobs) zu bauen und unsere Bilder zu speichern. Also, was genau sind das?

  • GitHub-Aktionen sind Jobs / Pipelines Damit können Sie Ihre Entwicklungsworkflows automatisieren. Sie können sie verwenden, um einzelne Aufgaben zu erstellen und sie dann zu benutzerdefinierten Workflows zu kombinieren, die dann beispielsweise bei jedem Push-to-Repository oder bei der Erstellung der Version ausgeführt werden.
  • GitHub-Paketregistrierung ist ein Paket-Hosting-Service, der vollständig in GitHub integriert ist. Hier können Sie verschiedene Arten von Paketen speichern, z. B. Ruby Edelsteine or npm Pakete. Wir werden es verwenden, um unsere zu speichern Docker Bilder. Wenn Sie nicht vertraut sind GitHub-Paketregistrierung Wenn Sie weitere Informationen dazu wünschen, können Sie meinen Blog-Beitrag lesen hier.

Nun zu verwenden GitHub-Aktionenmüssen wir schaffen Workflows Diese werden basierend auf den von uns ausgewählten Triggern (z. B. Push-to-Repository) ausgeführt. Diese Workflows sind YAML Dateien, die in leben .github/workflows Verzeichnis in unserem Repository:

Dort werden wir 2 Dateien erstellen build-test.yml und push.yml. Zuerst von ihnen build-test.yml enthält 2 Jobs, die bei jedem Push in das Repository ausgelöst werden. Schauen wir uns diese an:

Erster Job angerufen build Überprüft, ob unsere Anwendung erstellt werden kann, indem Sie unsere ausführen make build-dev Ziel. Bevor es jedoch ausgeführt wird, überprüft es zuerst unser Repository, indem es die aufgerufene Aktion ausführt checkout welches am veröffentlicht wird GitHub.

Der zweite Job ist etwas komplizierter. Es führt Tests gegen unsere Anwendung sowie 3 Linters (Code Quality Checker) durch. Wie beim vorherigen Job verwenden wir checkout@v1 Aktion, um unseren Quellcode zu erhalten. Danach führen wir eine weitere veröffentlichte Aktion namens aus setup-python@v1 Dadurch wird die Python-Umgebung für uns eingerichtet (Details dazu finden Sie hier hier). Jetzt, da wir eine Python-Umgebung haben, benötigen wir auch Anwendungsabhängigkeiten von requirements.txt mit denen wir installieren pip. An diesem Punkt können wir fortfahren zu rennen make test Ziel, das unsere auslöst Pytest Suite. Wenn unsere Testsuite erfolgreich ist, installieren wir die zuvor genannten Linters - Pylint, flocke8 und Bandit. Endlich rennen wir make lint Ziel, das jeden dieser Linters auslöst.

Das ist alles für den Build / Test-Job, aber was ist mit dem Pushing-Job? Lassen Sie uns auch das durchgehen:

Die ersten 4 Zeilen definieren, wann dieser Job ausgelöst werden soll. Wir geben an, dass dieser Job nur gestartet werden soll, wenn Tags in das Repository verschoben werden (* Gibt das Muster des Tag-Namens an - in diesem Fall - etwas). Dies ist so, dass wir unser Docker-Image nicht weiterleiten GitHub-Paketregistrierung Jedes Mal, wenn wir in das Repository pushen, sondern nur dann, wenn wir ein Tag pushen, das die neue Version unserer Anwendung angibt.

Nun zum Hauptteil dieses Jobs: Zunächst wird der Quellcode ausgecheckt und die Umgebungsvariable von festgelegt RELEASE_VERSION zu git Tag, den wir gedrückt haben. Dies erfolgt über das eingebaute System ::setenv Merkmal von GitHub-Aktionen (Mehr Info hier). Als Nächstes meldet es sich mit in der Docker-Registrierung an REGISTRY_TOKEN Geheimnis im Repository gespeichert und Login des Benutzers, der den Workflow initiiert hat ( github.actor). Schließlich läuft es in der letzten Zeile push Ziel, das ein Prod-Image erstellt und es mit zuvor gepusht in die Registrierung schiebt git Tag als Bild-Tag.

Sie können die vollständige Codeliste in den Dateien in meinem Repository auschecken hier.

Codequalitätsprüfungen mit CodeClimate

 
Zu guter Letzt werden wir auch Codequalitätsprüfungen mit hinzufügen CodeKlima und SonarCloud. Diese werden zusammen mit unserem ausgelöst Test Job oben gezeigt. Fügen wir also ein paar Zeilen hinzu:

Wir fangen mit an CodeKlima für die wir zuerst exportieren GIT_BRANCH Variable, die wir mit abrufen GITHUB_REF Umgebungsvariable. Als nächstes laden wir herunter CodeKlima Testreporter und mach es ausführbar. Als Nächstes formatieren wir damit den von unserer Testsuite generierten Abdeckungsbericht und senden ihn in der letzten Zeile an CodeKlima mit Testreporter-ID, die wir in Repository-Geheimnissen speichern.

Im Hinblick auf die SonarCloudmüssen wir schaffen sonar-project.properties Datei in unserem Repository, die so aussieht (Werte für diese Datei finden Sie unter SonarCloud Dashboard unten rechts):

Ansonsten können wir nur vorhandene verwenden sonarcloud-github-action, die die ganze Arbeit für uns erledigt. Alles was wir tun müssen ist 2 Token zu liefern - GitHub eine, die standardmäßig im Repository ist und SonarCloud Token, von dem wir bekommen können SonarCloud Webseite.

Hinweis: Schritte zum Abrufen und Festlegen aller zuvor genannten Token und Geheimnisse finden Sie in der README-Datei des Repositorys hier.

Zusammenfassung

 
Das ist es! Mit Tools, Konfigurationen und Code von oben sind Sie bereit, alle Aspekte Ihres nächsten zu erstellen und zu automatisieren Python Projekt! Wenn Sie weitere Informationen zu den in diesem Artikel gezeigten / diskutierten Themen benötigen, lesen Sie die Dokumente und den Code in meinem Repository hier: https://github.com/MartinHeinz/python-project-blueprint und wenn Sie Vorschläge / Probleme haben, reichen Sie diese bitte im Repository ein oder markieren Sie sie einfach, wenn Ihnen dieses kleine Projekt von mir gefällt. 🙂

 
Downloads

 
Bio: Martin Heinz ist DevOps Engineer bei IBM. Als Softwareentwickler interessiert sich Martin leidenschaftlich für Computersicherheit, Datenschutz und Kryptografie, konzentriert sich auf Cloud- und Serverless-Computing und ist immer bereit, sich einer neuen Herausforderung zu stellen.

Original. Mit Genehmigung erneut veröffentlicht.

Related:

Quelle: https://www.kdnuggets.com/2020/09/automating-every-aspect-python-project.html

spot_img

Neueste Intelligenz

spot_img

Chat mit uns

Hallo! Wie kann ich dir helfen?