Aktivieren Sie den Build-Cache von Docker in GitHub Action und stellen Sie ihn auf Amazon ECS bereit

Dinge die zu tun sind

Erstellen Sie mit GitHub Action ein Docker-Image, speichern Sie es in Amazon ECR und stellen Sie es in Amazon ECS bereit.

--Punkt

Vorbereitung

--Erstellen Sie eine Ziel-ECR --Erstellen Sie eine ECR, für die die Bereitstellung erfolgen soll --Erstellen Sie einen AWS IAM-Benutzer zur Verwendung mit GitHub Action (erfordert ECR- und ECS-Berechtigungen).

Fahren Sie mit diesen wie erstellt fort.

Zu erstellender Workflow

Erstellen Sie einen Workflow wie den folgenden und speichern Sie ihn in ".github / workflows /" im Repository mit einem geeigneten Namen wie "deploy-to-ecs.yml". Durch Verschieben des Tags in den Hauptzweig funktioniert dieser Workflow. Das Docker-Image wird in ECR verschoben und in ECS bereitgestellt. Verwenden Sie Githubs Release. Ich gehe davon aus.

.github/workflows/deploy-to-ecs.yml

name: Deploy to ECS 
on:
  push:
    tags:
      - v*

env:
  ECR_REPOSITORY: your-repository-name
  ECS_SERVICE: your-service-name
  ECS_CLUSTER: your-cluster-name

jobs:
  deploy:
    name: Deploy to ECS
    if: github.event.base_ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Configure AWS Credentials #AWS-Zugriffsberechtigungseinstellungen
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1

      - name: Login to Amazon ECR #ECR-Anmeldevorgang
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1

      - name: Set Docker Tag Env #Ordnen Sie die Docker Image-Version dem Tag zu
        run: echo "::IMAGE_TAG=$(echo ${{ github.ref }} | sed -e "s#refs/tags/##g")" >> $GITHUB_ENV

      - name: Build, tag, and push image to Amazon ECR #Docker Image Build&Push
        env:
          DOCKER_BUILDKIT: 1
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
        run: |
          docker build --cache-from=$ECR_REGISTRY/$ECR_REPOSITORY:latest --build-arg BUILDKIT_INLINE_CACHE=1 -f Dockerfile -t $ECR_REPOSITORY .
          docker tag $ECR_REPOSITORY:latest $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          docker tag $ECR_REPOSITORY:latest $ECR_REGISTRY/$ECR_REPOSITORY:latest
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest

      - name: Render Amazon ECS task definition for app container #Rendering der ECS-Taskdefinitionsdatei des App-Containers
        id: render-app-container
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: .aws/ecs/task-definition.json
          container-name: app
          image: ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }}

      - name: Deploy to Amazon ECS service #Bereitstellung von ECS-Diensten
        uses: aws-actions/amazon-ecs-deploy-task-definition@v1
        with:
          task-definition: ${{ steps.render-app-container.outputs.task-definition }}
          service: ${{ env.ECS_SERVICE }}
          cluster: ${{ env.ECS_CLUSTER }}
          wait-for-service-stability: false

Kommentar

Die Funktionsweise des Workflows wird in der Reihenfolge von oben konkret erläutert.

1. Name des Workflows

name: Deploy to ECS 

Ich habe mich für den Namen des Workflows entschieden. Dieser Name wird angezeigt, wenn Sie den Workflow in der Liste auf der Registerkarte Github-Repository oder Aktion überprüfen. Wenn Sie mehrere Workflows in einer Verifizierungsumgebung oder Produktionsumgebung erstellen, wird empfohlen, den Namen so zu ändern, dass er leicht zu unterscheiden ist.

2. Arbeitsablaufbedingungen

on:
  push:
    tags:
      - v*

Es funktioniert, wenn Tags, die mit v beginnen, wie z. B. v1.0.0, verschoben werden und Release Es wird davon ausgegangen, dass dieser Workflow durch Erstellen von (/ github / Administration-a-Repository / Verwalten von Releases in einem Repository) funktioniert. Auch diesmal in Jobs, so dass es nicht funktioniert, wenn das Tag in einen anderen Zweig verschoben wird

if: github.event.base_ref == 'refs/heads/main'

Es funktioniert nicht, wenn es nicht der Hauptzweig ist.

Lassen Sie die Beschreibung von "if" weg, damit es funktioniert, wenn es in einen bestimmten Zweig verschoben wird

on:
  push:
    branches:
      - target-branch

Bitte beschreiben Sie als. (Ändern Sie den Zielzweig in den Zweig, der bereitgestellt werden soll.)

Ergänzung

Um zu erkennen, dass es funktioniert, wenn ein Tag mit der Beschreibungsmethode "on: push:" in einen bestimmten Zweig verschoben wird

on:
  push:
    tags:
      - v*
     branches:
      - target-branch

Wenn Sie wie schreiben, ist dies eine oder Bedingung (wenn entweder das Tag oder der Zweig verschoben wird) anstelle der Bedingung und. Geben Sie daher das Ziel-Tag mit on: push: und das Ziel mit if an Der Zweig von ist angegeben.

3. Zuordnung zu Umgebungsvariablen

env:
  ECR_REPOSITORY: your-repository-name
  ECS_SERVICE: your-service-name
  ECS_CLUSTER: your-cluster-name

Es wird einer Umgebungsvariablen zugewiesen, um die Beschreibung des Werts zu reduzieren, der im Job häufig verwendet wird. Bitte ändern Sie "Ihr-Name" in den Namen in Ihrer Umgebung

4. Starten Sie Jobs

jobs:
  deploy:
    name: Deploy to ECS
    if: github.event.base_ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

Überprüfen Sie den Zielzweig in der Umgebung von "ubuntu-latest" und beginnen Sie mit der Ausführung des Jobs. (Wie bereits erwähnt, wird die "if" -Zeile so geschrieben, dass sie nur im Hauptzweig ausgeführt wird, wenn das Tag verschoben wird. Dies ist nicht erforderlich, wenn die Betriebsbedingung geändert wird, um den Zweig zu verschieben.)

5. Melden Sie sich bei AWS an

- name: Configure AWS Credentials #AWS-Zugriffsberechtigungseinstellungen
    uses: aws-actions/configure-aws-credentials@v1
    with:
      aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
      aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      aws-region: ap-northeast-1

Ich bin bei dem AWS-Konto angemeldet, das die ECR zum Pushen und das ECS zum Bereitstellen erstellt hat. Bereitstellung mithilfe von Githubs Secret (https://docs.github.com/de/free-pro-team@latest/actions/reference/encrypted-secrets) IAM-Zugriff und geheimen Schlüsseln AWS_ACCESS_KEY_ID Bitte registrieren Sie sich mit und AWS_SECRET_ACCESS_KEY.

6. ECR-Login

 - name: Login to Amazon ECR #ECR-Anmeldevorgang
    id: login-ecr
    uses: aws-actions/amazon-ecr-login@v1

Melden Sie sich bei der ECR des AWS-Kontos an, das Sie in Schritt 5 angemeldet haben.

7. Docker-Image-Tag-Einstellungen

  - name: Set Docker Tag Env #Ordnen Sie die Docker Image-Version dem Tag zu
    run: echo "::IMAGE_TAG=$(echo ${{ github.ref }} | sed -e "s#refs/tags/##g")" >> $GITHUB_ENV

Das Tag wurde so verschoben, dass das Image-Tag von Docker denselben Wert hat wie das Tag von git. Es wird in einem Format wie "v1.0.0" entfernt und der Umgebungsvariablen zugewiesen. Wenn Sie unter den Betriebsbedingungen des Workflows keine Tags verwenden,

run: echo "::IMAGE_TAG=${{ github.sha }}" >> $GITHUB_ENV

Ich denke, es ist eine gute Idee, einen Commit-Hash zu verwenden, um das Image-Tag einzigartig zu machen.

8. Erstellen Sie ein Docker-Image und drücken Sie auf ECR

  - name: Build, tag, and push image to Amazon ECR #Docker Image Build&Push
    env:
      DOCKER_BUILDKIT: 1
      ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
    run: |
      docker build --cache-from=$ECR_REGISTRY/$ECR_REPOSITORY:latest --build-arg BUILDKIT_INLINE_CACHE=1 -f Dockerfile -t $ECR_REPOSITORY .
      docker tag $ECR_REPOSITORY:latest $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
      docker tag $ECR_REPOSITORY:latest $ECR_REGISTRY/$ECR_REPOSITORY:latest
      docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
      docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest

Wenn Sie ein Docker-Image lokal erstellen, wird der Build mit dem zuvor erstellten Image beschleunigt, aber GitHub Action behält das vorherige Build-Ergebnis nicht bei, sodass die Erstellung jedes Mal einige Zeit in Anspruch nimmt. Daher wird hier Dockers "Docker-Build --cache-from" verwendet, um den Build zu beschleunigen. Wir erstellen ein Docker-Image, verschieben das in der Umgebungsvariablen IMAGE_TAG gespeicherte Tag und der Wert ändert sich dynamisch für jede Workflow-Operation, sodass der Wert zum Zeitpunkt des vorherigen Builds verwendet wird. Da es schwierig ist, es zu bekommen, drücke ich auch das neueste Tag und verwende das neueste Tag für das Caching. Auf diese Weise kann der Cache verwendet werden, während er mit dem Release-Tag übereinstimmt. (DOCKER_BUILDKIT, BUILDKIT_INLINE_CACHE wird beschrieben, da --cache-from verwendet werden muss.) Hinweis: Wenn Sie den mehrstufigen Build von Docker verwenden, können Sie diese Methode nicht zwischenspeichern, da das Docker-Image nicht den gesamten Build-Prozess enthält. In diesem Fall sollten Sie sich auf [Artikel wie diesen] beziehen (https://engineer.recruit-lifestyle.co.jp/techblog/2020-09-25-docker-build/).

9. Erstellen Sie eine ECS-Aufgabendefinition

- name: Render Amazon ECS task definition for app container #Rendering der ECS-Taskdefinitionsdatei des App-Containers
    id: render-app-container
    uses: aws-actions/amazon-ecs-render-task-definition@v1
    with:
      task-definition: .aws/ecs/task-definition.json
      container-name: app
      image: ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ env.IMAGE_TAG }}

Um ECS auszuführen, ist eine Aufgabendefinition erforderlich, und es ist erforderlich, die Repository- und Tag-Informationen des Docker-Images zu beschreiben, das dort verwendet werden soll. Daher ist es beim Aktualisieren von DockerImage auch erforderlich, die Aufgabendefinition zu aktualisieren, und dieser Prozess wird ausgeführt.

今回はレポジトリへタスク定義ファイル.aws/ecs/task-definition.jsonを作成してあり、そのファイルを呼び出し、Dockerイメージの情報を更新しています。 Referenzbeispiel für task-definition.json)

{
  "containerDefinitions": [
      "portMappings": [
        {
          "hostPort": 80,
          "protocol": "tcp",
          "containerPort": 80
        }
      ],
      "image": "your-image-name",
      "name": "app"
    }
  ],
  "cpu": "256",
  "executionRoleArn": "your-role-name",
  "family": "your-family",
  "memory": "512",
  "requiresCompatibilities": [
    "FARGATE"
  ],
  "networkMode": "awsvpc"
}

Lesen von s3 scheint möglich zu sein. Verwalten Sie daher bitte jede Aufgabendefinition, die Sie mögen.

10. In ECS bereitstellen

- name: Deploy to Amazon ECS service #Bereitstellung von ECS-Diensten
    uses: aws-actions/amazon-ecs-deploy-task-definition@v1
    with:
      task-definition: ${{ steps.render-app-container.outputs.task-definition }}
      service: ${{ env.ECS_SERVICE }}
      cluster: ${{ env.ECS_CLUSTER }}
      wait-for-service-stability: false

Es wird auf der Grundlage der in 9 erstellten Aufgabendefinition für ECS bereitgestellt. Wenn Sie "Wait-for-Service-Stability" auf "true" setzen, können Sie auf den Abschluss der Ausführung warten, bis die Bereitstellung abgeschlossen ist, und den Abschluss der Bereitstellung benachrichtigen. Die Ausführungszeit von Github-Aktionen erhöht sich jedoch. Es besteht die Möglichkeit, dass der Ausführungsrahmen überschritten wird. Es ist auch möglich, den Abschluss der Bereitstellung mit AWS Lambda zu verknüpfen und zu benachrichtigen. Daher wird empfohlen, dies in einer Umgebung mit vielen Bereitstellungen zu tun.

11. Ende

Wenn der obige Ablauf ordnungsgemäß funktioniert, ist die Bereitstellung abgeschlossen.

Bonus. Ausführung der Aufgabe allein

- name: Run Migrate #Führen Sie die Migration aus
    env:
      CLUSTER_ARN: your_cluster_arn
      ECS_SUBNER_FIRST: your_subnet_first
      ECS_SUBNER_SECOND: your_subner_second
      ECS_SECURITY_GROUP: your_security_group
    run: |
      aws ecs run-task --launch-type FARGATE --cluster $ECS_CLUSTER --task-definition ${{ steps.put-migrate-task.outputs.render-app-container }} --network-configuration "awsvpcConfiguration={subnets=[$ECS_SUBNER_FIRST, $ECS_SUBNER_SECOND],securityGroups=[$ECS_SECURITY_GROUP],assignPublicIp=ENABLED}" > run-task.log
      TASK_ARN=$(jq -r '.tasks[0].taskArn' run-task.log)
      aws ecs wait tasks-stopped --cluster $CLUSTER_ARN --tasks $TASK_ARN

Ich wollte die Datenbank vor der Bereitstellung dieses Mal migrieren, daher habe ich in Schritt 10 einen solchen Job zum ECS hinzugefügt, bevor ich die Aufgabe allein bereitgestellt und ausgeführt habe. Auf diese Weise ist es auch möglich, eine einzelne Aufgabe in Github-Aktionen auszuführen.

Zusammenfassung

Bei der Bereitstellung in ECS gibt es meiner Meinung nach Optionen wie das Kombinieren von AWS CodeBuild und AWS CodePipeline, aber es ist auch möglich, die Bereitstellung einfach mit GitHub Action durchzuführen.

Referenzartikel

Ich habe sehr viel auf den folgenden Artikel verwiesen.

Recommended Posts

Aktivieren Sie den Build-Cache von Docker in GitHub Action und stellen Sie ihn auf Amazon ECS bereit
Führen Sie Rubocop und RSpec auf CircleCI aus und stellen Sie es in ECS bereit
Bis Sie Quarkus ausführen und Docker-Image auf Amazon ECS ausführen
Stellen Sie Rails on Docker für Heroku bereit
Versuchen Sie, eine Java 8-Umgebung unter Amazon Linux2 zu erstellen
Testen, erstellen und verschieben Sie Docker-Images mithilfe von GitHub-Aktionen in die GitHub-Container-Registrierung
Cache Gradle-abhängige Dateien, um die Docker-Erstellung zu beschleunigen
Wie man mit Heroku einsetzt
Installieren Sie Ubuntu20.04 auf RaspberryPi 4 und erstellen Sie Kubernetes, um den Container auszuführen
Verwenden Sie Jenkins, um in Docker zu erstellen und dann ein Docker-Image zu erstellen.