diff --git a/API.md b/API.md
index 397cdbd0..abb565b9 100644
--- a/API.md
+++ b/API.md
@@ -148,6 +148,7 @@ const eCRDeploymentProps: ECRDeploymentProps = { ... }
| src
| IImageName
| The source of the docker image. |
| buildImage
| string
| Image to use to build Golang lambda for custom resource, if download fails or is not wanted. |
| environment
| {[ key: string ]: string}
| The environment variable to set. |
+| imageArch
| string
| The image architecture to be copied. |
| lambdaHandler
| string
| The name of the lambda handler. |
| lambdaRuntime
| aws-cdk-lib.aws_lambda.Runtime
| The lambda function runtime environment. |
| memoryLimit
| number
| The amount of memory (in MiB) to allocate to the AWS Lambda function which replicates the files from the CDK bucket to the destination bucket. |
@@ -211,6 +212,19 @@ The environment variable to set.
---
+##### `imageArch`Optional
+
+```typescript
+public readonly imageArch: string;
+```
+
+- *Type:* string
+- *Default:* runtime.GOARCH if it's not explicitly specified, according to https://github.com/containers/image/blob/main/internal/pkg/platform/platform_matcher.go#L161
+
+The image architecture to be copied.
+
+---
+
##### `lambdaHandler`Optional
```typescript
diff --git a/lambda/main.go b/lambda/main.go
index 639d52c6..803ff736 100644
--- a/lambda/main.go
+++ b/lambda/main.go
@@ -53,6 +53,10 @@ func handler(ctx context.Context, event cfn.Event) (physicalResourceID string, d
if err != nil {
return physicalResourceID, data, err
}
+ imageArch, err := getStrPropsDefault(event.ResourceProperties, IMAGE_ARCH, "")
+ if err != nil {
+ return physicalResourceID, data, err
+ }
srcCreds, err := getStrPropsDefault(event.ResourceProperties, SRC_CREDS, "")
if err != nil {
return physicalResourceID, data, err
@@ -71,7 +75,7 @@ func handler(ctx context.Context, event cfn.Event) (physicalResourceID string, d
return physicalResourceID, data, err
}
- log.Printf("SrcImage: %v DestImage: %v", srcImage, destImage)
+ log.Printf("SrcImage: %v DestImage: %v ImageArch: %v", srcImage, destImage, imageArch)
srcRef, err := alltransports.ParseImageName(srcImage)
if err != nil {
@@ -82,13 +86,13 @@ func handler(ctx context.Context, event cfn.Event) (physicalResourceID string, d
return physicalResourceID, data, err
}
- srcOpts := NewImageOpts(srcImage)
+ srcOpts := NewImageOpts(srcImage, imageArch)
srcOpts.SetCreds(srcCreds)
srcCtx, err := srcOpts.NewSystemContext()
if err != nil {
return physicalResourceID, data, err
}
- destOpts := NewImageOpts(destImage)
+ destOpts := NewImageOpts(destImage, imageArch)
destOpts.SetCreds(destCreds)
destCtx, err := destOpts.NewSystemContext()
if err != nil {
diff --git a/lambda/main_test.go b/lambda/main_test.go
index a28b323f..46dd0345 100644
--- a/lambda/main_test.go
+++ b/lambda/main_test.go
@@ -33,10 +33,10 @@ func TestMain(t *testing.T) {
destRef, err := alltransports.ParseImageName(destImage)
assert.NoError(t, err)
- srcOpts := NewImageOpts(srcImage)
+ srcOpts := NewImageOpts(srcImage, "")
srcCtx, err := srcOpts.NewSystemContext()
assert.NoError(t, err)
- destOpts := NewImageOpts(destImage)
+ destOpts := NewImageOpts(destImage, "")
destCtx, err := destOpts.NewSystemContext()
assert.NoError(t, err)
@@ -53,3 +53,12 @@ func TestMain(t *testing.T) {
})
assert.NoError(t, err)
}
+
+func TestNewImageOpts(t *testing.T) {
+ srcOpts := NewImageOpts("s3://cdk-ecr-deployment/nginx.tar:nginx:latest", "arm64")
+ _, err := srcOpts.NewSystemContext()
+ assert.NoError(t, err)
+ destOpts := NewImageOpts("dir:/tmp/nginx.dir", "arm64")
+ _, err = destOpts.NewSystemContext()
+ assert.NoError(t, err)
+}
diff --git a/lambda/utils.go b/lambda/utils.go
index 461c3807..9d0311d8 100644
--- a/lambda/utils.go
+++ b/lambda/utils.go
@@ -23,6 +23,7 @@ import (
const (
SRC_IMAGE string = "SrcImage"
DEST_IMAGE string = "DestImage"
+ IMAGE_ARCH string = "ImageArch"
SRC_CREDS string = "SrcCreds"
DEST_CREDS string = "DestCreds"
)
@@ -86,14 +87,15 @@ type ImageOpts struct {
requireECRLogin bool
region string
creds string
+ arch string
}
-func NewImageOpts(uri string) *ImageOpts {
+func NewImageOpts(uri string, arch string) *ImageOpts {
requireECRLogin := strings.Contains(uri, "dkr.ecr")
if requireECRLogin {
- return &ImageOpts{uri, requireECRLogin, GetECRRegion(uri), ""}
+ return &ImageOpts{uri, requireECRLogin, GetECRRegion(uri), "", arch}
} else {
- return &ImageOpts{uri, requireECRLogin, "", ""}
+ return &ImageOpts{uri, requireECRLogin, "", "", arch}
}
}
@@ -109,6 +111,7 @@ func (s *ImageOpts) NewSystemContext() (*types.SystemContext, error) {
ctx := &types.SystemContext{
DockerRegistryUserAgent: "ecr-deployment",
DockerAuthConfig: &types.DockerAuthConfig{},
+ ArchitectureChoice: s.arch,
}
if s.creds != "" {
diff --git a/src/index.ts b/src/index.ts
index 9ab65116..cb801f66 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -32,6 +32,14 @@ export interface ECRDeploymentProps {
*/
readonly dest: IImageName;
+ /**
+ * The image architecture to be copied.
+ *
+ * @default - the underlying lambda auto-detects the relevant architecture (e.g., amd64, arm64)
+ * https://github.com/containers/image/blob/main/internal/pkg/platform/platform_matcher.go#L161
+ */
+ readonly imageArch?: string;
+
/**
* The amount of memory (in MiB) to allocate to the AWS Lambda function which
* replicates the files from the CDK bucket to the destination bucket.
@@ -207,6 +215,7 @@ export class ECRDeployment extends Construct {
SrcCreds: props.src.creds,
DestImage: props.dest.uri,
DestCreds: props.dest.creds,
+ ImageArch: props.imageArch ?? '',
},
});
}
diff --git a/test/example.ecr-deployment.ts b/test/example.ecr-deployment.ts
index 2d5bd7c8..60cd229d 100644
--- a/test/example.ecr-deployment.ts
+++ b/test/example.ecr-deployment.ts
@@ -34,9 +34,27 @@ class TestECRDeployment extends Stack {
dest: new ecrDeploy.DockerImageName(`${repo.repositoryUri}:latest`),
});
+ new ecrDeploy.ECRDeployment(this, 'DeployECRImage', {
+ src: new ecrDeploy.DockerImageName(image.imageUri),
+ dest: new ecrDeploy.DockerImageName(`${repo.repositoryUri}:latest`),
+ imageArch: 'arm64',
+ });
+
+ new ecrDeploy.ECRDeployment(this, 'DeployDockerImage', {
+ src: new ecrDeploy.DockerImageName('javacs3/javacs3:latest', 'dockerhub'),
+ dest: new ecrDeploy.DockerImageName(`${repo.repositoryUri}:dockerhub`),
+ }).addToPrincipalPolicy(new iam.PolicyStatement({
+ effect: iam.Effect.ALLOW,
+ actions: [
+ 'secretsmanager:GetSecretValue',
+ ],
+ resources: ['*'],
+ }));
+
new ecrDeploy.ECRDeployment(this, 'DeployDockerImage', {
src: new ecrDeploy.DockerImageName('javacs3/javacs3:latest', 'dockerhub'),
dest: new ecrDeploy.DockerImageName(`${repo.repositoryUri}:dockerhub`),
+ imageArch: 'amd64',
}).addToPrincipalPolicy(new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: [