Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(assets): support platform flag for DockerImageAsset #16770

Closed
wants to merge 29 commits into from
Closed

feat(assets): support platform flag for DockerImageAsset #16770

wants to merge 29 commits into from

Conversation

pahud
Copy link
Contributor

@pahud pahud commented Oct 4, 2021

As we are not allowed to specify platform flag for DockerImageAsset, users deploying cdk on x86_64 platform will not be able to bundle lambda.DockerImageFunction for the new arm64 architecture. Similarly, users deploying cdk on arm64 architecture like Mac M1 will not be able to bundle images for AWS Fargate, which is x86_64 only.

With this support, we are allowed to:

  • bundle image assets for a specific architecture with the new platform property of DockerImageAsset from aws-ecr-assets.
  • bundle arm64 DockerImageFunction from aws-lambda on x86_64.
  • bundle x86_64 container images for AWS Fargate from aws-ecs on arm64.

Fixes: #12472

Background

When we bundle and publish the docker container image assets with cdk deploy, it's important we must build images of correct architectures for different services. For AWS Fargate, as it only supports x86_64 at this moment, we must build x86_64(amd64) architecture docker images, while for Lambda Graviton2, the arm64 would be required.

Architecture of the images

Run docker inspect to check the Architecture for local images:

For example:

docker inspect 6aab191c10a7 | grep "Arch"    
        "Architecture": "arm64",

(The image was built for arm64 platform)

How to build images with correct Architecture?

Many docker image registries come with multi-architecture support. Read Introducing multi-architecture container images for Amazon ECR for more details on Amazon ECR. Let's take public.ecr.aws/lambda/python:latest for example. Run docker manifest inspect to check its manifest for architectures:

docker manifest inspect public.ecr.aws/lambda/python:latest                                                                                                                               
{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
   "manifests": [
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 1580,
         "digest": "sha256:fc52f9b4ca941653c109fca35078fb3d589283f61e37ab88bed05101c607de7a",
         "platform": {
            "architecture": "arm64",
            "os": "linux",
            "variant": "v8"
         }
      },
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 1580,
         "digest": "sha256:68ffef9d11b6de8675b657ecfb5eadf152150c720e627fb9b5ea0c69ef6ac8d0",
         "platform": {
            "architecture": "amd64",
            "os": "linux"
         }
      }
   ]
}

This image supports both linux/arm64 and linux/amd64 from the manifest.

Similarly, if we check python:3.9 from docker hub, we can list all platforms/architectures supported from its manifest data.

docker manifest inspect python:3.9

So how can we ensure to build correct architecture from different desktops like Apple Mac M1 or any x86_64 desktops? Let's take the following Dockerfile for example:

FROM public.ecr.aws/lambda/python:latest

For Apple Mac M1 users, if we docker build with this Dockerfile, under the covers the image layers for arm64 will be pulled because the Apple Mac M1 is arm64 architecture unless:

  1. we specify the DOCKER_DEFAULT_PLATFORM env var(see (assets): allow user to pass platform option to Docker builds #12472 (comment))
  2. Specify the --platform in the Dockerfile like
FROM --platform=linux/amd64 someBaseImage:someVersion
  1. docker build with --platform flag

Let's take M1 for example, if we docker build without passing --platform, we'll build an arm64 image.

圖片

However, if we pass --platform='linux/amd64' we'll be able to build amd64 image from exactly the same Dockerfile.

圖片

Similarly, for x86_64 desktop users, we'll build amd64 images by default and arm64 images by passing --platform='linux/arm64'.

When we bundle container image assets for AWS Fargate, we must build amd64 images. For Lambda arm64 architecture, we must build arm64 images for Lambda container runtime, no matter which platform you synthesize and deploy the assets. The key is always to pass correct --platform flag with Dockerfile from a base image with multiple-platform support.

However, what if we use python:latest-arm64 as the base image for our Dockerfile? Well, we will lose the advantages of multi-architecture support as this will only build arm64 images.

builder experience with aws-ecr-assets

Specify platform with ARM_64 or AMD_64 from docker image assets with multi-architecture docker base images

import * as assets from '@aws-cdk/aws-ecr-assets';

new assets.DockerImageAsset(stack, 'DockerImage', {
  directory: path.join(__dirname, 'demo-image'),
  platform: DockerPlatform.ARM_64,
});

builder experience with aws-ecs

For Mac M1 users deploying Amazon ECS services on AWS Fargate from local container image assets with multi-architecture docker base images. Specify the platform to ensure the image would be built for AMD_64 architecture.

taskDefinition.addContainer('web', {
  image: ecs.ContainerImage.fromAsset(path.join(__dirname, '../demo-image'), {
    platform: DockerPlatform.AMD_64,
  }),
  portMappings: [{
    containerPort: 8000,
  }],
});

builder experience with aws-lambda

For x86_64 users deploying Lambda functions with container runtime on Lambda Graviton2(arm64) from local container image assets with multi-architecture docker base images. Specify the platform to ensure the image would be built for ARM64 architecture.

new DockerImageFunction(this, 'MyLambda', {
  code: DockerImageCode.fromImageAsset(path.join(__dirname, 'docker-arm64-handler'), {
    platform: DockerPlatform.ARM_64,
  }),
  architectures: [Architecture.ARM_64],
});

builder experience with aws-apprunner

AWS App Runner supports x86_64 architecture only at this moment. For Mac M1 users, use platform to ensure the AMD_64 architecture for the DockerImageAsset.

import * as assets from '@aws-cdk/aws-ecr-assets';
import { Service } from '@aws-cdk/aws-apprunner';

const imageAsset = new assets.DockerImageAsset(stack, 'ImageAssets', {
  directory: path.join(__dirname, './docker.assets'),
  platform: DockerPlatform.AMD_64,
});

new Service(stack, 'Service', {
  source: Source.fromAsset({
    imageConfiguration: { port: 8000 },
    asset: imageAsset,
  }),
});

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

@gitpod-io
Copy link

gitpod-io bot commented Oct 4, 2021

@pahud pahud marked this pull request as draft October 4, 2021 01:39
@mergify
Copy link
Contributor

mergify bot commented Oct 4, 2021

Title does not follow the guidelines of Conventional Commits. Please adjust title before merge.

@pahud pahud changed the title WIP feat: support platform flag for DockerImageAsset feat: WIP - support platform flag for DockerImageAsset Oct 4, 2021
@pahud pahud changed the title feat: WIP - support platform flag for DockerImageAsset feat(lambda): WIP - support platform flag for DockerImageAsset Oct 4, 2021
@pahud pahud changed the title feat(lambda): WIP - support platform flag for DockerImageAsset feat(core): WIP - support platform flag for DockerImageAsset Oct 4, 2021
@pahud pahud changed the title feat(core): WIP - support platform flag for DockerImageAsset feat(assets): WIP - support platform flag for DockerImageAsset Oct 4, 2021
@pahud pahud changed the title feat(assets): WIP - support platform flag for DockerImageAsset feat(assets): support platform flag for DockerImageAsset Oct 4, 2021
@pahud pahud marked this pull request as ready for review October 4, 2021 23:20

new DockerImageFunction(this, 'MyLambda', {
code: DockerImageCode.fromImageAsset(path.join(__dirname, 'docker-arm64-handler'), {
platform: DockerPlatform.ARM_64,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if there's a way to automatically set the platform based on the value of architectures.

Maybe pass props.architectures to _bind() here?

export class DockerImageFunction extends Function {
constructor(scope: Construct, id: string, props: DockerImageFunctionProps) {
super(scope, id, {
...props,
handler: Handler.FROM_IMAGE,
runtime: Runtime.FROM_IMAGE,
code: props.code._bind(),
});
}
}

then you can set the platform in fromImageAsset?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @jogold,

This should have been addressed. Can you take a look again?

I think we still need an unit test to spyOn some method being called with correct platform. I've checked your packages/@aws-cdk/aws-lambda-go/test/bundling.test.ts and have been trying to write a similar test but ended up with no luck. Could you advise how to write the unit test for this PR? Any code snippets would be appreciated.

@pahud pahud marked this pull request as draft October 7, 2021 07:01
@pahud pahud marked this pull request as ready for review October 14, 2021 14:22
@pahud
Copy link
Contributor Author

pahud commented Oct 14, 2021

Hi @jogold can you take a look again?

@peterwoodworth peterwoodworth changed the title feat(assets): support platform flag for DockerImageAsset feat(assets): support platform flag for DockerImageAsset Oct 21, 2021
@github-actions github-actions bot added the @aws-cdk/assets Related to the @aws-cdk/assets package label Oct 21, 2021
@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildProject89A8053A-LhjRyN9kxr8o
  • Commit ID: f52256f
  • Result: SUCCEEDED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@Nicktho
Copy link

Nicktho commented Nov 9, 2021

Hi @pahud this PR seems to be a bit out of date, is this still being worked on?

* Use this if the platform name is not yet supported by the CDK.
* @param [platform=linux/amd64] the platform to use for docker build.
*/
public static custom(platform?: string) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it makes sense to provide a default value here for platform. DockerPlatform.custom() doesn't make semantic sense...

Suggested change
public static custom(platform?: string) {
public static custom(platform: string) {

* Specify this property to build images for a specific platform. Support docker API 1.38+.
*
* @default - no specific platform
*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
*

@@ -81,6 +81,16 @@ new lambda.DockerImageFunction(this, 'ECRFunction', {
The props for these docker image resources allow overriding the image's `CMD`, `ENTRYPOINT`, and `WORKDIR`
configurations. See their docs for more information.

To deploy a `DockerImageFunction` on Lambda `arm64` architecture, make sure you specify `Architecture.ARM_64` in `architecture`.
This will bundle docker image assets for `arm64` architecture with `--platform linux/arm64` implicitly even you build it from a `x86_64` architecture.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This will bundle docker image assets for `arm64` architecture with `--platform linux/arm64` implicitly even you build it from a `x86_64` architecture.
This will bundle docker image assets for `arm64` architecture with `--platform linux/arm64` implicitly even you build it within an `x86_64` host.

Comment on lines +48 to +50
/**
* determine the platform from `architecture`.
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a docstring:

Suggested change
/**
* determine the platform from `architecture`.
*/
// determine the platform from `architecture`.

@nikovirtala
Copy link
Contributor

@pahud I wouldn't mind if you could address the changes requested by Elad – I want to see this get merged 😄

@pahud
Copy link
Contributor Author

pahud commented Nov 30, 2021

@pahud I wouldn't mind if you could address the changes requested by Elad – I want to see this get merged 😄

Sorry for the delay. Yes I will address this shortly and continue this PR. Thanks!!

/**
* determine the platform from `architecture`.
*/
platform: arch?.dockerPlatform ? DockerPlatform.custom(arch.dockerPlatform) : undefined,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: align the style like this

...options.platform ? ['--platform', options.platform] : [],

Suggested change
platform: arch?.dockerPlatform ? DockerPlatform.custom(arch.dockerPlatform) : undefined,
...arch?.dockerPlatform ? { platform: DockerPlatform.custom(arch.dockerPlatform) } : {},

@eladb
Copy link
Contributor

eladb commented Jan 25, 2022

@pahud what's the status here?

@eladb eladb removed their assignment Jan 25, 2022
@rix0rrr rix0rrr added feature-request A feature should be added or improved. p1 and removed @aws-cdk/assets Related to the @aws-cdk/assets package labels Mar 4, 2022
@aws-cdk-automation
Copy link
Collaborator

This PR has been in CHANGES REQUESTED for 21 days, and looks abandoned. It will be closed in 10 days if no further commits are pushed to it.

@github-actions
Copy link

This PR has been deemed to be abandoned, and will be automatically closed. Please create a new PR for these changes if you think this decision has been made in error.

@github-actions github-actions bot added the closed-for-staleness This issue was automatically closed because it hadn't received any attention in a while. label Apr 20, 2022
@github-actions github-actions bot closed this Apr 20, 2022
@danielsharvey
Copy link
Contributor

Will this PR be revived?

@CarmenAPuccio
Copy link

@pahud @ericzbeard - Curious if this one is going to be revived? It looks to be close and I was hoping to use this feature in a demo I was building.

mergify bot pushed a commit that referenced this pull request May 26, 2022
…ker images (#20439)

This PR adds support for specifying the desired build platform when building docker images (ie: build an arm64 image on an amd64/x86_64 host). Closes #12472 

This PR does NOT touch Lambda builders, only ECR assets. #16770 attempted to implement support for ECR and Lambda but was abandoned. Meanwhile #16858 implemented lambda platform support. This implements the ECR side

I have run `yarn integ`

----

### All Submissions:

* [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md)

### Adding new Unconventional Dependencies:

* [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md/#adding-new-unconventional-dependencies)

### New Features

* [x] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/master/INTEGRATION_TESTS.md)?
	* [x] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)?

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
@yakirza17
Copy link
Contributor

@pahud @eladb It's important PR, can you revived this? It's must to have for upgrading existing systems to use arm64.

mergify bot pushed a commit that referenced this pull request Aug 3, 2022
Based on [this](#16770) PR
Add the missing part to add platform support when using lambda `fromImageAsset`

As we are not allowed to specify `platform` flag for `DockerImageAsset`, users deploying cdk on x86_64 platform will not be able to bundle lambda.DockerImageFunction for the new arm64 architecture. Similarly, users deploying cdk on arm64 architecture like Mac M1 will not be able to bundle images for AWS Fargate, which is x86_64 only.

# builder experience with aws-lambda
For x86_64 users deploying Lambda functions with container runtime on Lambda Graviton2(arm64) from local container image assets with multi-architecture docker base images. Specify the platform to ensure the image would be built for ARM64 architecture.

```
 new DockerImageFunction(stack, 'Lambda', {
      code: DockerImageCode.fromImageAsset(path.join(__dirname, 'docker-arm64-handler')),
      architecture: Architecture.ARM_64,
    });
```

Fixes: #12472, #20907
----

### All Submissions:

* [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md)

### Adding new Unconventional Dependencies:

* [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-new-unconventional-dependencies)

### New Features

* [x] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)?
	* [x] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)?

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
josephedward pushed a commit to josephedward/aws-cdk that referenced this pull request Aug 30, 2022
Based on [this](aws#16770) PR
Add the missing part to add platform support when using lambda `fromImageAsset`

As we are not allowed to specify `platform` flag for `DockerImageAsset`, users deploying cdk on x86_64 platform will not be able to bundle lambda.DockerImageFunction for the new arm64 architecture. Similarly, users deploying cdk on arm64 architecture like Mac M1 will not be able to bundle images for AWS Fargate, which is x86_64 only.

# builder experience with aws-lambda
For x86_64 users deploying Lambda functions with container runtime on Lambda Graviton2(arm64) from local container image assets with multi-architecture docker base images. Specify the platform to ensure the image would be built for ARM64 architecture.

```
 new DockerImageFunction(stack, 'Lambda', {
      code: DockerImageCode.fromImageAsset(path.join(__dirname, 'docker-arm64-handler')),
      architecture: Architecture.ARM_64,
    });
```

Fixes: aws#12472, aws#20907
----

### All Submissions:

* [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md)

### Adding new Unconventional Dependencies:

* [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-new-unconventional-dependencies)

### New Features

* [x] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)?
	* [x] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)?

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-for-staleness This issue was automatically closed because it hadn't received any attention in a while. feature-request A feature should be added or improved. p1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

(assets): allow user to pass platform option to Docker builds