Activer le cache de construction de Docker dans GitHub Action et déployer sur Amazon ECS

Choses à faire

Créez une image Docker à l'aide de GitHub Action, enregistrez-la sur Amazon ECR et déployez-la sur Amazon ECS.

--Point

Préparation

--Créer un ECR de destination --Créer un ECR pour déployer --Créez un utilisateur AWS IAM à utiliser avec GitHub Action (nécessite les autorisations ECR et ECS)

Continuez avec ceux-ci comme créés.

Workflow pour créer

Créez un flux de travail comme celui ci-dessous et enregistrez-le dans .github / workflows / dans le référentiel avec un nom approprié tel que deploy-to-ecs.yml. En poussant la balise vers la branche principale, ce flux de travail fonctionne, l'image Docker est poussée vers ECR et déployée vers ECS. Opérez en utilisant la [Release] de Github (https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/managing-releases-in-a-repository) Je suppose que.

.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 #Paramètres d'autorisation d'accès AWS
        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 #Processus de connexion ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1

      - name: Set Docker Tag Env #Faire correspondre la version de l'image Docker à la balise
        run: echo "::IMAGE_TAG=$(echo ${{ github.ref }} | sed -e "s#refs/tags/##g")" >> $GITHUB_ENV

      - name: Build, tag, and push image to Amazon ECR #Construction d'image Docker&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 #Rendu du fichier de définition de tâche ECS du conteneur d'application
        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 #Déploiement du service ECS
        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

Commentaire

Le fonctionnement du workflow sera expliqué concrètement dans l'ordre du haut.

1. Nom du workflow

name: Deploy to ECS 

J'ai décidé du nom du workflow. Ce nom sera affiché lorsque vous vérifierez le flux de travail dans la liste à partir du référentiel Github ou de l'onglet Action. Lors de la création de plusieurs flux de travail dans un environnement de vérification ou un environnement de production, il est recommandé de modifier le nom afin qu'il soit facile à distinguer.

2. Conditions de fonctionnement du workflow

on:
  push:
    tags:
      - v*

Cela fonctionne lorsque les balises commençant par v telles que v1.0.0 sont poussées et Release On suppose que ce flux de travail fonctionnera en créant (/ github / administration-a-repository / manage-releases-in-a-repository). Aussi, cette fois dans les travaux afin que cela ne fonctionne pas si la balise est poussée vers une autre branche

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

Cela ne fonctionne pas si ce n'est pas la branche principale comme.

Pour le faire fonctionner lorsqu'il est poussé vers une branche spécifique, omettez la description de if

on:
  push:
    branches:
      - target-branch

Veuillez décrire comme. (Remplacez la branche cible par la branche à déployer.)

Supplément

Afin de se rendre compte que cela fonctionne quand une balise est poussée vers une branche spécifique par la méthode de description de on: push:

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

Si vous écrivez comme, ce sera une condition ou (lorsque la balise ou la branche est poussée) au lieu de la condition et, alors spécifiez la balise cible avec on: push: et cible avec if La branche de est spécifiée.

3. Affectation aux variables d'environnement

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

Il est affecté à une variable d'environnement pour réduire la description de la valeur qui est utilisée plusieurs fois dans le travail. Veuillez changer votre-〇〇〇-nom en celui de votre environnement

4. Commencez à exécuter des travaux

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

Vérifiez la branche cible dans l'environnement de ubuntu-latest et commencez à exécuter le travail. (Comme mentionné précédemment, la ligne if est écrite de sorte qu'elle ne sera exécutée que dans la branche principale lorsque l'étiquette est poussée. Il n'est pas nécessaire si la condition de fonctionnement est modifiée de pousser dans la branche.)

5. Connectez-vous à AWS

- name: Configure AWS Credentials #Paramètres d'autorisation d'accès AWS
    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

Je suis connecté au compte AWS qui a créé l'ECR à pousser et l'ECS à déployer. Déployez à l'aide de Github's Secret (https://docs.github.com/en/free-pro-team@latest/actions/reference/encrypted-secrets) Accès IAM et clés secrètes AWS_ACCESS_KEY_ID Veuillez vous inscrire avec et AWS_SECRET_ACCESS_KEY.

6. Connexion ECR

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

Connectez-vous à ECR pour le compte AWS que vous avez connecté à l'étape 5.

7. Paramètres de balise d'image Docker

  - name: Set Docker Tag Env #Faire correspondre la version de l'image Docker à la balise
    run: echo "::IMAGE_TAG=$(echo ${{ github.ref }} | sed -e "s#refs/tags/##g")" >> $GITHUB_ENV

La balise poussée pour que la balise image de Docker ait la même valeur que la balise de git est retirée dans un format comme v1.0.0 et affectée à la variable d'environnement. Si vous n'utilisez pas de balises dans les conditions de fonctionnement du workflow,

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

Je pense que c'est une bonne idée d'utiliser un hachage de validation pour rendre la balise d'image unique.

8. Créer une image Docker et pousser vers ECR

  - name: Build, tag, and push image to Amazon ECR #Construction d'image Docker&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

Lors de la création d'une image Docker localement, la génération accélère à l'aide de l'image précédemment créée, mais GitHub Action ne conserve pas le résultat de la génération précédente, donc la génération prend du temps à chaque fois. Par conséquent, ici, docker build --cache-from de Docker est utilisé pour accélérer la construction. Ce que nous faisons est de créer une image docker, en poussant la balise enregistrée dans la variable d'environnement IMAGE_TAG, et la valeur changera dynamiquement pour chaque opération de workflow, et la valeur au moment de la construction précédente sera utilisée. Comme il est difficile de l'obtenir, je pousse également la dernière balise et utilise la dernière balise pour la mise en cache. En faisant cela, le cache peut être utilisé tout en étant cohérent avec la balise release. (DOCKER_BUILDKIT, BUILDKIT_INLINE_CACHE est décrit car il est nécessaire d'utiliser --cache-from.) Remarque: Si vous utilisez la génération en plusieurs étapes de Docker, vous ne pouvez pas mettre en cache cette méthode car l'image Docker n'inclut pas l'ensemble du processus de génération. Dans ce cas, je pense que vous devriez vous référer aux Articles comme celui-ci.

9. Créer une définition de tâche ECS

- name: Render Amazon ECS task definition for app container #Rendu du fichier de définition de tâche ECS du conteneur d'application
    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 }}

Pour exécuter ECS, une définition de tâche est requise et il est nécessaire de décrire le référentiel et les informations de balise de l'image Docker à utiliser. Par conséquent, lors de la mise à jour de DockerImage, il est également nécessaire de mettre à jour la définition de tâche, et ce processus est en cours d'exécution.

今回はレポジトリへタスク定義ファイル.aws/ecs/task-definition.jsonを作成してあり、そのファイルを呼び出し、Dockerイメージの情報を更新しています。 Exemple de référence de 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"
}

Lire depuis s3 semble être possible, alors veuillez gérer chaque définition de tâche que vous aimez.

10. Déployer sur ECS

- name: Deploy to Amazon ECS service #Déploiement du service ECS
    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

Il est déployé sur ECS en fonction de la définition de tâche créée dans 9. En définissant wait-for-service-stabilite sur true, il est possible d'attendre la fin de l'exécution jusqu'à ce que le déploiement soit terminé et de notifier la fin du déploiement, mais le temps d'exécution des actions Github augmentera. Il est possible qu'il dépasse le cadre d'exécution. Il est également possible de suspendre l'achèvement du déploiement à l'aide d'AWS Lambda et de le notifier, il est donc recommandé de le faire dans un environnement avec de nombreux déploiements.

11. Fin

Si le flux ci-dessus fonctionne correctement, le déploiement est terminé.

Bonus. Exécution de la tâche seule

- name: Run Migrate #Lancer la migration
    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

Je voulais migrer la base de données avant de déployer cette fois, j'ai donc ajouté un tel travail à l'ECS à l'étape 10 avant de déployer et d'exécuter la tâche seule. En faisant cela, il est également possible d'exécuter une seule tâche dans Github Actions.

Sommaire

Lors du déploiement sur ECS, je pense qu'il existe des options telles que la combinaison d'AWS CodeBuild et d'AWS CodePipeline, mais il est également possible de déployer facilement à l'aide de GitHub Action.

Article de référence

J'ai beaucoup fait référence à l'article suivant.

Recommended Posts

Activer le cache de construction de Docker dans GitHub Action et déployer sur Amazon ECS
Exécutez Rubocop et RSpec sur CircleCI et déployez-le sur ECS
Jusqu'à ce que vous exécutiez Quarkus et que vous exécutiez l'image docker sur Amazon ECS
Déployer des rails sur Docker vers heroku
Essayez de créer un environnement Java 8 sur Amazon Linux2
Tester, créer et pousser des images Docker vers GitHub Container Registry à l'aide d'actions GitHub
Cachez les fichiers dépendants de Gradle pour accélérer la construction du docker
Comment déployer avec heroku
Installez Ubuntu20.04 sur RaspberryPi 4 et compilez Kubernetes pour exécuter le conteneur
Utilisez Jenkins pour créer dans Docker, puis créez une image Docker.