Module classic/ecr

Pulumi Elastic Contain Registry (ECR) Components

Pulumi’s API’s for simplifying working with ECR. The API currently provides ways to define and configure Repositories and LifecyclePolicies. It also makes it simple to build and push Docker Images to a Repository providing stored cloud images that can then be used by other AWS services like ECS.

Repositories

To start with, here’s a simple example of how one can create a simple ECR Repository:

import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";

const repository = new awsx.ecr.Repository("app");

With a repository available, it’s easy to build an push a Docker Image that will be stored in the cloud:

const repository = new awsx.ecr.Repository("app");

// "./app" is a relative folder to this application containing a Dockerfile.  For more
// examples of what can be built and pushed, see the @pulumi/docker package.
const image = repository.buildAndPushImage("./app");

Now that we have an image, it can be easily referenced from an ECS Service like so:

const repository = new awsx.ecr.Repository("app");
const image = repository.buildAndPushImage("./app");

const listener = new awsx.lb.NetworkListener("app", { port: 80 });
const nginx = new awsx.ecs.FargateService("app", {
    taskDefinitionArgs: {
        containers: {
            nginx: {
                image: image,
                memory: 128,
                portMappings: [listener],
            },
        },
    },
    desiredCount: 2,
});

In the case where you don’t really need to use the repository (except as a place to store the built image), the above can be simplified as:

const nginx = new awsx.ecs.FargateService("app", {
    taskDefinitionArgs: {
        containers: {
            nginx: {
                image: awsx.ecr.buildAndPushImage("app", "./app"),
                // ...
            },
        },
    },
    // ...
});

Lifecycle Policies

Amazon ECR lifecycle policies enable you to specify the lifecycle management of images in a repository. A lifecycle policy is a set of one or more rules, where each rule defines an action for Amazon ECR. The actions apply to images that contain tags prefixed with the given strings. This allows the automation of cleaning up unused images, for example expiring images based on age or count. You should expect that after creating a lifecycle policy the affected images are expired within 24 hours. See https://docs.aws.amazon.com/AmazonECR/latest/userguide/LifecyclePolicies.html for more details.

The ECR module makes it easy to configure the Lifecycle Policy for a given Repository. There are two main ways that control how an image is purged from the repository:

  1. Once a maximum number of images has been reached (maximumNumberOfImages).
  2. Once an image reaches a maximum allowed age (maximumAgeLimit).

Policies can apply to all images, ‘untagged’ images, or tagged images that match a specific tag-prefix.

By default an awsx.ecr.Repository is created with a policy that will only keep at most one untagged image around. In other words, the following are equivalent:

const repository1 = new awsx.ecr.Repository("app1");
const repository2 = new awsx.ecr.Repository("app2", {
    lifeCyclePolicyArgs: {
        rules: [{
            selection: "untagged",
            maximumNumberOfImages: 1,
        }],
    },
});

Policy Rules

A Lifecycle Policy is built from a collection of rules. These rules are ordered from lower priority to higher priority. How the collection of rules is interpreted is as follows:

  1. An image is expired by exactly one or zero rules.
  2. An image that matches the tagging requirements of a higher priority rule cannot be expired by a rule with a lower priority.
  3. Rules can never mark images that are marked by higher priority rules, but can still identify them as if they haven’t been expired.
  4. The set of rules must contain a unique set of tag prefixes.
  5. Only one rule is allowed to select untagged images.
  6. Expiration is always ordered by the “pushed at time” for an image, and always expires older images before newer ones.
  7. When using the tagPrefixList, an image is successfully matched if all of the tags in the tagPrefixList value are matched against any of the image’s tags.
  8. With maximumNumberOfImages, images are sorted from youngest to oldest based on their “pushed at time” and then all images greater than the specified count are expired.
  9. maximumAgeLimit, all images whose “pushed at time” is older than the specified number of days based on countNumber are expired.

Examples

Example A:

The following example shows the lifecycle policy syntax for a policy that expires untagged images older than 14 days:

const repository = new awsx.ecr.Repository("app", {
    lifeCyclePolicyArgs: {
        rules: [{
            selection: "untagged",
            maximumAgeLimit: 14,
        }],
    },
});

Example B: Filtering on Multiple Rules

The following examples use multiple rules in a lifecycle policy. An example repository and lifecycle policy are given along with an explanation of the outcome.

const repository = new awsx.ecr.Repository("app", {
    lifeCyclePolicyArgs: {
        rules: [{
            selection: { tagPrefixList: ["prod"] },
            maximumNumberOfImages: 1,
        }, {
            selection: { tagPrefixList: ["beta"] },
            maximumNumberOfImages: 1,
        }],
    },
});

Repository contents:

  • Image A, Taglist: [“beta-1”, “prod-1”], Pushed: 10 days ago
  • Image B, Taglist: [“beta-2”, “prod-2”], Pushed: 9 days ago
  • Image C, Taglist: [“beta-3”], Pushed: 8 days ago

The logic of this lifecycle policy would be:

  1. Rule 1 identifies images tagged with prefix prod. It should mark images, starting with the oldest, until there is one or fewer images remaining that match. It marks Image A for expiration.

  2. Rule 2 identifies images tagged with prefix beta. It should mark images, starting with the oldest, until there is one or fewer images remaining that match. It marks both Image A and Image B for expiration. However, Image A has already been seen by Rule 1 and if Image B were expired it would violate Rule 1 and thus is skipped.

Result: Image A is expired.

Example C: Filtering on Multiple Rules

This is the same repository as the previous example but the rule priority order is changed to illustrate the outcome.

const repository = new awsx.ecr.Repository("app", {
    lifeCyclePolicyArgs: {
        rules: [{
            selection: { tagPrefixList: ["beta"] },
            maximumNumberOfImages: 1,
        }, {
            selection: { tagPrefixList: ["prod"] },
            maximumNumberOfImages: 1,
        }],
    },
});

Repository contents:

  • Image A, Taglist: [“beta-1”, “prod-1”], Pushed: 10 days ago
  • Image B, Taglist: [“beta-2”, “prod-2”], Pushed: 9 days ago
  • Image C, Taglist: [“beta-3”], Pushed: 8 days ago

The logic of this lifecycle policy would be:

  1. Rule 1 identifies images tagged with beta. It should mark images, starting with the oldest, until there is one or fewer images remaining that match. It sees all three images and would mark Image A and Image B for expiration.

  2. Rule 2 identifies images tagged with prod. It should mark images, starting with the oldest, until there is one or fewer images remaining that match. It would see no images because all available images were already seen by Rule 1 and thus would mark no additional images.

Result: Images A and B are expired.

Example D: Filtering on Multiple Tags in a Single Rule

The following examples specify the lifecycle policy syntax for multiple tag prefixes in a single rule. An example repository and lifecycle policy are given along with an explanation of the outcome.

When multiple tag prefixes are specified on a single rule, images must match all listed tag prefixes.

const repository = new awsx.ecr.Repository("app", {
    lifeCyclePolicyArgs: {
        rules: [{
            selection: { tagPrefixList: ["alpha", "beta"] },
            maximumAgeLimit: 5,
        },
    },
});

Repository contents:

  • Image A, Taglist: [“alpha-1”], Pushed: 12 days ago
  • Image B, Taglist: [“beta-1”], Pushed: 11 days ago
  • Image C, Taglist: [“alpha-2”, “beta-2”], Pushed: 10 days ago
  • Image D, Taglist: [“alpha-3”], Pushed: 4 days ago
  • Image E, Taglist: [“beta-3”], Pushed: 3 days ago
  • Image F, Taglist: [“alpha-4”, “beta-4”], Pushed: 2 days ago

The logic of this lifecycle policy would be:

  1. Rule 1 identifies images tagged with alpha and beta. It sees images C and F. It should mark images that are older than five days, which would be Image C.

  2. Result: Image C is expired.

Example E: Filtering on All Images

The following lifecycle policy examples specify all images with different filters. An example repository and lifecycle policy are given along with an explanation of the outcome.

const repository = new awsx.ecr.Repository("app", {
    lifeCyclePolicyArgs: {
        rules: [{
            selection: "any",
            maximumNumberOfImages: 5,
        },
    },
});

Repository contents:

  • Image A, Taglist: [“alpha-1”], Pushed: 4 days ago
  • Image B, Taglist: [“beta-1”], Pushed: 3 days ago
  • Image C, Taglist: [], Pushed: 2 days ago
  • Image D, Taglist: [“alpha-2”], Pushed: 1 day ago

The logic of this lifecycle policy would be:

  1. Rule 1 identifies all images. It sees images A, B, C, and D. It should expire all images other than the newest one. It marks images A, B, and C for expiration.

  2. Result: Images A, B, and C are expired.

Resources

Others

Resources

Resource Repository

class Repository extends ComponentResource

A [Repository] represents an [aws.ecr.Repository] along with an associated [LifecyclePolicy] controlling how images are retained in the repo.

Docker images can be built and pushed to the repo using the [buildAndPushImage] method. This will call into the @pulumi/docker/buildAndPushImage function using this repo as the appropriate destination registry.

constructor

new Repository(name: string, args: RepositoryArgs, opts: ComponentResourceOptions)

method buildAndPushImage

public buildAndPushImage(pathOrBuild: pulumi.Input<string | DockerBuild>): Output<string>

Builds the docker container specified by [pathOrBuild] and pushes it to this repository. The result is the unique ID pointing to that pushed image in this repo. This unique ID can be passed as the value to image: repo.buildAndPushImage(...) in an ecs.Container.

method getData

protected getData(): Promise<TData>

Retrieves the data produces by [initialize]. The data is immediately available in a derived class’s constructor after the super(...) call to ComponentResource.

method getProvider

getProvider(moduleMember: string): ProviderResource | undefined

method initialize

protected initialize(args: Inputs): Promise<TData>

Can be overridden by a subclass to asynchronously initialize data for this Component automatically when constructed. The data will be available immediately for subclass constructors to use. To access the data use .getData.

method isInstance

static isInstance(obj: any): obj is ComponentResource

Returns true if the given object is an instance of CustomResource. This is designed to work even when multiple copies of the Pulumi SDK have been loaded into the same process.

method registerOutputs

protected registerOutputs(outputs?: Inputs | Promise<Inputs> | Output<Inputs>): void

registerOutputs registers synthetic outputs that a component has initialized, usually by allocating other child sub-resources and propagating their resulting property values.

ComponentResources can call this at the end of their constructor to indicate that they are done creating child resources. This is not strictly necessary as this will automatically be called after the initialize method completes.

property lifecyclePolicy

public lifecyclePolicy: LifecyclePolicy | undefined;

property repository

public repository: Repository;

property urn

urn: Output<URN>;

urn is the stable logical URN used to distinctly address a resource, both before and after deployments.

Others

function buildAndPushImage

buildAndPushImage(name: string, pathOrBuild: pulumi.Input<string | DockerBuild>, args?: RepositoryArgs, opts?: pulumi.ComponentResourceOptions): RepositoryImage

Creates a new [Repository], optionally configured using [args], builds the docker container specified by [pathOrBuild] and then pushes the built image to the repository. The result contains both the Repository created as well as the unique ID referencing the built image in that repo. This result type can be passed in as image: ecr.buildAndPushImage(...) for an ecs.Container

class LifecyclePolicy

class LifecyclePolicy extends LifecyclePolicy

constructor

new LifecyclePolicy(name: string, repository: Repository, args?: LifecyclePolicyArgs, opts: ComponentResourceOptions)

Creates a new [LifecyclePolicy] for the given [repository]. If [args] is not provided, then [getDefaultLifecyclePolicyArgs] will be used to set the default policy for this repo.

method defaultLifecyclePolicyArgs

public static defaultLifecyclePolicyArgs(): LifecyclePolicyArgs

Creates a default lifecycle policy such that at most a single untagged image is retained. All tagged layers and images will never expire.

method get

static get(name: string, id: pulumi.Input<pulumi.ID>, state?: LifecyclePolicyState, opts?: pulumi.CustomResourceOptions): LifecyclePolicy

Get an existing LifecyclePolicy resource’s state with the given name, ID, and optional extra properties used to qualify the lookup.

method getProvider

getProvider(moduleMember: string): ProviderResource | undefined

method isInstance

static isInstance(obj: any): obj is LifecyclePolicy

Returns true if the given object is an instance of LifecyclePolicy. This is designed to work even when multiple copies of the Pulumi SDK have been loaded into the same process.

property id

id: Output<ID>;

id is the provider-assigned unique ID for this managed resource. It is set during deployments and may be missing (undefined) during planning phases.

property policy

policy: pulumi.Output<string>;

The policy document. This is a JSON formatted string. See more details about Policy Parameters in the official AWS docs.

property registryId

registryId: pulumi.Output<string>;

The registry ID where the repository was created.

property repository

repository: pulumi.Output<string>;

Name of the repository to apply the policy.

property urn

urn: Output<URN>;

urn is the stable logical URN used to distinctly address a resource, both before and after deployments.

interface LifecyclePolicyArgs

interface LifecyclePolicyArgs

See https://docs.aws.amazon.com/AmazonECR/latest/userguide/lifecycle_policy_examples.html for more details.

property rules

rules: pulumi.Input<pulumi.Input<LifecyclePolicyRule>[]>;

Specifies the rules to determine how images should be retired from this repository. Rules are ordered from lowest priority to highest. If there is a rule with a selection value of any, then it will have the highest priority.

interface LifecyclePolicyRule

interface LifecyclePolicyRule

The following behaviors hold for these rules:

  • An image is expired by exactly one or zero rules.

  • An image that matches the tagging requirements of a higher priority rule cannot be expired by a rule with a lower priority.

  • Rules can never mark images that are marked by higher priority rules, but can still identify them as if they haven’t been expired.

  • The set of rules must contain a unique set of tag prefixes.

  • Only one rule is allowed to select untagged images.

  • Expiration is always ordered by pushed_at_time, and always expires older images before newer ones.

  • When using the tagPrefixList, an image is successfully matched if all of the tags in the tagPrefixList value are matched against any of the image’s tags.

  • With maximumNumberOfImages, images are sorted from youngest to oldest based on pushed_at_time and then all images greater than the specified count are expired.

  • With maximumAgeLimit, all images whose pushed_at_time is older than the specified number of days based on countNumber are expired.

property description

description?: pulumi.Input<string>;

Describes the purpose of a rule within a lifecycle policy.

property maximumAgeLimit

maximumAgeLimit?: pulumi.Input<number>;

The maximum age limit (in days) for your images. Either [maximumNumberOfImages] or [maximumAgeLimit] must be provided.

property maximumNumberOfImages

maximumNumberOfImages?: pulumi.Input<number>;

The maximum number of images that you want to retain in your repository. Either [maximumNumberOfImages] or [maximumAgeLimit] must be provided.

property selection

selection: pulumi.Input<"untagged" | "any" | {
    tagPrefixList: pulumi.Input<pulumi.Input<string>[]>;
}>;

Determines whether the lifecycle policy rule that you are adding specifies a tag for an image. If you specify any, then all images have the rule applied to them. If you specify untagged then the rule will only apply to untagged images. Otherwise, you can specify a tagPrefixList value.

interface RepositoryArgs

interface RepositoryArgs

property lifeCyclePolicyArgs

lifeCyclePolicyArgs?: LifecyclePolicyArgs;

The arguments controlling the [LifecyclePolicy] for this [Repository]. If undefined, a default one will be created using LifecyclePolicy.getDefaultLifecyclePolicyArgs.

property repository

repository?: aws.ecr.Repository;

Underlying repository. If not provided, a new one will be created on your behalf.

property tags

tags?: pulumi.Input<Record<string, pulumi.Input<string>>>;

A mapping of tags to assign to the resource.

class RepositoryImage

 implements ContainerImageProvider

A simple pair of a [Repository] and a built docker image that was pushed to it. This can be passed in as the image: repoImage value to an ecs.Container.

constructor

new RepositoryImage(repository: Repository, image: pulumi.Input<string>)

method environment

public environment(): never[]

method image

public image(): Input<string>

property imageValue

public imageValue: pulumi.Input<string>;

property repository

public repository: Repository;