Skip to content

Commit ffb21c5

Browse files
Merge pull request #29 from benbjurstrom/main
Add support for container images
2 parents 37ab313 + ed5e23a commit ffb21c5

File tree

8 files changed

+152
-5
lines changed

8 files changed

+152
-5
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
# Changelog
22
## Unreleased
33

4+
## 0.3.2 - 2021-08-13
5+
6+
### Added
7+
8+
- Support for Container Images. [#29](https://github.com/hammerstonedev/sidecar/pull/29)
9+
410
## 0.3.1 - 2021-07-31
511

612
### Fixed

docs/functions/handlers-and-packages.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,36 @@ class ScreenshotFunction extends LambdaFunction
394394
}
395395
```
396396

397+
## Container Images
398+
399+
In addition to the standard runtimes AWS Lambda offers the ability to package your Lambda function code and dependencies as a container image of up to 10 GB in size.
400+
401+
To use a container image with Sidecar you must first build a Lambda compatible docker image and push it to the Amazon Elastic Container Registry (ECR). See [the official docs](https://docs.aws.amazon.com/lambda/latest/dg/images-create.html) for step-by-step instructions.
402+
403+
Once the container has been added to the registry update the Sidecar function's handler method to return the `Package::CONTAINER_HANDLER` constant. Finally, update the function's `package` method to return the ECR Image URI as shown below.
404+
405+
```php
406+
use Hammerstone\Sidecar\LambdaFunction;
407+
use Hammerstone\Sidecar\Package;
408+
409+
class ExampleFunction extends LambdaFunction
410+
{
411+
public function handler()
412+
{
413+
return Package::CONTAINER_HANDLER;
414+
}
415+
416+
public function package()
417+
{
418+
return [
419+
'ImageUri' => '123456789012.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest',
420+
];
421+
}
422+
}
423+
```
424+
425+
With the above configuration in place you can create and activate the AWS Lambda function with the `artisan sidecar:deploy --activate` command. From there you can use Sidecar to interact with the container image in the same manner as traditional runtimes.
426+
397427
## Further Reading
398428

399429
To read more about what you can and should include in your package, based on your runtime, see the following pages in Amazon's documentation:

src/Clients/LambdaClient.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,16 @@ public function updateExistingFunction(LambdaFunction $function)
145145
// and S3Key be top level instead of nested under `Code`.
146146
$code = [
147147
'FunctionName' => $config['FunctionName'],
148-
'S3Bucket' => $config['Code']['S3Bucket'],
149-
'S3Key' => $config['Code']['S3Key'],
150148
'Publish' => $config['Publish']
151149
];
152150

151+
if ($function->packageType() === 'Zip') {
152+
$code['S3Bucket'] = $config['Code']['S3Bucket'];
153+
$code['S3Key'] = $config['Code']['S3Key'];
154+
} else {
155+
$code = array_merge($code, $function->package());
156+
}
157+
153158
$config = Arr::except($config, ['Code', 'Publish']);
154159

155160
$this->updateFunctionConfiguration($config);

src/Deployment.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,11 @@ public function activate($prewarm = false)
104104
protected function deploySingle(LambdaFunction $function)
105105
{
106106
Sidecar::log('Environment: ' . Sidecar::getEnvironment());
107-
Sidecar::log('Runtime: ' . $function->runtime());
107+
Sidecar::log('Package Type: ' . $function->packageType());
108+
if ($function->packageType() === 'Zip') {
109+
Sidecar::log('Runtime: ' . $function->runtime());
110+
}
111+
108112

109113
$function->beforeDeployment();
110114

src/LambdaFunction.php

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Hammerstone\Sidecar\Exceptions\SidecarException;
1111
use Hammerstone\Sidecar\Results\PendingResult;
1212
use Hammerstone\Sidecar\Results\SettledResult;
13+
use Illuminate\Support\Arr;
1314
use Illuminate\Support\Str;
1415

1516
abstract class LambdaFunction
@@ -197,6 +198,18 @@ public function runtime()
197198
return 'nodejs14.x';
198199
}
199200

201+
/**
202+
* The type of deployment package. Set to Image for container
203+
* image and set Zip for .zip file archive.
204+
*
205+
* @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-lambda-2015-03-31.html#createfunction
206+
* @return string
207+
*/
208+
public function packageType()
209+
{
210+
return $this->handler() === Package::CONTAINER_HANDLER ? 'Image' : 'Zip';
211+
}
212+
200213
/**
201214
* An array full of ARN strings. Totally optional.
202215
*
@@ -233,6 +246,7 @@ public function variables()
233246
* If your file lived in a folder called "lambda", you can just prepend the
234247
* path to your handler, leaving you with e.g. "lambda/image.generate".
235248
*
249+
* @see https://hammerstone.dev/sidecar/docs/main/functions/handlers-and-packages
236250
* @see https://docs.aws.amazon.com/aws-sdk-php/v2/api/class-Aws.Lambda.LambdaClient.html#_createFunction
237251
* @return string
238252
*/
@@ -320,17 +334,29 @@ public function makePackage()
320334
*/
321335
public function toDeploymentArray()
322336
{
323-
return [
337+
$config = [
324338
'FunctionName' => $this->nameWithPrefix(),
325339
'Runtime' => $this->runtime(),
326340
'Role' => config('sidecar.execution_role'),
327341
'Handler' => $this->handler(),
328-
'Code' => $this->makePackage()->deploymentConfiguration(),
342+
'Code' => $this->packageType() === 'Zip'
343+
? $this->makePackage()->deploymentConfiguration()
344+
: $this->package(),
329345
'Description' => $this->description(),
330346
'Timeout' => (int)$this->timeout(),
331347
'MemorySize' => (int)$this->memory(),
332348
'Layers' => $this->layers(),
333349
'Publish' => true,
350+
'PackageType' => $this->packageType(),
334351
];
352+
353+
// For container image packages, we need to remove the Runtime
354+
// and Handler since the container handles both of those
355+
// things inherently.
356+
if ($this->packageType() === 'Image') {
357+
$config = Arr::except($config, ['Runtime', 'Handler']);
358+
}
359+
360+
return $config;
335361
}
336362
}

src/Package.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@
1717

1818
class Package
1919
{
20+
/**
21+
* If your package is a container image, it does not require
22+
* a handler function. Use this constant instead.
23+
*
24+
* @see https://hammerstone.dev/sidecar/docs/main/functions/handlers-and-packages
25+
* @var string
26+
*/
27+
public const CONTAINER_HANDLER = 'container';
28+
2029
/**
2130
* @var array
2231
*/

tests/Unit/LambdaClientTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Aws\Lambda\Exception\LambdaException;
99
use Hammerstone\Sidecar\Clients\LambdaClient;
1010
use Hammerstone\Sidecar\Tests\Unit\Support\DeploymentTestFunction;
11+
use Hammerstone\Sidecar\Tests\Unit\Support\DeploymentTestFunctionWithImage;
1112
use Hammerstone\Sidecar\Tests\Unit\Support\EmptyTestFunction;
1213
use Illuminate\Support\Facades\Event;
1314
use Mockery;
@@ -199,6 +200,38 @@ public function update_existing_function()
199200
$this->lambda->updateExistingFunction($function);
200201
}
201202

203+
/** @test */
204+
public function update_existing_image_function()
205+
{
206+
$function = new DeploymentTestFunctionWithImage;
207+
208+
$this->lambda->shouldReceive('functionExists')
209+
->once()
210+
->andReturn(false);
211+
212+
$this->lambda->shouldReceive('updateFunctionConfiguration')
213+
->once()
214+
->with([
215+
'FunctionName' => 'test-FunctionName',
216+
'Role' => null,
217+
'Description' => 'test-Description [ffeb0fec]',
218+
'Timeout' => 300,
219+
'MemorySize' => 512,
220+
'Layers' => [],
221+
'PackageType' => 'Image',
222+
]);
223+
224+
$this->lambda->shouldReceive('updateFunctionCode')
225+
->once()
226+
->with([
227+
'FunctionName' => 'test-FunctionName',
228+
'Publish' => 'test-Publish',
229+
'ImageUri' => '123.dkr.ecr.us-west-2.amazonaws.com/image:latest',
230+
]);
231+
232+
$this->lambda->updateExistingFunction($function);
233+
}
234+
202235
/** @test */
203236
public function existing_function_unchanged()
204237
{
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
/**
3+
* @author Aaron Francis <aarondfrancis@gmail.com|https://twitter.com/aarondfrancis>
4+
*/
5+
6+
namespace Hammerstone\Sidecar\Tests\Unit\Support;
7+
8+
use Hammerstone\Sidecar\LambdaFunction;
9+
use Hammerstone\Sidecar\Package;
10+
11+
class DeploymentTestFunctionWithImage extends LambdaFunction
12+
{
13+
public function handler()
14+
{
15+
return Package::CONTAINER_HANDLER;
16+
}
17+
18+
public function package()
19+
{
20+
return [
21+
'ImageUri' => '123.dkr.ecr.us-west-2.amazonaws.com/image:latest',
22+
];
23+
}
24+
25+
public function nameWithPrefix()
26+
{
27+
return 'test-FunctionName';
28+
}
29+
30+
public function description()
31+
{
32+
return 'test-Description';
33+
}
34+
}

0 commit comments

Comments
 (0)