Cloud Native Infrastructure as Code

Container Management with Pulumi

Pulumi provides a cloud native programming model for container management: deploy Docker to AWS Fargate, Microsoft ACI, and Kubernetes.

Any code, any cloud, any language.

// Deploy Nginx to AWS Fargate
import * as cloud from "@pulumi/cloud";

let nginx = new cloud.Service("nginx", {
image: "nginx",
ports: [{ port: 80 }],
replicas: 2,
}); export let url = nginx.defaultEndpoint;



What is Container Management?

Docker, and containers more generally, transformed the way that developers could build, ship, and run applications. As a standardized unit of delivery, containers have all of the libraries, code, and runtime knowledge they need to work, and so can be deployed and scaled into any environment.

For DevOps teams, container management is an important capability whether delivering containers into bespoke environments, or more likely through a managed cloud offering such as AWS Fargate, AWS ECS, and Microsoft ACI, or through Kubernetes - either on-premises or AWS EKS, Microsoft AKS, or Google GKE.

Deploying containers with Pulumi

Container management solutions are broadly split into two options: low-management solutions for ease of deployment, and Kubernetes-based solutions for complete control.

Low Cluster Management

AWS Fargate, and Microsoft ACI are examples of services that enable the deployment of containers without having to manage servers or clusters. This means teams can very easily build container applications and deploy them into production without worrying about infrastructure, but gaining the benefits of seamless scaling.

Kubernetes Management

While running Kubernetes on-premises is a viable, and well-used solution, the major cloud vendors also offer Kubernetes sevices: Amazon EKS, Microsoft AKS, and Google GKE.


Pulumi makes it simple to interact with any of the services available from the major cloud vendors, and with Kubernetes.

The @pulumi/cloud library provides very high level, multi cloud access for deploying container applications, while the specialized @pulumi/cloud-aws, @pulumi/cloud-azure, @pulumi/cloud-gcp, and @pulumi/kubernetes libraries offer fine grained control of the individual cloud vendor services.

Deploy Nginx to AWS Fargate

In this example, Pulumi uses a multi-cloud cloud.Service object to pull the nginx image from Docker Hub, and deploy it in a load-balanced way to AWS Fargate. Pulumi can pull from any container registry.


Get Started

// In Pulumi configuration

pulumi config set cloud-aws:useFargate true

// Deploy Nginx to AWS Fargate

import * as cloud from "@pulumi/cloud";

let nginx = new cloud.Service("nginx", {
    image: "nginx",
    ports: [{ port: 80 }],
    replicas: 2,
});

export let url = nginx.defaultEndpoint;

Deploying with a custom build

This example uses a trivial Dockerfile that derives from the nginx base image and copies the ./www directory into the nginx HTML target so that it will be served up.


Get Started

// Using a custom build based on Nginx
        
import * as cloud from "@pulumi/cloud";

let nginx = new cloud.Service("nginx", {
    build: ".",
    ports: [{ port: 80 }],
    replicas: 2,
});

export let url = nginx.defaultEndpoint;


// Dockerfile
FROM nginx
COPY ./www /usr/share/nginx/html
    

Connecting containers

This example shows how we can connect containers using Pulumi - in this case Redis for a data store, and a Python flask app for a front end. Using Pulumi, it is easy to obtain a reference to the container objects, and connect them using code.


Get Started

import * as pulumi from "@pulumi/pulumi";
import * as cloud from "@pulumi/cloud";

// The data layer for the application
let redisCache = new cloud.Service("voting-app-cache", {
    containers: {
        redis: {
            image: "redis:alpine",
            memory: 512,
            ports: [{ port: redisPort }],
            command: ["redis-server", "--requirepass", redisPassword],
        },
    },
});

let redisEndpoint = redisCache.endpoints.apply(endpoints => 
                                    endpoints.redis[redisPort]);

// A custom container for the frontend, which is a Python Flask app
let frontend = new cloud.Service("voting-app-frontend", {
    containers: {
        votingAppFrontend: {
            build: "./frontend",   // path to Dockerfile folder
            memory: 512,
            ports: [{ port: 80 }],            
            environment: { 
                // pass the Redis container info in environment variables
                "REDIS":      redisEndpoint.apply(e => e.hostname),
                "REDIS_PORT": redisEndpoint.apply(e => e.port.toString()),
                "REDIS_PWD":  redisPassword
            }
        },
    },
});

export let frontendURL = frontend.endpoints.apply(e => e["votingAppFrontend"][80].hostname);
    

Deploy containers to Microsoft ACI

The @pulumi/azure library provides fine-grained control of Azure resources. In this example, we deploy a simple linux container to Microsoft ACI, in the West US zone.


Get Started

import * as azure from "@pulumi/azure";

const resourceGroup = new azure.core.ResourceGroup("resourcegroup", {
    location: "West US",
});

const containerGroup = new azure.containerservice.Group("containergroup", {
    location: resourceGroup.location,
    resourceGroupName: resourceGroup.name,
    ipAddressType: "public",
    osType: "linux",
    containers: [
        {
            name: "hw",
            image: "microsoft/aci-helloworld:latest",
            cpu: 0.5,
            memory: 1.5,
            port: 80
        },
    ],
    tags: {
        "environment": "testing",
    },
});
    

Invoke a long-running container as a task

This example shows a container used for executing a long-running task. Here, we use a container to perform a thumbnail extraction on a piece of video uploaded to an S3 bucket.


Get Started

let cloud = require("@pulumi/cloud-aws");

// A bucket to store videos and thumbnails.
let videos = new cloud.Bucket("bucket");

// A task which runs an FFMPEG transform to extract a thumbnail image.
let ffmpegThumbnailTask = new cloud.Task("ffmpegThumbTask", {
    build: ".",
    memoryReservation: 512,
});

// When a new video is uploaded, run the FFMPEG task on the video file.
videos.onPut("onNewVideo", args => {
    let file = args.key;
    ffmpegThumbnailTask.run({
        environment: {
            "S3_BUCKET":   videos.bucket.name.get(),
            "INPUT_VIDEO": file,
            "TIME_OFFSET": file.substring(file.indexOf('_')+1, file.indexOf('.')).replace('-',':'),
            "OUTPUT_FILE": file.substring(0, file.indexOf('_')) + '.jpg',
        },
    });
}, { keySuffix: ".mp4" });

exports.bucketName = videos.bucket.name;
    

How Pulumi Works

Get started with Pulumi

Pulumi works with your favorite language, and can be used with any cloud.

Install Pulumi

Setup

Configure

Try our tutorials

Quickstarts

Tour

Read the docs

Reference

Examples

Need help with container management? Drop us a line.

More from Pulumi

Migrate to Pulumi

In this video, Pulumi CTO, Luke Hoban, discusses how to begin to migrate to Pulumi from existing tools such as CloudFormation and Terraform.

Learn more

Serverless, Containers, and Infrastructure

In this blog post, we show productive Pulumi can be at combining different aspects of cloud architecture for truly cloud native programming.

Learn more