Preparing Migration to AWS App Runner
Tags: aws, containers, productivity, devops
Published: 2023-03-03 07:13:55

## Hot News!

The AWS App Runner is ready in ap-southeast-1 (Singapore). If you want to learn more about the news, please visit [this page](https://aws.amazon.com/about-aws/whats-new/2023/03/aws-app-runner-singapore-frankfurt-sydney-regions/).

## Roadmap

I want to deploy my open-source application named Simple Password Manager Service to AWS. I have tried deploying to Beanstalk and ECS, but those services don't fit my requirements. I want to have managed service and have an HTTPS connection by default. I can use Beanstalk and ECS, but I need to address the Load Balancer to use HTTPS. Currently, I don't want to control the Load Balancer myself. I want a service like AWS App Runner, but previously only available for limited regions. I believe this is the perfect time to use AWS App Runner!

I want to separate the steps into three steps. First, I want to regularly deploy to ECR. Second, I want to create the AWS App Runner and setup the deployment to use the latest version. Lastly, I will setup the deployment by tags to have more stable versions.

![spms plan ci/cd](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cthua2b8m9bkecen113x.png)

<figcaption>SPMS CI/CD Plan</figcaption>

## Deploying ECR using Azure DevOps

### Preparing ECR Repository

I created ECR using AWS CDK. I don't have any plan to have the automation for creating/updating/deleting the AWS CDK, but I might consider it for later. I have created the private ECR with this code.

```csharp
using Amazon.CDK;
using Amazon.CDK.AWS.ECR;
using Constructs;

namespace SimplePasswordManagerService.Infra {
  public class SimplePasswordManagerServiceInfraStack : Stack {
    internal SimplePasswordManagerServiceInfraStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) {
      var repository = new Repository(this, "spms", new RepositoryProps {
        RepositoryName = "spms",
        ImageTagMutability = TagMutability.MUTABLE,
        RemovalPolicy = RemovalPolicy.DESTROY,
        ImageScanOnPush = true,
        Encryption = RepositoryEncryption.KMS,
        LifecycleRules = new LifecycleRule[] {
        new LifecycleRule {
          MaxImageAge = Duration.Days(7),
          RulePriority = 1,
          TagStatus = TagStatus.UNTAGGED,
        }}
      });
    }
  }
}
```

![ECR Private](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ll72jrfm3iko3tnlbcex.png)

<figcaption>ECR SPMS - Private</figcaption>

### Azure DevOps Pipelines

Please refer to this cool post to set up your Azure DevOps with the AWS IAM Account. You are required to install the AWS Toolkit for Azure DevOps extension and set up the Service Connection.

{% embed https://aws.amazon.com/blogs/devops/use-the-aws-toolkit-for-azure-devops-to-automate-your-deployments-to-aws/ %}

You also can check [the official documentation](https://docs.aws.amazon.com/vsts/latest/userguide/getting-started.html#set-up-aws-credentials-for-the-aws-tools-for-vsts).

The pipelines will be like this.

![Azure Pipelines](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h8jbysepkhh4ioke6tql.png)

<figcaption>Azure Pipelines</figcaption>

The `azure-pipelines.yml` looks like this.

```yml
trigger:
- main

pr:
- main

variables:
  isPullRequest: ${{eq(variables['Build.Reason'], 'PullRequest')}}
  isMain: $[eq(variables['Build.SourceBranch'], 'refs/heads/main')]

pool:
  vmImage: ubuntu-22.04

parameters:
  - name: awsCredentials
    displayName: AWS Credentials
    type: string
    default: 'AWS-Dev-AssumeRole'
  - name: region
    displayName: AWS Region
    type: string
    default: 'ap-southeast-1'

steps:
- script: npm install -g aws-cdk
  displayName: 'Install AWS CDK'
- script: cd SimplePasswordManagerService.Infra && cdk synth
  displayName: 'CDK Synth'
- task: Docker@2
  displayName: 'Build Docker Image'
  inputs:
    command: 'build'
    Dockerfile: 'Dockerfile'
    repository: 'spms'
    tags: '$(Build.BuildId)'
- task: ECRPushImage@1
  displayName: 'Push Image to ECR'
  condition: and(succeeded(), eq(variables.isPullRequest, 'false'), eq(variables.isMain, 'true'))
  inputs:
    awsCredentials: '${{ parameters.awsCredentials }}'
    regionName: '${{ parameters.region }}'
    sourceImageName: 'spms'
    sourceImageTag: '$(Build.BuildId)'
    repositoryName: 'spms'
    pushTag: '$(Build.BuildId)'
```

{% github bervProject/SimplePasswordManagerService %}

## Thanks!

Thank you for reading! If you have any feedback, feel free to comment on this post. I'm going to post about my second step in the next post. Stay tuned!

![Happy Day GIF](https://media.giphy.com/media/UDov4HrdkLYFutGfTO/giphy.gif)