Skip to content

Commit bf5bc35

Browse files
prajinkhadkamcopik
andauthored
Container support for AWS (#205)
* [Feat] Add build base docker image as abstract method. * [Feat] Update aws to build the base docker image. * [Feat] Add Container deployment flag. To Do [Check for the valid providers that support container deployment] * [Feat] Add Container deployment support. * [Feat] Addd support of the base docker image AWS (python) * [Feat] Code Refacotring. * [Feat] Added Refactoring to do tasks. * [Feat] 1. Return container deployment flag, container URI. 2. Add create function with container URI * [Feat] Refactored the code. To Do: Need to add entrrypoint for docker aws. * Add entry point in the Dockerfile * Maintain cache for the container deployment. * Add correct entrypoint in dockerfile for lambda * Remove Whitespaces * Docler client login through user provided credentials, refactor ecr authorization, and rase NotImplementedError for GCP and Azure * Fix Mistyped * Minor fixes: Getting docker username, passwoord from config * Minor fixes: Only show the push image error once * Minor fixes: Refactor some print debugging statements. * Get repository name from Config. * Get repository name from Config if user has provided else generate randomly * Refactoring * Refactored the create function with simple if/else * Linter and formatter * Removed the parsing for repository name and Image tag. We can use it directly, no need to parse again. * Linter and formatter * Updating function based on container deployment and sotre the code hash for cache * Refactored * Added container deployment as CLI option and update the docs (usage.md) * Linter and formatter * Linter and formatter * Linter and formatter * Add new paramters ( container deployment nad uri) to update_function docs. * Dockerfile for NodeJs * Add Empty requirements * Add Empty requirements * Black fomatter * Black fomatter * Black fomatter * Black fomatter * Black fomatter * Fail early if contianer deployment is set for other than AWS. * Black fomatter * Minor Fix. * Minor Fix. * Remove unnecessary spaces * Use resource id instead of randomname for ecr reposiotry * [Feat] Linting and rebase errors * [aws] Make sure to fail when we cannot log in to ECR * [aws] Reorganize ECR repository creation * [aws] Add improt to rich (nice display) and boto3 stubs for ECR * [aws] Do not cache Docker passwords * [aws] Remove unnecessary config * [aws] Remove unnecessary Docker login * [aws] Customize function name for container deployment * [aws] remove debug output * [aws] [system] Extend cache system to support containers * [aws] Fix typo in the Docker image * [aws] Build arm64 Docker images * [system] Supporting proper caching of containers with different architectures * [aws] Prune pip cache after building the image * [aws] Remove unnecessary package * [aws] CodeRabbit fixes * [aws] Adjust other implementations to a new interface * [aws] Move container implementation to a separate class * [aws] Fix CodeRabbit issue * [aws] [whisk] Fuse two container implementations * [tools] Fix incorrect handling of False values * [system] Reorient container definition to distinguish between AWS and OpenWhisk support * [system] Add storage configuration option for benchmark invoke * [system] Disable rich output for regression * [benchmark] Separate directory for concurrent build of code package and container * [system] Extend regression to support containers * [system] Provide documentation on multi-platform builds * [aws] Update docs --------- Co-authored-by: Marcin Copik <[email protected]>
1 parent 4f7c5dd commit bf5bc35

32 files changed

+1149
-342
lines changed

benchmarks/100.webapps/120.uploader/python/requirements.txt

Whitespace-only changes.

benchmarks/300.utilities/311.compression/python/requirements.txt

Whitespace-only changes.
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from distutils.core import setup
2+
from glob import glob
3+
from pkg_resources import parse_requirements
4+
5+
with open('requirements.txt') as f:
6+
requirements = [str(r) for r in parse_requirements(f)]
7+
8+
setup(
9+
name='function',
10+
install_requires=requirements,
11+
packages=['function'],
12+
package_dir={'function': '.'},
13+
package_data={'function': glob('**', recursive=True)},
14+
)
15+

config/example.json

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
{
22
"experiments": {
3-
"deployment": "openwhisk",
3+
"deployment": "aws",
44
"update_code": false,
55
"update_storage": false,
6-
"download_results": false,
6+
"download_results": false,
77
"architecture": "arm64",
8+
"container_deployment": true,
89
"runtime": {
9-
"language": "nodejs",
10-
"version": "16"
10+
"language": "python",
11+
"version": "3.8"
1112
},
1213
"type": "invocation-overhead",
1314
"perf-cost": {

config/systems.json

+71-40
Original file line numberDiff line numberDiff line change
@@ -55,31 +55,46 @@
5555
}
5656
}
5757
},
58-
"architecture": ["x64"]
58+
"architecture": ["x64"],
59+
"deployments": ["package"]
5960
},
6061
"aws": {
6162
"languages": {
6263
"python": {
6364
"base_images": {
64-
"3.11": "amazon/aws-lambda-python:3.11",
65-
"3.10": "amazon/aws-lambda-python:3.10",
66-
"3.9": "amazon/aws-lambda-python:3.9",
67-
"3.8": "amazon/aws-lambda-python:3.8"
65+
"x64": {
66+
"3.11": "amazon/aws-lambda-python:3.11",
67+
"3.10": "amazon/aws-lambda-python:3.10",
68+
"3.9": "amazon/aws-lambda-python:3.9",
69+
"3.8": "amazon/aws-lambda-python:3.8"
70+
},
71+
"arm64": {
72+
"3.11": "amazon/aws-lambda-python:3.11.2024.05.23.17",
73+
"3.10": "amazon/aws-lambda-python:3.10.2024.06.19.11",
74+
"3.9": "amazon/aws-lambda-python:3.9.2024.05.20.23",
75+
"3.8": "amazon/aws-lambda-python:3.8.2024.09.05.16"
76+
}
6877
},
6978
"images": [
7079
"build"
7180
],
7281
"deployment": {
7382
"files": [
7483
"handler.py",
75-
"storage.py"
84+
"storage.py",
85+
"setup.py"
7686
],
7787
"packages": []
7888
}
7989
},
8090
"nodejs": {
8191
"base_images": {
82-
"16": "amazon/aws-lambda-nodejs:16"
92+
"x64": {
93+
"16": "amazon/aws-lambda-nodejs:16"
94+
},
95+
"arm64": {
96+
"16": "amazon/aws-lambda-nodejs:16.2024.09.06.13"
97+
}
8398
},
8499
"images": [
85100
"build"
@@ -95,17 +110,20 @@
95110
}
96111
}
97112
},
98-
"architecture": ["x64", "arm64"]
113+
"architecture": ["x64", "arm64"],
114+
"deployments": ["package", "container"]
99115
},
100116
"azure": {
101117
"languages": {
102118
"python": {
103119
"base_images": {
104-
"3.7": "mcr.microsoft.com/azure-functions/python:3.0-python3.7",
105-
"3.8": "mcr.microsoft.com/azure-functions/python:3.0-python3.8",
106-
"3.9": "mcr.microsoft.com/azure-functions/python:3.0-python3.9",
107-
"3.10": "mcr.microsoft.com/azure-functions/python:4-python3.10",
108-
"3.11": "mcr.microsoft.com/azure-functions/python:4-python3.11"
120+
"x64": {
121+
"3.7": "mcr.microsoft.com/azure-functions/python:3.0-python3.7",
122+
"3.8": "mcr.microsoft.com/azure-functions/python:3.0-python3.8",
123+
"3.9": "mcr.microsoft.com/azure-functions/python:3.0-python3.9",
124+
"3.10": "mcr.microsoft.com/azure-functions/python:4-python3.10",
125+
"3.11": "mcr.microsoft.com/azure-functions/python:4-python3.11"
126+
}
109127
},
110128
"images": [
111129
"build"
@@ -123,9 +141,11 @@
123141
},
124142
"nodejs": {
125143
"base_images": {
126-
"16": "mcr.microsoft.com/azure-functions/node:4-node16",
127-
"18": "mcr.microsoft.com/azure-functions/node:4-node18",
128-
"20": "mcr.microsoft.com/azure-functions/node:4-node20"
144+
"x64": {
145+
"16": "mcr.microsoft.com/azure-functions/node:4-node16",
146+
"18": "mcr.microsoft.com/azure-functions/node:4-node18",
147+
"20": "mcr.microsoft.com/azure-functions/node:4-node20"
148+
}
129149
},
130150
"images": [
131151
"build"
@@ -148,18 +168,21 @@
148168
"username": "docker_user"
149169
}
150170
},
151-
"architecture": ["x64"]
171+
"architecture": ["x64"],
172+
"deployments": ["package"]
152173
},
153174
"gcp": {
154175
"languages": {
155176
"python": {
156177
"base_images": {
157-
"3.7": "ubuntu:22.04",
158-
"3.8": "ubuntu:22.04",
159-
"3.9": "ubuntu:22.04",
160-
"3.10": "ubuntu:22.04",
161-
"3.11": "ubuntu:22.04",
162-
"3.12": "ubuntu:22.04"
178+
"x64": {
179+
"3.7": "ubuntu:22.04",
180+
"3.8": "ubuntu:22.04",
181+
"3.9": "ubuntu:22.04",
182+
"3.10": "ubuntu:22.04",
183+
"3.11": "ubuntu:22.04",
184+
"3.12": "ubuntu:22.04"
185+
}
163186
},
164187
"images": [
165188
"build"
@@ -177,12 +200,14 @@
177200
},
178201
"nodejs": {
179202
"base_images": {
180-
"10": "ubuntu:18.04",
181-
"12": "ubuntu:18.04",
182-
"14": "ubuntu:18.04",
183-
"16": "ubuntu:18.04",
184-
"18": "ubuntu:22.04",
185-
"20": "ubuntu:22.04"
203+
"x64": {
204+
"10": "ubuntu:18.04",
205+
"12": "ubuntu:18.04",
206+
"14": "ubuntu:18.04",
207+
"16": "ubuntu:18.04",
208+
"18": "ubuntu:22.04",
209+
"20": "ubuntu:22.04"
210+
}
186211
},
187212
"images": [
188213
"build"
@@ -200,16 +225,19 @@
200225
}
201226
}
202227
},
203-
"architecture": ["x64"]
228+
"architecture": ["x64"],
229+
"deployments": ["package"]
204230
},
205231
"openwhisk": {
206232
"languages": {
207233
"python": {
208234
"base_images": {
209-
"3.7": "openwhisk/action-python-v3.7",
210-
"3.9": "openwhisk/action-python-v3.9",
211-
"3.10": "openwhisk/action-python-v3.10",
212-
"3.11": "openwhisk/action-python-v3.11"
235+
"x64": {
236+
"3.7": "openwhisk/action-python-v3.7",
237+
"3.9": "openwhisk/action-python-v3.9",
238+
"3.10": "openwhisk/action-python-v3.10",
239+
"3.11": "openwhisk/action-python-v3.11"
240+
}
213241
},
214242
"images": [
215243
"function"
@@ -228,11 +256,13 @@
228256
},
229257
"nodejs": {
230258
"base_images": {
231-
"10": "openwhisk/action-nodejs-v10",
232-
"12": "openwhisk/action-nodejs-v12",
233-
"14": "openwhisk/action-nodejs-v14",
234-
"18": "openwhisk/action-nodejs-v18",
235-
"20": "openwhisk/action-nodejs-v20"
259+
"x64": {
260+
"10": "openwhisk/action-nodejs-v10",
261+
"12": "openwhisk/action-nodejs-v12",
262+
"14": "openwhisk/action-nodejs-v14",
263+
"18": "openwhisk/action-nodejs-v18",
264+
"20": "openwhisk/action-nodejs-v20"
265+
}
236266
},
237267
"images": [
238268
"function"
@@ -249,6 +279,7 @@
249279
}
250280
}
251281
},
252-
"architecture": ["x64"]
282+
"architecture": ["x64"],
283+
"deployments": ["container"]
253284
}
254285
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
ARG BASE_IMAGE
2+
FROM $BASE_IMAGE
3+
COPY . function/
4+
COPY handler.js .
5+
RUN cd function \
6+
&& npm install --no-package-lock --production \
7+
&& npm cache clean --force
8+
9+
CMD ["handler.handler"]
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
ARG BASE_IMAGE
2+
FROM $BASE_IMAGE
3+
ARG VERSION
4+
ENV PYTHON_VERSION=${VERSION}
5+
6+
COPY . function/
7+
8+
RUN touch function/__init__.py
9+
RUN if test -f "function/requirements.txt.${PYTHON_VERSION}"; then \
10+
pip install --no-cache-dir \
11+
-r function/requirements.txt \
12+
-r function/requirements.txt.${PYTHON_VERSION} \
13+
function/ && \
14+
pip cache purge; \
15+
else \
16+
pip install --no-cache-dir \
17+
-r function/requirements.txt \
18+
function/ && \
19+
pip cache purge; \
20+
fi
21+
22+
CMD ["function/handler.handler"]

docs/build.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ JSON configuration files are needed.
4242

4343
**Build Docker Image** - in this step, we create a new image `function.{platform}.{benchmark}.{language}-{version}`.
4444
Benchmark and all of its dependencies are installed there, and the image can be deployed directly
45-
to the serverless platform. At the moment, this step is used only in OpenWhisk.
45+
to the serverless platform. At the moment, this step is used only on AWS and in OpenWhisk.
4646

4747
## Docker Image Build
4848

docs/modularity.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ This function has been retrieved from the cache and requires refreshing function
340340
In practice, this is often limited to updating logging handlers - see existing implementations for details.
341341

342342
```python
343-
def update_function(self, function: Function, code_package: Benchmark):
343+
def update_function(self, function: Function, code_package: Benchmark, container_deployment: bool, container_uri: str):
344344
```
345345

346346
This function updates the function's code and configuration in the platform.

docs/platforms.md

+10
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@ points for each platform.
1212
> [!WARNING]
1313
> On many platforms, credentials can be provided as environment variables or through the SeBS configuration. SeBS will not store your credentials in the cache. When saving results, SeBS stores user benchmark and experiment configuration for documentation and reproducibility, except for credentials that are erased. If you provide the credentials through JSON input configuration, do not commit nor publish these files anywhere.
1414
15+
### Architectures
16+
17+
By default, SeBS defaults functions built for the x64 (x86_64) architecture. On AWS, functions can also be build and deployed for ARM CPUs to benefit from Graviton CPUs available on Lambda.
18+
This change primarily affects functions that make use of dependencies with native builds, such as `torch`, `numpy` or `ffmpeg`.
19+
20+
Such functions can be build as code packages on any platforms, as we rely on package managers like pip and npm to provide binary dependencies.
21+
However, special care is needed to build Docker containers: since installation of packages is a part of the Docker build, we cannot natively execute
22+
binaries based on ARM containers on x86 CPUs. To build multi-platform images, we recommend to follow official [Docker guidelines](https://docs.docker.com/build/building/multi-platform/#build-multi-platform-images) and provide static QEMU installation.
23+
On Ubuntu-based distributions, this requires installing an OS package and executing a single Docker command to provide seamless emulation of ARM containers.
24+
1525
### Cloud Account Identifiers
1626

1727
SeBS ensures that all locally cached cloud resources are valid by storing a unique identifier associated with each cloud account. Furthermore, we store this identifier in experiment results to easily match results with the cloud account or subscription that was used to obtain them. We use non-sensitive identifiers such as account IDs on AWS, subscription IDs on Azure, and Google Cloud project IDs.

docs/usage.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ For each command you can pass `--verbose` flag to increase the verbosity of the
44
By default, all scripts will create a cache in the directory `cache` to store code with
55
dependencies and information on allocated cloud resources.
66
Benchmarks will be rebuilt after a change in source code is detected.
7-
To enforce redeployment of code and benchmark inputs please use flags `--update-code`
8-
and `--update-storage`, respectively.
7+
To enforce redeployment of code, benchmark inputs, container deployment (supported in AWS) please use flags `--update-code`, `--update-storage` and `--container-deployment` respectively.
98

109
**Note:** The cache does not support updating the cloud region. If you want to deploy benchmarks
1110
to a new cloud region, then use a new cache directory.

requirements.aws.txt

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,4 @@ boto3
22
botocore
33
flake8-boto3
44
urllib3
5-
boto3-stubs
6-
boto3-stubs[lambda,s3,apigatewayv2,sts,logs,iam]
5+
boto3-stubs[lambda,s3,apigatewayv2,sts,logs,iam,ecr]

requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ scipy
1818
#
1919
pycurl>=7.43
2020
click>=7.1.2
21+
rich
2122

0 commit comments

Comments
 (0)