1. Docs
  2. Pulumi IaC
  3. Clouds
  4. AWS
  5. Guides

AWS Guides

    Pulumi Crosswalk for AWS is a collection of libraries that use automatic well-architected best practices to make common infrastructure-as-code tasks in AWS easier and more secure.

    Overview

    Pulumi Crosswalk for AWS supports “day one” tasks, such as creating your initial container-based workloads using Amazon Elastic Container Service (ECS)—including Fargate or Kubernetes (EKS)—and creating serverless workloads using Amazon API Gateway and AWS Lambda. Secure and cost-conscious defaults are chosen so that simple programs automatically use best practices for the underlying infrastructure, enabling better productivity with confidence.

    Pulumi Crosswalk for AWS also supports “day two and beyond” tasks, such as scaling your workload, securing and integrating it with your existing infrastructure, or going to production in multiple complex environments. This includes Amazon Virtual Private Cloud (VPC) for network isolation, AWS Auto Scaling for dynamic scaling, and AWS Identity and Access Management (IAM) for securing your infrastructure.

    For example, this program builds and publishes a Dockerized application to a private Elastic Container Registry (ECR), spins up an ECS Fargate cluster, and runs a scalable, load balanced service, all in response to a single pulumi up command line invocation:

    "use strict";
    const pulumi = require("@pulumi/pulumi");
    const aws = require("@pulumi/aws");
    const awsx = require("@pulumi/awsx");
    
    const repo = new awsx.ecr.Repository("repo", {
        forceDelete: true,
    });
    
    const image = new awsx.ecr.Image("image", {
        repositoryUrl: repo.url,
        context: "./app",
        platform: "linux/amd64",
    });
    
    const cluster = new aws.ecs.Cluster("cluster");
    
    const lb = new awsx.lb.ApplicationLoadBalancer("lb");
    
    const service = new awsx.ecs.FargateService("service", {
        cluster: cluster.arn,
        assignPublicIp: true,
        taskDefinitionArgs: {
            container: {
                name: "my-service",
                image: image.imageUri,
                cpu: 128,
                memory: 512,
                essential: true,
                portMappings: [
                    {
                        containerPort: 80,
                        targetGroup: lb.defaultTargetGroup,
                    },
                ],
            },
        },
    });
    
    exports.url = pulumi.interpolate`http://${lb.loadBalancer.dnsName}`;
    
    import * as pulumi from "@pulumi/pulumi";
    import * as aws from "@pulumi/aws";
    import * as awsx from "@pulumi/awsx";
    
    const repo = new awsx.ecr.Repository("repo", {
        forceDelete: true,
    });
    
    const image = new awsx.ecr.Image("image", {
        repositoryUrl: repo.url,
        context: "./app",
        platform: "linux/amd64",
    });
    
    const cluster = new aws.ecs.Cluster("cluster");
    
    const lb = new awsx.lb.ApplicationLoadBalancer("lb");
    
    const service = new awsx.ecs.FargateService("service", {
        cluster: cluster.arn,
        assignPublicIp: true,
        taskDefinitionArgs: {
            container: {
                name: "my-service",
                image: image.imageUri,
                cpu: 128,
                memory: 512,
                essential: true,
                portMappings: [
                    {
                        containerPort: 80,
                        targetGroup: lb.defaultTargetGroup,
                    },
                ],
            },
        },
    });
    
    export const url = pulumi.interpolate`http://${lb.loadBalancer.dnsName}`;
    
    import pulumi
    import pulumi_aws as aws
    import pulumi_awsx as awsx
    
    repository = awsx.ecr.Repository(
        "repository",
        awsx.ecr.RepositoryArgs(
            force_delete=True
        ),
    )
    
    image = awsx.ecr.Image(
        "image",
        awsx.ecr.ImageArgs(
            repository_url=repository.url, context="./app", platform="linux/amd64"
        ),
    )
    
    cluster = aws.ecs.Cluster("cluster")
    lb = awsx.lb.ApplicationLoadBalancer("lb")
    
    service = awsx.ecs.FargateService(
        "service",
        awsx.ecs.FargateServiceArgs(
            cluster=cluster.arn,
            assign_public_ip=True,
            task_definition_args=awsx.ecs.FargateServiceTaskDefinitionArgs(
                container=awsx.ecs.TaskDefinitionContainerDefinitionArgs(
                    name="my-service",
                    image=image.image_uri,
                    cpu=512,
                    memory=128,
                    essential=True,
                    port_mappings=[
                        awsx.ecs.TaskDefinitionPortMappingArgs(
                            container_port=80,
                            target_group=lb.default_target_group,
                        )
                    ],
                ),
            ),
        ),
    )
    
    pulumi.export("url", pulumi.Output.concat("http://", lb.load_balancer.dns_name))
    
    package main
    
    import (
    	"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/ecs"
    	"github.com/pulumi/pulumi-awsx/sdk/v2/go/awsx/ecr"
    	ecsx "github.com/pulumi/pulumi-awsx/sdk/v2/go/awsx/ecs"
    	"github.com/pulumi/pulumi-awsx/sdk/v2/go/awsx/lb"
    	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
    )
    
    func main() {
    	pulumi.Run(func(ctx *pulumi.Context) error {
    		repository, err := ecr.NewRepository(ctx, "repository", &ecr.RepositoryArgs{
    			ForceDelete: pulumi.Bool(true),
    		})
    		if err != nil {
    			return err
    		}
    
    		image, err := ecr.NewImage(ctx, "image", &ecr.ImageArgs{
    			RepositoryUrl: repository.Url,
    			Context:       pulumi.String("./app"),
    			Platform:      pulumi.StringPtr("linux/amd64"),
    		})
    		if err != nil {
    			return err
    		}
    
    		cluster, err := ecs.NewCluster(ctx, "cluster", nil)
    		if err != nil {
    			return err
    		}
    
    		lb, err := lb.NewApplicationLoadBalancer(ctx, "lb", nil)
    		if err != nil {
    			return err
    		}
    
    		_, err = ecsx.NewFargateService(ctx, "service", &ecsx.FargateServiceArgs{
    			Cluster:        cluster.Arn,
    			AssignPublicIp: pulumi.Bool(true),
    			TaskDefinitionArgs: &ecsx.FargateServiceTaskDefinitionArgs{
    				Container: &ecsx.TaskDefinitionContainerDefinitionArgs{
    					Name:      pulumi.String("app"),
    					Image:     image.ImageUri,
    					Cpu:       pulumi.Int(512),
    					Memory:    pulumi.Int(128),
    					Essential: pulumi.Bool(true),
    					PortMappings: ecsx.TaskDefinitionPortMappingArray{
    						&ecsx.TaskDefinitionPortMappingArgs{
    							ContainerPort: pulumi.Int(80),
    							TargetGroup:   lb.DefaultTargetGroup,
    						},
    					},
    				},
    			},
    		})
    		if err != nil {
    			return err
    		}
    
    		ctx.Export("url", pulumi.Sprintf("http://%s", lb.LoadBalancer.DnsName()))
    		return nil
    	})
    }
    
    using System.Collections.Generic;
    using Pulumi;
    using Aws = Pulumi.Aws;
    using Awsx = Pulumi.Awsx;
    
    return await Deployment.RunAsync(() =>
    {
        var repo = new Awsx.Ecr.Repository("repo", new()
        {
            ForceDelete = true,
        });
    
        var image = new Awsx.Ecr.Image("image", new()
        {
            RepositoryUrl = repo.Url,
            Context = "./app",
            Platform = "linux/amd64",
        });
    
        var cluster = new Aws.Ecs.Cluster("cluster");
    
        var lb = new Awsx.Lb.ApplicationLoadBalancer("lb");
    
        var service = new Awsx.Ecs.FargateService("service", new Awsx.Ecs.FargateServiceArgs
        {
            Cluster = cluster.Arn,
            AssignPublicIp = true,
            TaskDefinitionArgs = new Awsx.Ecs.Inputs.FargateServiceTaskDefinitionArgs
            {
                Container = new Awsx.Ecs.Inputs.TaskDefinitionContainerDefinitionArgs
                {
                    Name = "my-service",
                    Image = image.ImageUri,
                    Cpu = 128,
                    Memory = 512,
                    Essential = true,
                    PortMappings = new[]
                    {
                        new Awsx.Ecs.Inputs.TaskDefinitionPortMappingArgs
                        {
                            ContainerPort = 80,
                            TargetGroup = lb.DefaultTargetGroup,
                        },
                    },
                },
            },
        });
    
        return new Dictionary<string, object?>
        {
            ["url"] = lb.LoadBalancer.Apply(loadBalancer => Output.Format($"http://{loadBalancer.DnsName}")),
        };
    });
    
    package myproject;
    
    import com.pulumi.Context;
    import com.pulumi.Pulumi;
    import com.pulumi.core.Output;
    import com.pulumi.awsx.ecr.Repository;
    import com.pulumi.awsx.ecr.RepositoryArgs;
    import com.pulumi.awsx.ecr.Image;
    import com.pulumi.awsx.ecr.ImageArgs;
    import com.pulumi.aws.ecs.Cluster;
    import com.pulumi.awsx.lb.ApplicationLoadBalancer;
    import com.pulumi.awsx.ecs.FargateService;
    import com.pulumi.awsx.ecs.FargateServiceArgs;
    import com.pulumi.awsx.ecs.inputs.FargateServiceTaskDefinitionArgs;
    import com.pulumi.awsx.ecs.inputs.TaskDefinitionContainerDefinitionArgs;
    import com.pulumi.awsx.ecs.inputs.TaskDefinitionPortMappingArgs;
    
    public class App {
        public static void main(String[] args) {
            Pulumi.run(App::stack);
        }
    
        public static void stack(Context ctx) {
            var repository = new Repository("repository", RepositoryArgs.builder()
                .forceDelete(true)
                .build());
    
            var image = new Image("image", ImageArgs.builder()
                .repositoryUrl(repository.url())
                .context("./app")
                .platform("linux/amd64")
                .build());
    
            var cluster = new Cluster("cluster");
    
            var lb = new ApplicationLoadBalancer("lb");
    
            var service = new FargateService("service", FargateServiceArgs.builder()
                .cluster(cluster.arn())
                .assignPublicIp(true)
                .taskDefinitionArgs(FargateServiceTaskDefinitionArgs.builder()
                    .container(TaskDefinitionContainerDefinitionArgs.builder()
                        .name("my-service")
                        .image(image.imageUri())
                        .cpu(128)
                        .memory(512)
                        .essential(true)
                        .portMappings(TaskDefinitionPortMappingArgs.builder()
                            .containerPort(80)
                            .targetGroup(lb.defaultTargetGroup())
                            .build())
                        .build())
                    .build())
                .build());
    
            ctx.export("url", Output.format("http://%s", lb.loadBalancer().applyValue(loadBalancer -> loadBalancer.dnsName())));
        }
    }
    
    name: awsx-load-balanced-fargate-ecr-yaml
    runtime: yaml
    
    resources:
      repo:
        type: awsx:ecr:Repository
        properties:
          forceDelete: true
    
      image:
        type: awsx:ecr:Image
        properties:
          repositoryUrl: ${repo.url}
          context: ./app
          platform: linux/amd64
    
      cluster:
        type: aws:ecs:Cluster
    
      lb:
        type: awsx:lb:ApplicationLoadBalancer
    
      service:
        type: awsx:ecs:FargateService
        properties:
          cluster: ${cluster.arn}
          assignPublicIp: true
          taskDefinitionArgs:
            container:
              name: my-service
              image: ${image.imageUri}
              cpu: 128
              memory: 512
              essential: true
              portMappings:
                - containerPort: 80
                  targetGroup: ${lb.defaultTargetGroup}
    
    outputs:
      url: http://${lb.loadBalancer.dnsName}
    

    This example uses the default VPC and reasonable security defaults, but supports easy customization of all aspects.

    Code Example Deep Dive

    Watch this video to dive into an Amazon ECS and Fargate code example that conceptually illustrates the benefits of using Crosswalk libraries versus authoring code from scratch with the AWS classic provider.

    Getting Started

    To get started with Pulumi Crosswalk for AWS, download and install Pulumi, and configure it to work with your AWS account. Afterwards, try the tutorial for Running Containers on ECS Fargate or select one of the relevant User Guides to get started:

    Containers

    Serverless

    Monitoring

    Core Infrastructure

    Continuous Deployment

    Other AWS Services

    Pulumi supports the entirety of the AWS platform. If your favorite service isn’t listed above, check out:

    Frequently Asked Questions (FAQ)

    What Clouds Does Pulumi Crosswalk Support?

    Pulumi Crosswalk supports AWS only at the moment. Support for additional clouds is on the roadmap (Azure, Google Cloud, and Kubernetes).

    What Languages are Supported?

    Pulumi Crosswalk for AWS is available for all supported Pulumi languages.

    What Packages Define Pulumi Crosswalk for AWS?

    Because Pulumi Crosswalk for AWS is a broader “brand” for our framework spanning multiple packages, there isn’t a single package that contains everything. The @pulumi/aws, @pulumi/awsx, @pulumi/aws-apigateway and @pulumi/eks packages each has an important role to play.

    Is Pulumi Crosswalk for AWS Free to Use?

    Yes, Pulumi Crosswalk for AWS is completely open source and free to use, along with the Individual Edition of Pulumi. Pulumi’s commercial offerings already fully support Pulumi Crosswalk for AWS.

    If you would like to contribute to the packages, please see the relevant repo on GitHub: pulumi/pulumi-aws, pulumi/pulumi-awsx pulumi/pulumi-aws-apigateway, or pulumi/eks. Issues and Pull Requests are welcome!

    If I’m an Existing User, What Has Changed?

    The primary change is new functionality added to the above packages, and the availability of these User Guides. Pulumi Crosswalk for AWS continues to work with the standard Pulumi CLI and Pulumi Cloud. If you already use the free Individual Edition, or paid Team or Enterprise Edition, you can continue to do so now with Pulumi Crosswalk for AWS functionality.

    Upgrading from an old version of Pulumi Crosswalk for AWS?

    Previous versions of @pulumi/awsx were TypeScript-only. The functionality has changed from these TypeScript-only versions. We have taken the opportunity to move the existing TypeScript-only functionality into a classic namespace. To create a VPC using the old TypeScript version of Crosswalk for AWS, the following code would work:

    import * as awsx from "@pulumi/awsx/classic";
    
    const vpc = new awsx.ec2.Vpc("classic-vpc", {});
    

    Any resource that you use from the existing library can continue to be used from that classic namespace. All of the classic functionality is available in that namesoace.

    Is Support or Training Available for Pulumi Crosswalk for AWS?

    Yes! Please fill out this form and a Pulumi team member will be in touch.

      PulumiUP 2024. Watch On Demand.