<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Piotr Łagowski</title>
    <description>The latest articles on Forem by Piotr Łagowski (@gasparini16).</description>
    <link>https://forem.com/gasparini16</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F237003%2Fa11cb188-5241-47cb-9819-3df6bd6aad25.jpeg</url>
      <title>Forem: Piotr Łagowski</title>
      <link>https://forem.com/gasparini16</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/gasparini16"/>
    <language>en</language>
    <item>
      <title>Github Actions: how to deploy application to AWS ECS and migrate database with Flyway</title>
      <dc:creator>Piotr Łagowski</dc:creator>
      <pubDate>Tue, 14 May 2024 18:38:14 +0000</pubDate>
      <link>https://forem.com/gasparini16/github-actions-how-to-deploy-application-to-aws-ecs-and-migrate-database-with-flyway-14e3</link>
      <guid>https://forem.com/gasparini16/github-actions-how-to-deploy-application-to-aws-ecs-and-migrate-database-with-flyway-14e3</guid>
      <description>&lt;p&gt;Automatization is extremely important in the context of application development and this is where Github Actions will be great. In this article, we will focus on the necessary instructions to run a workflow that will perform the deployment of our application on AWS ECS and run the database migration using Flyway. An application built using the Spring Framework will be used as an example.&lt;/p&gt;

&lt;p&gt;The following instructions necessary for deployment have been developed for the deployment of &lt;a href="https://cresh.me" rel="noopener noreferrer"&gt;CRESH&lt;/a&gt;, a great platform for validating business ideas.&lt;/p&gt;

&lt;h1&gt;
  
  
  Adding secrets in Github Repo
&lt;/h1&gt;

&lt;p&gt;The first step will be to add secrets relating to information such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;aws user access key&lt;/li&gt;
&lt;li&gt;aws use secret access key&lt;/li&gt;
&lt;li&gt;datasource connection pool&lt;/li&gt;
&lt;li&gt;database username&lt;/li&gt;
&lt;li&gt;database password&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those fields are necessary for the deployment and database migration.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting workflow environment variables
&lt;/h1&gt;

&lt;p&gt;At the very beginning, we can define the environment variables that we will use in the workflow area. Below are the necessary variables that we will need for deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;env:
  ECR_REPOSITORY: &amp;lt;ecr_repo_name&amp;gt;
  ECS_SERVICE: &amp;lt;ecs_service_name&amp;gt;
  ECS_CLUSTER: &amp;lt;ecs_cluster_name&amp;gt;
  CONTAINER_NAME: &amp;lt;container_name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Action Steps
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Setup AWS CLI
&lt;/h3&gt;

&lt;p&gt;Logging into the AWS CLI is essential for the entire workflow. An Access Key and Secret Access Key can be created on the AWS Console for a specific user. Let's assume that for this article, a github_user user has been created to allow you to perform any action using the AWS CLI. Remember that the user you create on AWS should have the appropriate roles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: Setup AWS CLI
        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: eu-west-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setup Java
&lt;/h3&gt;

&lt;p&gt;A simple step that will be used to set the Java version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: Setup Java
        uses: actions/setup-java@v2
        with:
          distribution: 'adopt'
          java-version: '17'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setup Flyway
&lt;/h3&gt;

&lt;p&gt;Downloading and unpacking a specific version of the flyway. This will enable us to run the migration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      - name: Setup Flyway
        run: |
          curl -LJO https://repo1.maven.org/maven2/org/flywaydb/flyway-commandline/7.14.0/flyway-commandline-7.14.0-linux-x64.tar.gz
          tar xvzf flyway-commandline-7.14.0-linux-x64.tar.gz
          sudo mv flyway-7.14.0 /usr/local/flyway
          sudo ln -s /usr/local/flyway/flyway /usr/local/bin/flyway
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run Flyway Migration
&lt;/h3&gt;

&lt;p&gt;Start the migration process, in which it is necessary to provide database access secrets and indicate the location of the migration files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      - name: Run Flyway Migration
        run: |
          /usr/local/flyway/flyway -url=${{ secrets.SPRING_DATASOURCE_URL }} -user=${{ secrets.SPRING_DATASOURCE_USERNAME }} -password=${{ secrets.SPRING_DATASOURCE_PASSWORD }} -locations=filesystem:src/main/resources/database/migrations migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Login to Amazon ECR
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;And here app deployment starts!&lt;/strong&gt; &lt;a href="https://github.com/aws-actions" rel="noopener noreferrer"&gt;The AWS Github actions repo&lt;/a&gt; comes to your aid here. Logging can be done as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@62f4f872db3836360b72999f4b87f1ff13310f3a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Build and Push Docker Image to AWS ECR
&lt;/h3&gt;

&lt;p&gt;Building our application and pushing it to the AWS Elastic Container Registry. In order to build the application, you will need a Dockerfile, which will contain the maven command that prepares the jar file. Example Dockefile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Use an official Maven image as the build image with Java 17
FROM maven:3.8.4-openjdk-17-slim AS build

# Set the working directory in the container
WORKDIR /app

# Copy the project files into the container
COPY . .

# Build the application
RUN mvn clean install

# Use a lightweight JRE image with Java 17 as the final base image
FROM openjdk:17-jdk-slim

# Set the working directory in the container
WORKDIR /app

# Copy the JAR file from the build image to the runtime image
COPY --from=build /app/target/app_name.jar .

# Specify the command to run the application
CMD ["java", "-jar", "app_name.jar"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this step, we can also determine how we want to version the pushed image. In the example below, the timestamp will be used along with the short revision specifier, e.g: &lt;code&gt;2024.05.13_08-18-37-&amp;lt;git_rev&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      - name: Build and Push Docker Image to AWS ECR
        id: build-image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
        run: |
          VERSION="$(date +'%Y.%m.%d_%H-%M-%S')-$(git rev-parse --short HEAD)"
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$VERSION .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$VERSION
          echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$VERSION" &amp;gt;&amp;gt; $GITHUB_OUTPUT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Download task definition
&lt;/h3&gt;

&lt;p&gt;This step will download the existing task-definition file, which contains the necessary information about the container, including the Image ID.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      - name: Download task definition
        run: |
          aws ecs describe-task-definition --task-definition cresh-backend-ecs-task --query taskDefinition &amp;gt; task-definition.json
          echo "Docker Image URI: ${{ steps.build-image.outputs.image }}"
          replacement_image=${{ steps.build-image.outputs.image }}
          json_file="task-definition.json"
          jq --arg replacement_image "$replacement_image" '.containerDefinitions[0].image = $replacement_image' "$json_file" &amp;gt; tmp.json &amp;amp;&amp;amp; mv tmp.json "$json_file"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Fill the new Image ID in the Amazon ECS task definition
&lt;/h3&gt;

&lt;p&gt;Replacing the image ID in the downloaded task-definition.json file is necessary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      - name: Fill in the new image ID in the Amazon ECS task definition
        id: task-def
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: ./task-definition.json
          container-name: ${{ env.CONTAINER_NAME }}
          image: ${{ steps.build-image.outputs.image }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Trigger deployment
&lt;/h3&gt;

&lt;p&gt;Finally, the deployment process takes place by replacing the task definition file with the image ID we want to deploy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      - name: Deploy Amazon ECS task definition
        uses: aws-actions/amazon-ecs-deploy-task-definition@v1
        with:
          task-definition: ./task-definition.json
          service: ${{ env.ECS_SERVICE }}
          cluster: ${{ env.ECS_CLUSTER }}
          wait-for-service-stability: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;The above article provides the necessary instructions needed to create the workflow responsible for deploying the application on AWS ECS and migrating the database using Flyway. What do you think about this? Maybe you know other ways to build such a workflow? Share it in the comments!&lt;/p&gt;

&lt;h1&gt;
  
  
  Useful links
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://github.com/aws-actions" rel="noopener noreferrer"&gt;AWS Github Actions Repo&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html" rel="noopener noreferrer"&gt;Information about ECS&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.aws.amazon.com/AmazonECR/latest/userguide/what-is-ecr.html" rel="noopener noreferrer"&gt;Information about ECR&lt;/a&gt;&lt;/p&gt;

</description>
      <category>githubactions</category>
      <category>devops</category>
      <category>aws</category>
      <category>cloud</category>
    </item>
  </channel>
</rss>
