Skip to main content

Node.js-Docker-Images in GitHub Packages mit GitHub Actions verwalten

Artikel von
blog hero github actions docker push

13. Juli 2021

0 Min. Lesezeit

Wenn Sie heute Open-Source-Entwicklung betreiben, sind Sie wahrscheinlich in der GitHub-Community aktiv – und beteiligen sich an Open-Source-Projekten und ihren Repositorys. Eine neuere Ergänzung des GitHub-Ökosystems ist GitHub Packages. Der Dienst wurde 2019 angekündigt und erhält nun mit der allgemeinen Verfügbarkeit der Container-Registry von GitHub Packages weitere Updates. Damit können wir Docker-basierte Images und alle anderen OCI-kompatiblen Formate vollständig innerhalb des GitHub-Ökosystems veröffentlichen und abrufen.

In diesem Beitrag führe ich Sie Schritt für Schritt durch einen GitHub-Actions-Workflow. Sie erfahren, wie Sie Node.js-Projekte als Docker-Images veröffentlichen und anschließend in die Container-Registry von GitHub Packages übertragen.

Bevor wir beginnen: Wussten Sie, dass es ein eigenes Supportforum für GitHub-Nutzer gibt, die GitHub Support Community? Schauen Sie vorbei, wenn Sie Hilfe benötigen.

Für diesen Beitrag verwenden wir das Node.js-Projekt dockly, ein Open-Source-Kommandozeilentool für Node.js, das eine immersive Terminaloberfläche zur Verwaltung von Docker-Containern und -Diensten bietet.

README für Dockly mit einer Terminal-Oberfläche zur Verwaltung von Docker-Containern, einschließlich Containerlisten, Statusdiagrammen und Protokollen.

Einen GitHub-Actions-Workflow erstellen

Rufen Sie Ihr Open-Source-Repository auf GitHub auf und klicken Sie auf den Tab Actions, dann auf New Workflow und anschließend auf set up a workflow yourself. Die Ansicht sollte dann so aussehen:

GitHub-Actions-Seite mit der Überschrift „Workflow-Vorlage auswählen“ und Optionen zum Auswählen oder Einrichten eines Workflows

Zuerst legen wir den Dateinamen des Workflows fest: docker-publish.yml oder eine andere Namenskonvention Ihrer Wahl.

GitHub füllt den Workflow-Code möglicherweise automatisch aus. Löschen Sie in diesem Fall einfach den gesamten Inhalt und fügen Sie Folgendes ein:

name: Docker

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

on:
  push:
    branches: [ main ]
    tags: [ 'v*.*.*' ]
  pull_request:
    branches: [ main ]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

Der obige Workflow legt die folgenden Konventionen fest:

  • Der Workflow wird nur bei Commits im main-Branch oder bei Pull Requests an den main-Branch ausgeführt. Hinweis: Wenn Ihr Repository noch die frühere Konvention mit dem master-Branch verwendet, sollten Sie den Namen hier und im restlichen Codebeispiel entsprechend ändern. Der Workflow wird außerdem bei jedem Push von Tags im Semver-Format <v*.*.*> an das Repository ausgeführt. Das ist praktisch, weil wir so für jede Version Docker-Images veröffentlichen können.

  • Dadurch wird sichergestellt, dass beim Veröffentlichen eines neuen Docker-Images auch GitHub-Repository-Tags erstellt werden.

  • Für die übrigen Workflow-Jobs werden globale Umgebungsvariablen eingerichtet, die auf die GitHub Container Registry (ghcr.io) verweisen. Außerdem wird der Name des Docker-Images nach der üblichen Konvention von Docker Hub festgelegt: <user>/<repo>, zum Beispiel lirantal/nodejs-app.

Als Nächstes definieren wir unsere Jobs und richten einen Prozess zum Erstellen und anschließenden Veröffentlichen des Docker-Images ein.

Docker-Image als Teil des GitHub-Actions-Workflows erstellen

Um Docker-Images in der Container-Registry von GitHub Packages (oder auch nur auf GitHub) veröffentlichen zu können, müssen wir uns zuerst mit einem gültigen Konto authentifizieren. Deshalb besteht der erste Schritt im Build- und Publish-Job darin, sich anzumelden.

Fügen Sie den folgenden Code direkt unter dem zuvor eingefügten Code ein:

jobs:
  build_and_publish:

    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Log into registry ${{ env.REGISTRY }}
        if: github.event_name != 'pull_request'
        uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract Docker metadata
        id: meta
        uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

Sehen wir uns die Aktionen an, die von den hier beschriebenen Jobs ausgeführt werden:

  1. Im ersten Schritt wird der Quellcode des Repositorys ausgecheckt.

  2. Anschließend authentifizieren wir uns bei der Container-Registry von GitHub Packages. Wie Sie sehen, verwenden wir die zuvor definierte Umgebungsvariable REGISTRY, die auf ghcr.io verweist – die eigene Registry von GitHub für Container-Images.

    Als Benutzername für die Authentifizierung dient der Nutzer, der den Workflow gestartet hat. Das sollte mit Ihrem Benutzernamen als Inhaber des Repositorys übereinstimmen. Als Passwort wird GITHUB_TOKEN verwendet, das GitHub-Actions-Workflows automatisch zur Verfügung steht. Sie müssen es also nicht manuell als Secret oder Umgebungsvariable im Repository hinzufügen. Die Anmeldung bei der Registry wird bei Pull Requests übersprungen. Das ist ohnehin nicht erforderlich und könnte bei Pull-Request-CI und Forks sensible Informationen offenlegen.

  3. Der letzte Schritt im obigen Codebeispiel extrahiert Metadaten aus dem Image und stellt sie für den Docker-Image-Build bereit (unser nächster und letzter Schritt in diesem Workflow!). Die Metadaten enthalten Informationen zu Tags und Labels, die der Docker-Build-Aktion zur Verfügung gestellt werden. Konkret legt die übergebene Eingabe images den Namen des Docker-Images fest, der als Basis für die Tags dient.

Docker-Image erstellen und in der Container-Registry von GitHub Packages veröffentlichen

Im letzten Schritt wird das Docker-Image erstellt und veröffentlicht. Dafür verwenden wir eine Aktion, die beides in einem Schritt erledigt. Sie werden sehen, dass wir die Eingabe push des Workflows auf eine Bedingung setzen: Das Image wird nur dann in der Registry veröffentlicht, wenn das Ereignis nicht durch einen Pull Request ausgelöst wurde:

      - name: Build and push Docker image
        uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
        with:
          context: .
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

Das war’s.

Sobald Sie den Workflow speichern (mit der richtigen Einrückung!) und ausführen, indem Sie ihn in den main-Branch mergen, sollte ein Image erstellt und in der Container-Registry von GitHub Packages veröffentlicht werden.

Wenn alles geklappt hat, sehen Sie das lang ersehnte grüne Häkchen für einen erfolgreichen Job – so wie bei mir:

GitHub-Actions-Workflow mit erfolgreichem Build und Push eines Images zu GHCR auf dem Master-Branch

Wie übertrage ich ein Docker-Image in die Container-Registry von GitHub Packages?

Verwenden Sie die offizielle Docker-GitHub-Aktion docker/build-push-action in Ihrer GitHub-Actions-Workflow-Datei und stellen Sie sicher, dass die Umgebungsvariable REGISTRY auf ghcr.io gesetzt ist.

Docker-Images aus der Container-Registry von GitHub Packages abrufen

Nachdem wir nun ein Docker-Image unseres Projekts in einer öffentlichen Registry veröffentlicht haben, testen wir es, indem wir es in unsere lokale Entwicklungsumgebung abrufen:

$ docker pull ghcr.io/lirantal/my-nodejs-app
Using default tag: latest
latest: Pulling from lirantal/my-nodejs-app
b4d181a07f80: Pulling fs layer
de8ecf497b75: Pulling fs layer
69b92f9e5e70: Pulling fs layer
1f2b8e2c8ad8: Waiting
d0f4259cb643: Waiting
9ae47f3f99ba: Waiting
87270829eb60: Waiting
905fc634546c: Waiting

Wie gebe ich an, welche Docker-Image-Version abgerufen werden soll?

Der Befehl docker pull nimmt ein zusätzliches Argument im Format <registry>/<user>/<repo>:<image tag> entgegen. Um beispielsweise das Docker-Image-Tag „latest“ des my-nodejs-app image aus der Container-Registry von GitHub Packages abzurufen, verwenden Sie folgenden Befehl: docker pull ghcr.io/lirantal/my-nodejs-app

Juhu, es hat geklappt!

Aber Moment … gibt es keine bessere Möglichkeit, die Docker-Images anzuzeigen, die ich in GitHub Packages übertrage? Hier sind Sie richtig!

Docker-Images in GitHub Packages finden

Wenn Sie Ihr GitHub-Profil aufrufen (zum Beispiel meines unter https://github.com/lirantal?tab=packages), sehen Sie jetzt alle Ihre öffentlich verfügbaren Docker-Images.

Wenn Sie dieser Anleitung gefolgt sind und Ihr eigenes Docker-Image erstellt haben: Können Sie es finden? Hier ist die Seite des Docker-Image-Pakets, das ich im Rahmen der GitHub-Actions-CI des Repositorys in GitHub Packages übertragen habe:

GitHub-Container-Registry-Seite für dockly mit dem Docker-Pull-Befehl, getaggten Image-Versionen und der README-Datei.

Kein latest-Tag im veröffentlichten Docker-Image?

Wenn Sie versucht haben, das Docker-Image anhand seines Namens abzurufen, ohne ein Docker-Image-Tag für den verwendeten main- oder master-Branch anzugeben, ist Ihnen vielleicht aufgefallen, dass das häufig verwendete Docker-Image-Tag latest nicht verfügbar ist. Das passiert, wenn keine Semver-Tags (semantische Versionierung) übertragen wurden. Wenn Sie in Ihrem eigenen Repository solche Tags übertragen, sollte das Tag verfügbar sein.

Wenn Sie für das veröffentlichte Docker-Image unbedingt den Tag-Alias latest festlegen möchten, können Sie die Metadatenaktion wie folgt aktualisieren (beachten Sie den zusätzlichen mehrzeiligen flavor-Schlüssel):

      - name: Extract Docker metadata
        id: meta
        uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          flavor: |
            latest=true
            prefix=
            suffix=

Beachten Sie jedoch, dass dadurch immer das Image-Tag latest als Alias für das veröffentlichte Docker-Image gesetzt wird, wenn der main-Branch einen CI-Job auslöst.

Wie versehe ich ein Docker-Image mit dem Tag latest?

Um ein zuvor erstelltes Image lokal mit einem Tag zu versehen, verwenden Sie die folgende Syntax für den Docker-Tag-Befehl: docker tag <local image name> <new tag>. Zum Beispiel: docker tag my-nodejs-app lirantal/my-nodejs-app:latest

Wie führe ich ein Docker-Image mit einem Tag aus?

Um beim Ausführen eines Images ein bestimmtes Docker-Image-Tag zu verwenden, geben Sie im Befehl docker run einfach den vollständig qualifizierten Image-Namen und das Tag an. Zum Beispiel: docker run --rm -p 27017:27017 mongo:latest

Relevante Docker- und Container-Integrationen im GitHub Actions Marketplace

Sie können GitHub-Actions-Workflows auch im GitHub Actions Marketplace finden und erstellen. Dort stehen Ihnen mehr als 9.000 Workflows aus den Bereichen Codequalität, Abhängigkeitsverwaltung, Sicherheit und mehr zur Verfügung. Dort finden Sie auch die Snyk GitHub Actions, mit denen Sie Ihre Projekte vor Schwachstellen in Open-Source-Bibliotheken von Drittanbietern schützen und sicherstellen können, dass Ihr Team sichere Programmierpraktiken befolgt.

Für unser Thema – Docker-Images erstellen, testen und in einer Registry veröffentlichen – gibt es einen einfacheren Einstieg als die Suche im Marketplace. Wenn sich bereits eine Dockerfile in Ihrem Repository befindet, erkennt GitHub sie automatisch und schlägt passende Workflows für GitHub Actions vor. Rufen Sie einfach den Tab Actions auf:

GitHub-Actions-Einrichtungsseite mit vorgeschlagenen Dockerfile-Workflows zum Veröffentlichen eines Docker-Containers oder Erstellen eines Docker-Images

Der erste vorgeschlagene Workflow Publish Docker Container richtet einen ähnlichen Workflow zum Erstellen und Veröffentlichen von Docker-Images ein wie der, den wir uns bereits angesehen haben.

Zusammenfassung und nächste Schritte

Habe ich Ihr Interesse an sicheren Entwicklungspraktiken geweckt? Wunderbar! Hier finden Sie einige weiterführende Ressourcen, mit denen Sie loslegen und bei Ihrem Team Sicherheitspunkte sammeln können:

  1. Die Sicherheit der Supply Chain ist wichtig. Hier sind 10 Best Practices für GitHub-Sicherheit, damit Sie nicht dieselben Fehler machen.

  2. Arbeiten Sie mit Node.js und erstellen Sie npm-Pakete? Ich auch! In diesem Beitrag erfahren Sie, wie Sie mit GitHub Actions npm-Pakete sicher veröffentlichen.

  3. Wenn Sie viel im GitHub-Ökosystem arbeiten, sollten Sie sich das Code-Scanning von Snyk ansehen. Es lässt sich nahtloser in Ihre Workflows integrieren: GitHub Security Code Scanning: Schützen Sie Ihre Open-Source-Abhängigkeiten

Starten Sie mit Capture the Flag

Erfahren Sie in unserem virtuellen On-Demand-Workshop für Einsteiger, wie Sie Capture-the-Flag-Herausforderungen lösen.

Gepostet in:

Weiterlesen

Live Stream

Remediation Agents einfach erklärt: Warum Beheben wichtiger ist als Finden

Erfahren Sie, wie Snyks Remediation Agent mithilfe von Security-Intelligence, Breakability-Analysen und Validierung Schwachstellen in mergefähige Pull Requests verwandelt.

feature ai ide dark
Blog

Ein erster Blick auf Evo Agentic AppSec: agentische Behebung und Schutz vor bösartigem Code

Entdecken Sie die ersten Agentic-AppSec-Funktionen von Snyk: einen autonomen Remediation Agent, der Schwachstellen behebt, und Malicious Code Defense, das riskante Pakete vor der Veröffentlichung blockiert.

feature insights context
Blog

Der keyv-npm-Angriff: Preinstall-Malware, vertrauenswürdige Provenance und IDE-Hooks

keyv 6.0.0 und zehn weitere npm-Releases enthielten Malware, die bei der Installation ausgeführt wird. Erfahren Sie, welche Versionen betroffen sind, welche Hashes gelten, wie Sie die Malware erkennen und in welcher Reihenfolge Sie sicher reagieren.