Skip to content
This repository was archived by the owner on Dec 2, 2020. It is now read-only.

Commit a3c8d94

Browse files
committed
Extract function deployment package from container image
Bump version to 1.0, yay!
1 parent a9842a5 commit a3c8d94

File tree

10 files changed

+211
-69
lines changed

10 files changed

+211
-69
lines changed

README.md

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@
22

33
[![Build Status](https://travis-ci.org/awslabs/aws-lambda-container-image-converter.svg?branch=master)](https://travis-ci.org/awslabs/aws-lambda-container-image-converter)
44

5-
This container image converter tool (img2lambda) repackages container images (such as Docker images) into AWS Lambda layers, and publishes them as new layer versions to Lambda.
5+
This container image converter tool (img2lambda) extracts an AWS Lambda function deployment package from a container image (such as a Docker image).
6+
It also extracts AWS Lambda layers from a container image, and publishes them as new layer versions to Lambda.
67

7-
The tool copies all files under '/opt' in the Docker image, maintaining the individual Docker image layers as individual Lambda layers. The published layer ARNs will be stored in a file 'output/layers.json', which can be used as input when creating Lambda functions. Each layer is named using a "namespace" prefix (like img2lambda or my-docker-image) and the SHA256 digest of the Docker image layer, in order to provide a way of tracking the provenance of the Lambda layer back to the Docker image that created it.
8+
![img2lambda Demo](assets/demo.gif)
89

9-
If a layer is already published to Lambda (same layer name, SHA256 digest, and size), it will not be published again. Instead the existing layer version ARN will be written to the output file.
10+
To extract a Lambda function deployment package, the tool copies all files under '/var/task' in the container image into a deployment package zip file.
1011

11-
![img2lambda Demo](assets/demo.gif)
12+
To extract Lambda layers, the tool copies all files under '/opt' in the container image, repackaging the individual container image layers as individual Lambda layer zip files.
13+
The published layer ARNs are stored in a file 'output/layers.json', which can be used as input when creating Lambda functions.
14+
Each layer is named using a "namespace" prefix (like 'img2lambda' or 'my-docker-image') and the SHA256 digest of the container image layer, in order to provide a way of tracking the provenance of the Lambda layer back to the container image that created it.
15+
If a layer is already published to Lambda (same layer name, SHA256 digest, and size), it will not be published again.
16+
Instead the existing layer version ARN will be written to the output file.
1217

1318
**Table of Contents**
1419

@@ -41,7 +46,7 @@ GLOBAL OPTIONS:
4146
--image-type value, -t value Type of the source container image. Valid values: 'docker' (Docker image from the local Docker daemon), 'oci' (OCI image archive at the given path and optional tag) (default: "docker")
4247
--region value, -r value AWS region (default: "us-east-1")
4348
--profile value, -p value AWS credentials profile. Credentials will default to the same chain as the AWS CLI: environment variables, default profile, container credentials, EC2 instance credentials
44-
--output-directory value, -o value Destination directory for command output (default: "./output")
49+
--output-directory value, -o value Destination directory for output: function deployment package (function.zip) and list of published layers (layers.json, layers.yaml) (default: "./output")
4550
--layer-namespace value, -n value Prefix for the layers published to Lambda (default: "img2lambda")
4651
--dry-run, -d Conduct a dry-run: Repackage the image, but only write the Lambda layers to local disk (do not publish to Lambda)
4752
--description value, --desc value The description of this layer version (default: "created by img2lambda from image <name of the image>")
@@ -124,21 +129,21 @@ For example:
124129

125130
### Docker Example
126131

127-
Build the example Docker image to create a PHP Lambda custom runtime:
132+
Build the example Docker image to create a PHP Lambda custom runtime and Hello World PHP function:
128133
```
129134
cd example
130135
131136
docker build -t lambda-php .
132137
```
133138

134-
The example PHP functions are also built into the example image, so they can be run with Docker:
139+
The Hello World function can be invoked locally by running the Docker image:
135140
```
136141
docker run lambda-php hello '{"name": "World"}'
137142
138143
docker run lambda-php goodbye '{"name": "World"}'
139144
```
140145

141-
Run the tool to create and publish Lambda layers that contain the PHP custom runtime:
146+
Run the tool to both create a Lambda deployment package that contains the Hello World PHP function, and to create and publish Lambda layers that contain the PHP custom runtime:
142147
```
143148
../bin/local/img2lambda -i lambda-php:latest -r us-east-1 -o ./output
144149
```
@@ -154,26 +159,22 @@ podman build --format oci -t lambda-php .
154159
podman push lambda-php oci-archive:./lambda-php-oci
155160
```
156161

157-
Run the tool to create and publish Lambda layers that contain the PHP custom runtime:
162+
Run the tool to both create a Lambda deployment package that contains the Hello World PHP function, and to create and publish Lambda layers that contain the PHP custom runtime:
158163
```
159164
../bin/local/img2lambda -i ./lambda-php-oci -t oci -r us-east-1 -o ./output
160165
```
161166

162167
### Deploy Manually
163-
Create a PHP function that uses the layers:
168+
Create a PHP function that uses the layers and deployment package extracted from the container image:
164169
```
165-
cd function
166-
167-
zip hello.zip src/hello.php
168-
169170
aws lambda create-function \
170171
--function-name php-example-hello \
171172
--handler hello \
172-
--zip-file fileb://./hello.zip \
173+
--zip-file fileb://./output/function.zip \
173174
--runtime provided \
174175
--role "arn:aws:iam::XXXXXXXXXXXX:role/service-role/LambdaPhpExample" \
175176
--region us-east-1 \
176-
--layers file://../output/layers.json
177+
--layers file://./output/layers.json
177178
```
178179

179180
Finally, invoke the function:
@@ -191,18 +192,18 @@ cat hello-output.txt
191192

192193
### Deploy with AWS Serverless Application Model (SAM)
193194

194-
See [the sample template.yaml](example/function/template.yaml) and [the sample template.json](example/function/template.json).
195+
See [the sample template.yaml](example/deploy/template.yaml) and [the sample template.json](example/deploy/template.json).
195196

196197
Insert the layers ARNs into the function definition:
197198
```
198-
cd function
199+
cd example/deploy
199200
200201
sed -i 's/^- / - /' ../output/layers.yaml && \
201202
sed -e "/LAYERS_PLACEHOLDER/r ../output/layers.yaml" -e "s///" template.yaml > template-with-layers.yaml
202203
203204
OR
204205
205-
cd function
206+
cd example/deploy
206207
207208
sed -e "/\"LAYERS_PLACEHOLDER\"/r ../output/layers.json" -e "s///" template.json | jq . > template-with-layers.json
208209
```
@@ -247,11 +248,11 @@ cat hello-output.txt
247248

248249
### Deploy with Serverless Framework
249250

250-
See [the sample serverless.yml](example/function/serverless.yml) for how to use the img2lambda-generated layers in your Serverless function.
251+
See [the sample serverless.yml](example/deploy/serverless.yml) for how to use the img2lambda-generated layers in your Serverless function.
251252

252253
Deploy the function:
253254
```
254-
cd function
255+
cd example/deploy
255256
256257
serverless deploy -v
257258
```

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.5.0
1+
1.0.0

example/function/serverless.yml renamed to example/deploy/serverless.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,12 @@ functions:
88
hello:
99
handler: hello.hello
1010
package:
11-
include:
12-
- src/hello.php
11+
artifact: ../output/function.zip
1312
layers:
1413
${file(../output/layers.json)}
1514
goodbye:
1615
handler: goodbye.goodbye
1716
package:
18-
include:
19-
- src/goodbye.php
17+
artifact: ../output/function.zip
2018
layers:
2119
${file(../output/layers.json)}

example/function/template.json renamed to example/deploy/template.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"FunctionName": "sam-php-example-hello",
99
"Handler": "hello.hello",
1010
"Runtime": "provided",
11-
"CodeUri": "./",
11+
"CodeUri": "../output/function.zip",
1212
"Layers": "LAYERS_PLACEHOLDER"
1313
}
1414
},
@@ -18,7 +18,7 @@
1818
"FunctionName": "sam-php-example-goodbye",
1919
"Handler": "goodbye.goodbye",
2020
"Runtime": "provided",
21-
"CodeUri": "./",
21+
"CodeUri": "../output/function.zip",
2222
"Layers": "LAYERS_PLACEHOLDER"
2323
}
2424
}

example/function/template.yaml renamed to example/deploy/template.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Resources:
88
FunctionName: sam-php-example-hello
99
Handler: hello.hello
1010
Runtime: provided
11-
CodeUri: ./
11+
CodeUri: ../output/function.zip
1212
Layers: LAYERS_PLACEHOLDER
1313

1414
Goodbye:
@@ -17,5 +17,5 @@ Resources:
1717
FunctionName: sam-php-example-goodbye
1818
Handler: goodbye.goodbye
1919
Runtime: provided
20-
CodeUri: ./
20+
CodeUri: ../output/function.zip
2121
Layers: LAYERS_PLACEHOLDER

img2lambda/cli/main.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func createApp() (*cli.App, *types.CmdOptions) {
2323
app.EnableBashCompletion = true
2424
app.Name = "img2lambda"
2525
app.Version = version.VersionString()
26-
app.Usage = "Repackages a container image into AWS Lambda layers and publishes them to Lambda"
26+
app.Usage = "Repackages a container image into an AWS Lambda function deployment package. Extracts AWS Lambda layers from the image and publishes them to Lambda"
2727
app.Action = func(c *cli.Context) error {
2828
// parse and store the passed runtime list into the options object
2929
opts.CompatibleRuntimes = c.StringSlice("cr")
@@ -56,7 +56,7 @@ func createApp() (*cli.App, *types.CmdOptions) {
5656
},
5757
cli.StringFlag{
5858
Name: "output-directory, o",
59-
Usage: "Destination directory for command output",
59+
Usage: "Destination directory for output: function deployment package (function.zip) and list of published layers (layers.json, layers.yaml)",
6060
Value: "./output",
6161
Destination: &opts.OutputDir,
6262
},
@@ -125,13 +125,18 @@ func repackImageAction(opts *types.CmdOptions, context *cli.Context) error {
125125
imageLocation += ":latest"
126126
}
127127

128-
layers, err := extract.RepackImage(imageLocation, opts.OutputDir)
128+
layers, function, err := extract.RepackImage(imageLocation, opts.OutputDir)
129129
if err != nil {
130130
return err
131131
}
132132

133-
if len(layers) == 0 {
134-
return errors.New("No compatible layers found in the image (likely nothing found in /opt)")
133+
if function.FileCount == 0 {
134+
// remove empty zip file
135+
os.Remove(function.File)
136+
}
137+
138+
if len(layers) == 0 && function.FileCount == 0 {
139+
return errors.New("No compatible layers or function files found in the image (likely nothing found in /opt and /var/task)")
135140
}
136141

137142
if !opts.DryRun {

0 commit comments

Comments
 (0)