2023-05-01 17:44:41 -07:00

6.3 KiB
Raw Permalink Blame History

title, date, meta_desc, meta_image, authors, tags
title date meta_desc meta_image authors tags
Easily Deploy Applications With AWS App Runner 2021-05-18 AWS App Runner configures networking, scaling, and security, letting deploy applications via source code or container. aws-app-runner.png
lee-zen
AWS
App Runner

There are loads of benefits to packaging up an application as a container. You can ensure that your application has all the required dependencies and runs in the isolated, predictable environment you expect. When it comes to running that containerized application, there are many options, including Kubernetes, Amazon Elastic Container Service (ECS), and Docker. Often, running a container application at scale requires setting up a container orchestrator and providing network infrastructure to the containers. Configuring this can be complex, especially if youre not familiar with virtual networking concepts such as virtual private clouds, load balancers, and the like.

AWS recently introduced App Runner, which allows you to easily deploy an application via either source code that lives in GitHub or container image repository. It handles all the configurations of networking, scaling, and security. In this blog post, well show you how easy it is to use Pulumi to set up the necessary infrastructure to use App Runner.

In our case, well build a container-based application. To create an App Runner service, we will be using Amazon's Elastic Container Registry (ECR) to create a repository to host our container images. In addition, well need to push our image to the repository and ensure that App Runner has permissions to pull images from our repository.

Well use Go for our examples today. First, lets setup the ECR repository:

repo, err := ecr.NewRepository(ctx, "sampleapp", &ecr.RepositoryArgs{})

Note that were using Pulumis auto-naming support to generate the repository name.

Next, lets make sure that the App Runner service can pull images from the repository. To do so, well create a role:

role, err := iam.NewRole(ctx, "ecrAccessRole", &iam.RoleArgs{
    AssumeRolePolicy: pulumi.String(string(assumeRolePolicy)),
})

The assumeRolePolicy object is fairly straightforward, its just the JSON representation:

assumeRolePolicy, _ := json.Marshal(map[string]interface{}{
    "Version": "2012-10-17",
    "Statement": []map[string]interface{}{
        {
            "Action": "sts:AssumeRole",
            "Effect": "Allow",
            "Sid":    "",
            "Principal": map[string]interface{}{
                "Service": []string{
                    "build.apprunner.amazonaws.com",
                },
            },
        },
    },
})

Finally, we assign the image pull policy to this role:

pullImagePolicy, _ := json.Marshal(map[string]interface{}{
    "Version": "2012-10-17",
    "Statement": []map[string]interface{}{
        {
            "Effect": "Allow",
            "Action": []string{
                "ecr:GetAuthorizationToken",
                "ecr:BatchCheckLayerAvailability",
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage",
                "ecr:DescribeImages",
            },
            "Resource": "*",
        },
    },
})

_, err = iam.NewRolePolicy(ctx, "ecrAccessRolePolicy", &iam.RolePolicyArgs{
    Role:   role,
    Policy: pulumi.String(string(pullImagePolicy)),
})

With all of that setup, we can now build and push our container. For our example, we'll create an app directory within our project containing a simple Dockerfile and index.html file:

FROM nginx:latest
COPY ./index.html /usr/share/nginx/html/index.html

Where index.html is simply:

<html>
   <head>
       <meta charset="UTF-8">
       <title>Hello, Pulumi</title>
   </head>
   <body>
       <p>Hello, world!</p>
       <p>Made with ❤️ with <a href="https://pulumi.com">Pulumi</a></p>
   </body>
</html>

To push the image, we simply use Pulumis Image component resource to build and push. Well need our ECR credentials, which we can obtain via a simple function call and pass that information as an argument to our Image resource:

ecrCredentials, err := ecr.GetAuthorizationToken(ctx, &ecr.GetAuthorizationTokenArgs{
    RegistryId: nil,
}, nil)
if err != nil {
    return err
}

// Build and push our image into the ECR repo.
dockerImage, err := docker.NewImage(ctx, "sampleapp", &docker.ImageArgs{
    ImageName: repo.RepositoryUrl,
    Build: docker.DockerBuildArgs{
        Context: pulumi.String("./app"),
    },
    Registry: &docker.ImageRegistryArgs{
        Server:   repo.RepositoryUrl,
        Username: pulumi.String(ecrCredentials.UserName),
        Password: pulumi.String(ecrCredentials.Password),
    },
})
if err != nil {
    return err
}

At this point, we have everything we need to deploy our App Runner Service. Let's deploy it!

appRunnerService, err := apprunner.NewService(ctx, "service", &apprunner.ServiceArgs{
    ServiceName: pulumi.String("myservice"),
    SourceConfiguration: &apprunner.ServiceSourceConfigurationArgs{
        AuthenticationConfiguration: &apprunner.ServiceSourceConfigurationAuthenticationConfigurationArgs{
            AccessRoleArn: role.Arn,
        },
        ImageRepository: &apprunner.ServiceSourceConfigurationImageRepositoryArgs{
            ImageIdentifier:     dockerImage.ImageName,
            ImageRepositoryType: pulumi.String("ECR"),
            ImageConfiguration: &apprunner.ServiceSourceConfigurationImageRepositoryImageConfigurationArgs{
                Port: pulumi.String("80"),
            },
        },
    },
})
if err != nil {
    return err
}

And just like that, our service is up and running, and it only took a few dozen lines of code! With this kind of setup, we dont have to worry about load balancers or scaling or anything like that -- instead, we focused on building our application and stood up the bare minimum to have a repository image. We can export the URL of our service to visit it:

ctx.Export("serviceEndpoint", appRunnerService.ServiceUrl)

Were excited at how easy it is to use Pulumi to deploy applications via AWS App Runner, and we cant wait to see what exciting things you build with it! See AWS App Runner in action in this episode of Modern Infrastructure Wednesday.

{{< youtube "XdMynboheiA?rel=0" >}}