This post will write about Docker, AWS ECR, ECS, Fargate, RDS, and Github Action.

Contents

Overview

Getting Start AWS

  • Step 1. Create AWS Account

  • Step 2. Create IAM Account

Create Amazon ECR

Create Amazon ECS

Create Amazon RDS

Deploy: Push your Docker Image

  • Option 1. AWS Command line tool on macOS

    • Fargate Task Pending Issue!!

    • Try to access the Vapor app on Web Browser

  • Option 2. Github Action

 

MEMO

I’m not a DevOps or backend engineer. Before posting it, I read books about AWS and Server-Side Swift and tutorials and took advice from friends who work as backend engineers.

 

Overview

overview.png

To deploy the vapor docker container, I’ll use AWS services.

You can push your docker image to the ECR. And then, ECS pull your docker image by setting the ECR URI. ECS launch docker container on AWS. Also, It has integration with Load Balancer. The Fargate is a task of ECS. It is responsible for offering serverless. You can set memory and CPU for containers.

Getting Start AWS

Step 1. Create AWS Account

If you haven’t an account yet, let’s create a new account.

newAws.png

enterInfo.png

accountType.png

creditcard.png

Now You have an AWS account. This account is called a root account.

 

Step 2. Create IAM Account

Log in as root account. And then search the IAM at the top of the search bar.

searchIAM.png

Before creating IAM Account, Let’s make the group for users. I captured all of the steps. You just followed the steps below.

Create Groups

createGroup.png

Enter the group name you want to use it.

Enter the group name you want to use it.

attachPolicyType.png

checkGroup.png

confirm.png

You created the group. As you can see, there are no Users in the group. Let’s create an IAM account and add it to the group we made.

Create IAM Account

addUser.png

setUserDetail.png

addUserGoup.png

addTag.png

review.png

privateKey.png

Don’t forget to download .csv file. To access AWS using the CLI tool, you need to set accessKey, secretKey, and console login link.

Now You have an IAM Account. In the AWS document, You should not use the root account for creating the other services. You can use the root account when managing users (IAM service) and billings. 

That’s all about the root account’s role. Please log out root account now. And login with an IAM account you created to create an ECR, ECS, Fargate, and RDS services.

You can check the IAM account login URL in the above screenshot.(e.g,  https://xxxxx.signin.aws.amazon.com/console)

iam login.png

If you forgot the accountID(12 digits), you log in as a root account and check your accountID(12 digits).

If you forgot the accountID(12 digits), you log in as a root account and check your accountID(12 digits).

You will see your 12 digits of account id in the blue box above the screenshot.

You will see your 12 digits of account id in the blue box above the screenshot.

 

Create Amazon ECR

ecr_overview.png

ECR is a repository for Docker Images like Docker Hub. You can push and pull your Docker images and set version tags. The default setting is private, and also you can select a public repository.

Search the ECR at the top of the search bar and create a repository.

Search the ECR at the top of the search bar and create a repository.

Set the repository name you want.

Set the repository name you want.

That's it. Click the Create repository button.

That’s it. Click the Create repository button.

Wait a few seconds. You will see the repository you created. Now You are ready to push your Docker image to the ECR.

Wait a few seconds. You will see the repository you created. Now You are ready to push your Docker image to the ECR.

 

Create Amazon ECS

Now You need to create an ECS cluster and task to run your Docker Image in ECR.

Copy your ECR URI. (We will use this URI:latest as an image URI)

Copy your ECR URI. (We will use this URI:latest as an image URI)

Select the ECS Clusters and Click the Get started button.

Select the ECS Clusters and Click the Get started button.

3.png

Paste your ECR URI you copied. e.g., ecrUri:latest

Paste your ECR URI you copied. e.g., ecrUri:latest

5.png

Expand the Advanced Container Configuration. Scroll down to Environment section. Remove the default settings in the blue box above the screenshot.

Expand the Advanced Container Configuration. Scroll down to Environment section. Remove the default settings in the blue box above the screenshot.

7.png

Enter the task definition name you want.

Enter the task definition name you want.

9.png

10.png

11.png

 

Create Amazon RDS

To set up a database for your vapor app, You have to create an RDS service database. Search for the RDS keyword at the top of the search bar.

1.png

I'll use PostgreSQL. (Select database you want to use for vapor app)

I’ll use PostgreSQL. (Select database you want to use for vapor app)

3.png

4.png

Set your ECS VPC. The subgroup is automatically updated when you select the VPC.

Set your ECS VPC. The subgroup is automatically updated when you select the VPC.

Create New VPC security group to set the inbound for PostgreSQL default port 5432.

Create New VPC security group to set the inbound for PostgreSQL default port 5432.

7.png

That's it. You can check the database you create.

That’s it. You can check the database you create.

 

Deploy: Push your Docker Image

I’ll show you how to push your Docker image to the ECR. There are two options. Choose the option you like.

# Build image
FROM swift:5.3.2-focal as build

RUN apt-get update -y \
    && apt-get install -y libsqlite3-dev

WORKDIR /build

COPY . .

RUN swift build \
    --enable-test-discovery \
    -c release \
    -Xswiftc -g

# Run image
FROM swift:5.3.2-focal-slim

RUN useradd --user-group --create-home --home-dir /app vapor

WORKDIR /app

COPY --from=build --chown=vapor:vapor /build/.build/release /app
COPY --from=build --chown=vapor:vapor /build/Public /app/Public
COPY --from=build --chown=vapor:vapor /build/Resources /app/Resources

# ARS RDS Environment ARG
ARG AWS_RDS_HOST
ARG AWS_RDS_PORT
ARG AWS_RDS_USER
ARG AWS_RDS_PASS
ARG AWS_RDS_DB

# SignInWithApple Environment ARG
ARG SIWA_ID
ARG SIWA_REDIRECT_URL
ARG SIWA_JWK_ID
ARG SIWA_PRIVATE_KEY
ARG SIWA_TEAM_ID
ARG SIWA_APP_BUNDLE_ID

# Set Environment
RUN echo "SIWA_ID=${SIWA_ID}" > .env.production
RUN echo "SIWA_REDIRECT_URL=${SIWA_REDIRECT_URL}" >> .env.production
RUN echo "SIWA_JWK_ID=${SIWA_JWK_ID}" >> .env.production
RUN echo "SIWA_PRIVATE_KEY=${SIWA_PRIVATE_KEY}" >> .env.production
RUN echo "SIWA_TEAM_ID=${SIWA_TEAM_ID}" >> .env.production
RUN echo "SIWA_APP_BUNDLE_ID=${SIWA_APP_BUNDLE_ID}" >> .env.production

RUN echo "DB_HOST=${AWS_RDS_HOST}" >> .env.production
RUN echo "DB_PORT=${AWS_RDS_PORT}" >> .env.production
RUN echo "DB_USER=${AWS_RDS_USER}" >> .env.production
RUN echo "DB_PASS=${AWS_RDS_PASS}" >> .env.production
RUN echo "DB_NAME=${AWS_RDS_DB}" >> .env.production

USER vapor

# Export Port
EXPOSE 8080

ENTRYPOINT ["./Run"]
CMD ["serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8080"]

The code is my Dockerfile for the Vapor app. I’ll write the post about server-side swift. In this post, I focused on deploying the Docker Image to AWS. Don’t forget to export 8080.

 

Option 1. AWS Command line tool on macOS

Install AWS cli tool on macOS

1.png

2.png

Download the pkg file and install it. You don’t need to set the installation path. Just click the continue button until the installation is completed.

Open the terminal and check the CLI tool.

Open the terminal and check the CLI tool.

Deploy the Docker image using the CLI tool.

Let’s create a `deploy.sh` file in the path which has Dockerfile.

#!/bin/bash
#Set Variables
containerName="Enter your ECR Repository name"
ecrURI="EnterYour12DigitNumber.dkr.ecr.YourRegion.amazonaws.com/${containerName}"

echo "Step 1. Setup AWS Config"

aws configure set aws_access_key_id YourAccessKey --profile default
aws configure set aws_secret_access_key YourSecretKey --profile default
aws configure set region YourRegion --profile default

echo "Step 2. AWS ECR Login"
aws ecr get-login-password --region YourRegion | docker login --username AWS --password-stdin $ecrURI


echo "Step 3. Build Docker Image"
 docker build \
--build-arg SIWA_ID=SignInWithAppleID \
--build-arg SIWA_REDIRECT_URL=SetYourRedirectUrlForSignInWithApple \
--build-arg SIWA_JWK_ID=YourJWKIDForSignInWithApple \
--build-arg SIWA_PRIVATE_KEY=YourSignInWithApplePrivateKey \
--build-arg SIWA_TEAM_ID=YourSignInWithAppleTeamId \
--build-arg SIWA_APP_BUNDLE_ID=YourAppBundleId \
--build-arg AWS_RDS_HOST=YourRDSHostUrl \
--build-arg AWS_RDS_PORT=5432 \
--build-arg AWS_RDS_USER=YourRDSUserName \
--build-arg AWS_RDS_PASS=YourRDSPassword \
--build-arg AWS_RDS_DB=YourRDSDatabaseName \
-t "${containerName}:latest" -f Dockerfile .

echo "Step 4. Set tag on Docker Image"
docker tag "${containerName}:latest" "${ecrURI}:latest"

echo "Step 5. Push Docker Image to AWS ECR"
# docker push "vapor-app-image:latest"
docker push "${ecrURI}:latest"

Set your containerName and region. You can check these names on Amazon ECR.

Set your containerName and region. You can check these names on Amazon ECR.

Step 1. You can check the access key and secret key in the CSV file of the IAM Account you create.

Step 1. You can check the access key and secret key in the CSV file of the IAM Account you create.

aws_rds_host.png

Step 3. Check your RDS values on the RDS Database settings.

Step 3. Check your RDS values on the RDS Database settings.

sh ./deploy.sh

run1.png

run2.png

Let’s run the deploy script and check the result. There is no issue, and You pushed the Docker image to the ECR successfully.

You can see the image you pushed. If you want to check the command for push image using CLI, click the View push commands above the screenshot.

You can see the image you pushed. If you want to check the command for push image using CLI, click the View push commands above the screenshot.

 

Fargate Task Pending Issue!!

You pushed the Docker image to the ECR. The ECS Fargate task is automatically started to run the Vapor container. Let's check the Fargate task's status. You may find-out the problem. Its status is pending. Why?

You pushed the Docker image to the ECR. The ECS Fargate task is automatically started to run the Vapor container. Let’s check the Fargate task’s status. You may find-out the problem. Its status is pending. Why?

You didn't set the inbound rule for your ECS VPC. Let's put the inbound rule of the security group on RDS for ECS VPC.

You didn’t set the inbound rule for your ECS VPC. Let’s put the inbound rule of the security group on RDS for ECS VPC.

2.png

3.png

Add custom TCP 5432 PORT. Don't forget to select the source as your ECS Container Security Group.

Add custom TCP 5432 PORT. Don’t forget to select the source as your ECS Container Security Group.

Let's recheck the Fargate task. Its status is updated to Running. You resolve the RDS accessing problem!

Let’s recheck the Fargate task. Its status is updated to Running. You resolve the RDS accessing problem!

detail1.png

detail2.png

You can also check the log in the CloudWatch service. Your server is running now.

You can also check the log in the CloudWatch service. Your server is running now.

 

Try to access the Vapor app on Web Browser

Let’s check the public IP and access the Vapor app on the Web Browser.

check1.png

check2.png

Hmm, You can't access the server. The problem is that you didn't allow the 8080 port in the Cluster's security group.Let's resolve this issue.

Hmm, You can’t access the server. The problem is that you didn’t allow the 8080 port in the Cluster’s security group.

Let’s resolve this issue.

 

1.png

2.png

3.png

4.png

That's all. Now You can access the vapor app on Safari. Let's recheck it.

That’s all. Now You can access the vapor app on Safari. Let’s recheck it.

You resolve the access problem!

You resolve the access problem!

 

Option 2. Github Action

You can also set the deploy Docker Image using Github Action. Let’s set up. Before reading this section, I have to say that the setting of Github Action has one issue. I have almost done it except building Docker Image. If you want to try my setup, let’s keep follow my instruction.

Click the New workflow on your GitHub repository.

Click the New workflow on your GitHub repository.

2.png

I'll use the Deploy to Amazon ECS template.

I’ll use the Deploy to Amazon ECS template.

In the YML file, You can see the ${{ secrets.KEY }}. This KEY is Secret Environment Variables. You can set the values on your repository Settings tap.

In the YML file, You can see the ${{ secrets.KEY }}. This KEY is Secret Environment Variables. You can set the values on your repository Settings tap.

5.png

Set the Environment Variable Name and Value.

Set the Environment Variable Name and Value.

That’s it.

That’s it.

# This workflow will build and push a new container image to Amazon ECR,
# and then will deploy a new task definition to Amazon ECS, when a release is created
#
# To use this workflow, you will need to complete the following set-up steps:
#
# 1. Create an ECR repository to store your images.
#    For example: `aws ecr create-repository --repository-name my-ecr-repo --region us-east-2`.
#    Replace the value of `ECR_REPOSITORY` in the workflow below with your repository's name.
#    Replace the value of `aws-region` in the workflow below with your repository's region.
#
# 2. Create an ECS task definition, an ECS cluster, and an ECS service.
#    For example, follow the Getting Started guide on the ECS console:
#      https://us-east-2.console.aws.amazon.com/ecs/home?region=us-east-2#/firstRun
#    Replace the values for `service` and `cluster` in the workflow below with your service and cluster names.
#
# 3. Store your ECS task definition as a JSON file in your repository.
#    The format should follow the output of `aws ecs register-task-definition --generate-cli-skeleton`.
#    Replace the value of `task-definition` in the workflow below with your JSON file's name.
#    Replace the value of `container-name` in the workflow below with the name of the container
#    in the `containerDefinitions` section of the task definition.
#
# 4. Store an IAM user access key in GitHub Actions secrets named `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.
#    See the documentation for each action used below for the recommended IAM policies for this IAM user,
#    and best practices on handling the access key credentials.

on:
  push:        
     branches: [ master ]
name: Deploy to Amazon ECS

jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest

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

    - name: Configure AWS credentials
      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: us-east-2

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

    - name: Build, tag, and push image to Amazon ECR
      id: build-image
      env:
        ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
        ECR_CONTAINER_NAME: ${{ secrets.AWS_ECS_CONTAINER_NAME }}
        IMAGE_TAG: latest
      run: |
        # Build a docker container and
        # push it to ECR so that it can
        # be deployed to ECS.
        docker build \
          --build-arg SIWA_ID=${{ secrets.SIWA_ID }} \ 
          --build-arg SIWA_REDIRECT_URL=${{ secrets.SIWA_REDIRECT_URL }} \
          --build-arg SIWA_JWK_ID=${{ secrets.SIWA_JWK_ID }} \
          --build-arg SIWA_PRIVATE_KEY=${{ secrets.SIWA_PRIVATE_KEY }} \
          --build-arg SIWA_TEAM_ID=${{ secrets.SIWA_TEAM_ID }} \
          --build-arg SIWA_APP_BUNDLE_ID=${{ secrets.SIWA_APP_BUNDLE_ID }} \
          --build-arg AWS_RDS_HOST=${{ secrets.AWS_RDS_HOST }} \ 
          --build-arg AWS_RDS_PORT=${{ secrets.AWS_RDS_PORT }} \
          --build-arg AWS_RDS_USER=${{ secrets.AWS_RDS_USER }} \
          --build-arg AWS_RDS_PASS=${{ secrets.AWS_RDS_PASS }} \
          --build-arg AWS_RDS_DB=${{ secrets.AWS_RDS_DB }} \
        -t $ECR_REGISTRY/$ECR_CONTAINER_NAME:$IMAGE_TAG .
        docker push $ECR_REGISTRY/$ECR_CONTAINER_NAME:$IMAGE_TAG
        echo "::set-output name=image::$ECR_REGISTRY/$ECR_CONTAINER_NAME:$IMAGE_TAG"

I modified the YML file refer to our deploy.sh file. When you commit to the master branch, then Github Action is started. Let’s check the results.

Almost steps are done. But The Docker build step is failed.

Almost steps are done. But The Docker build step is failed.

In the build step, the docker command can't find the Dockerfile. If you use the `uses: docker/build-push-action@v2` in YML, You can successfully build your Dockerfile. But `uses: docker/build-push-action@v2` is trying to push docker hub, not AWS ECR…

In the build step, the docker command can’t find the Dockerfile. If you use the `uses: docker/build-push-action@v2` in YML, You can successfully build your Dockerfile. But `uses: docker/build-push-action@v2` is trying to push docker hub, not AWS ECR, even if I set the ECR URI. If you know to resolve this issue, please let me know. I’ll update the Github Action step soon!

 

 

Special Thanks

Thanks for advising me and review my post.

Quote of the week

"People ask me what I do in the winter when there's no baseball. I'll tell you what I do. I stare out the window and wait for spring."

~ Rogers Hornsby