Github Actions um Golden Images with HashiCorp Packer zu bauen


Bicycle

In früheren Beiträgen haben wir bereits verschiedene Möglichkeiten gezeigt, wie man mit HashiCorp Packer Golden Images erstellt. In diesem Beitrag zeigen wir, wie man den Prozess mit Github Actions automatisiert. Wir werden HashiCorp Vault verwenden, um die Geheimnisse für Packer zu speichern, Terraform in Kombination mit Terratest, um die tatsächlich erstellten Images bereitzustellen, und das Ergebnis von Packer mit Mondoo zu verifizieren. Unsere Images werden auf HCP Packer veröffentlicht, um sie verfügbar zu machen und die Versionsinformationen in verschiedenen Release-Kanälen (Entwicklung, Staging, Produktion) zu pflegen.

Zusätzlich fügen wir einige Sequenzen hinzu, um den Github-Workflow mit act ausführbar zu machen, wie [in diesem Artikel] (/blog/2024-08-14-github-actions-locally/) bereits beschrieben wurde.

Einrichtung von Github Actions

Zuerst richten wir in unserem Workflow die benötigten Tools ein, indem wir entsprechende Github Actions verwenden:

Vault Github Action

Um auf verschiedene Ressourcen zugreifen zu können, müssen wir in unserem Workflow diese Geheimnisse abrufen. Wir verwenden HCP Vault, um diese Werte zu speichern, und nutzen die vault-action, um auf diese Geheimnisse zuzugreifen und sie für die kommenden Schritte verfügbar zu machen. Momentan erstellen wir Golden Images parallel für Azure und AWS. Außerdem benötigen wir Zugang zur HCP-Plattform, um Informationen über unsere erstellten Images zu speichern, und zuletzt stellen wir Sicherheits- und Compliance-Scan-Informationen durch Mondoo bereit. Dafür müssen wir also noch die folgenden Secrets mittels der Vault Github Action abholen:

 1- name: Import Secrets
 2  id: import-secrets
 3  uses: hashicorp/vault-action@v2
 4  with:
 5    url: ${{ vars.VAULT_ADDRESS }}
 6    namespace: ${{ vars.VAULT_NAMESPACE}}
 7    method: approle
 8    path: github_ci
 9    roleId: ${{ secrets.VAULT_APPROLE_ID}}
10    secretId: ${{ secrets.VAULT_APPSECRET_ID }}
11    secrets: |
12        secret/data/ci/aws accessKey | AWS_ACCESS_KEY_ID ;
13        secret/data/ci/aws secretKey | AWS_SECRET_ACCESS_KEY;
14
15        secret/data/ci/hcp username | HCP_CLIENT_ID;
16        secret/data/ci/hcp password | HCP_CLIENT_SECRET;
17
18        secret/data/ci/mondoo password | MONDOO_AGENT_ACCOUNT;
19
20        secret/data/ci/azure subscriptionId | ARM_SUBSCRIPTION_ID;
21        secret/data/ci/azure tentantId | ARM_TENANT_ID;
22        secret/data/ci/azure clientId | ARM_CLIENT_ID;
23        secret/data/ci/azure clientSecret | ARM_CLIENT_SECRET;
24
25        secret/data/ci/ssh private;
26        secret/data/ci/ssh public;        

Python Setup

In unserem Bereitstellungsprozess für den eigentlichen Packer-Build verwenden wir Ansible-Playbooks, um die eigentlichen Image-Vorlagen zu provisionieren. Daher müssen wir Python einrichten, um sicherzustellen, dass alle erforderlichen Abhängigkeiten installiert und für unsere Ansible-Playbooks verfügbar sind.

1- uses: actions/setup-python@v5
2  with:
3    python-version: ${{ env.PYTHON_VERSION }}
4
5- name: Install Packertools
6  run: |
7    python -m pip install --upgrade pip
8    pip install -r requirements.txt
9    ansible-galaxy install -r ansible/requirements.yaml    

Packer innerhalb von Github Actions

Da wir die eigentliche Build-Quelle über die Umgebungsvariablen CLOUD, DISTRIBUTION und PLAY steuern können, haben wir Wrapper implementiert, die die Packer-Konfigurationsdatei und die Packer-Variablen-Datei erstellen. So können wir das gleiche Image für verschiedene Clouds (AWS, Azure, VMware, ...) und Distributionen (z. B. Windows, Ubuntu, CentOS, ...) mit denselben Playbooks erstellen.

In diesen Playbooks werden alle Geheimnisse (host_vars und group_vars) von einem Key/Value-Secret-Store innerhalb von HashiCorp Vault verwaltet – dies wird in einem separaten Beitrag ausführlich beschrieben.

Packer Build

 1- name: Create Packer Configuration
 2  run: ./scripts/create_packer_config.sh
 3
 4- name: Packer Build
 5  id: build
 6  run: |
 7    packer init "${CI_PROJECT_DIR}/packer/current_${GITHUB_RUN_ID}.pkr.hcl"
 8
 9    packer build ${EXTRA_ARGS} \
10      -var-file="${CI_PROJECT_DIR}/packer/current_${GITHUB_RUN_ID}.pkrvars.hcl" \
11      "${CI_PROJECT_DIR}/packer/current_${GITHUB_RUN_ID}.pkr.hcl" | tee "${GITHUB_RUN_ID}.log"
12
13    ./scripts/post-build.sh    

Der Build-Schritt ruft einfach packer init auf, um alle notwendigen Plugins herunterzuladen, und baut dann die eigentliche Konfiguration. Der tee-Befehl wird verwendet, um die Protokolldatei für eine spätere Referenz zu speichern, und das post-build.sh-Skript kümmert sich um das Parsen der Protokolldatei und das Speichern der eigentlichen Build-Informationen zur späteren Verwendung im Workflow.

Testing Packer Image

Vom Build-Schritt erhalten wir Informationen über die tatsächlichen Image-Vorlagennamen oder IDs, die wir testen möchten. Das test-wrapper.sh-Skript prüft lediglich, ob Tests gestartet werden können, und zieht die Testkonfiguration für die tatsächliche Cloud, Distribution und das Play. Die eigentlichen Tests werden von terratest durchgeführt, um das Image bereitzustellen, und anschließend von Mondoo gescannt. Weitere Informationen darüber haben wir in einem separaten Beitrag hier veröffentlicht.

1- name: Test Packer Image
2  id: test
3  run: ./scripts/test-wrapper.sh

Veröffentlichen von Packer Image

Nach einem erfolgreichen Test werden die Images auf den folgenden HCP-Packer-Kanal veröffentlicht. Das Image wird nach dem Packer-Build auf dem latest-Kanal veröffentlicht und mit etwas Terraform-Code auf andere Kanäle verschoben.

 1
 2data "hcp_packer_version" "src" {
 3  bucket_name  = local.hcp_bucket_name
 4  channel_name = var.hcp_channel_source
 5}
 6
 7resource "hcp_packer_channel" "destination" {
 8  name        = var.hcp_channel_destination
 9  bucket_name = local.hcp_bucket_name
10}
11
12resource "hcp_packer_channel_assignment" "destination" {
13  bucket_name         = local.hcp_bucket_name
14  channel_name        = var.hcp_channel_destination
15  version_fingerprint = data.hcp_packer_version.src.fingerprint
16}

Innerhalb des Skripts werden terraform init und terraform apply aufgerufen. Da wir jedoch den Terraform-Zustand nicht verwalten, rufen wir terraform import auf, um den aktuellen hcp_packer_channel.destination und hcp_packer_channel_assignment.destination mit ihren Werten zu verknüpfen.

1- name: Publish Packer Image
2  id: publish
3  if: github.ref_type == 'tag'
4  run: ./scripts/promote.sh

Ausführung bei abgebrochenem Job

Manchmal wird ein Job abgebrochen oder es warten bereits neuere Commits in der Warteschlange. In diesem Fall möchten wir einige Bereinigungsschritte ausführen, falls bereits Ressourcen durch unseren Workflow-Lauf erstellt wurden.

Möglicherweise müssen Sie nachsehen, ob noch von Packer erstellte Maschinen laufen, oder ob Ihr Testcode bestimmte Ressourcen erstellt hat, die zerstört werden müssen.

Zum Beispiel können Sie innerhalb der Packer-Konfiguration Tags definieren, die diese Maschinen als Packer-bezogen markieren, vielleicht auch den Commit-Hash als Tag hinzufügen.

1- name: Execute if the job was cancelled
2  if: ${{ cancelled() }}
3  run: ./scripts/cancel.sh

ACT-Erweiterungen

Beim Lesen aller Blog-Beiträge werden Sie auf unseren act-Artikel stoßen, der es Ihnen ermöglicht, Ihre Github-Workflows auf Ihrer lokalen Maschine auszuführen. So müssen Sie keine andere Methode definieren, um die eigentlichen Schritte zum Erstellen der Maschinen während der Entwicklung Ihrer Playbooks und Definitionen auszuführen.

act injiziert eine Umgebungsvariable ACT, die für diesen Zweck verwendet werden kann.

1- name: Install Act dependencies
2  if: ${{ env.ACT != '' }}
3  run: |
4    apt-get update  && apt-get install -y $MISSING_ACT_PACKAGES    

Fazit

Dieser GitHub-Workflow ist umfassend und gut konzipiert, um den Packer-Image-Erstellungsprozess auf sichere und effiziente Weise zu automatisieren. Die Integration mit HashiCorp Vault für das Geheimnismanagement gewährleistet einen sicheren Umgang mit sensiblen Informationen, während die Multi-Cloud-Unterstützung, die Automatisierung von Tests und Bereinigungsprozessen ihn für eine Vielzahl von Anwendungsfällen geeignet machen. Insgesamt bietet der Workflow eine ausgewogene Mischung aus Flexibilität, Sicherheit und Automatisierung und ist eine starke Wahl für den Einsatz in CI/CD-Produktionspipelines.

Zurück Unsere Trainings entdecken

Wir sind für Sie da

Sie interessieren sich für unsere Trainings oder haben einfach eine Frage, die beantwortet werden muss? Sie können uns jederzeit kontaktieren! Wir werden unser Bestes tun, um alle Ihre Fragen zu beantworten.

Hier kontaktieren