AWS CodeDeploy jar - amazon-web-services

I want to use AWS CodeDeploy to deploy a jar file and then run my java -jar command from there once it is on the EC2. But I've noticed that AWS CodeDeploy only pulls zip, tar and tar.gz` from S3. I'm thinking I will use CLI from my local jenkins to push a .zip file (containing the jar) to S3, then run another CLI command to start AWS CodeDeploy which will pull the .zip from S3.
However I do have a question the details on AWS CodeDeploy:
Can I use the appspec.yml to issue two commands,
1) unzip the .zip from S3 once it is on the EC2
2) Issue the java -jar on a specific location?
Thanks

1) You do not need issue an unzip command, the files section in appspec.yml is used to specify the files in your archive (source) you wish to copy to the file system on ec2 (destination) and will be done by the code deploy agent RE https://docs.aws.amazon.com/codedeploy/latest/userguide/reference-appspec-file-structure-files.html
2) Create a run script to issue java -jar command under the hook ApplicaitonStart
RE https://docs.aws.amazon.com/codedeploy/latest/userguide/reference-appspec-file-structure-hooks.html
Example appspec.yml on os linux based:
version: 0.0
os: linux
files:
- source: ./
destination: /home/ubuntu/myapp
hooks:
ApplicationStart:
- location: runapp.sh
runas: ubuntu
runapp.sh:
#!/usr/bin/env bash
echo 'Starting my app'
cd '/home/ubuntu/myapp'
java -jar myapp.jar
In this example, you would include runapp.sh in your deployment package

Related

How to pass command line arguments to a jar in aws beanstalk from jenkins pipeline?

i am able to transfer files from my Jenkins to AWS S3 bucket.Also i am able to create an environment in AWS Elastic beanstalk and the jar is running,However suppose i want to pass any command line arguements alongwith my jar and make it run then what should be the syntax in Jenkins Pipeline declarative code?
This is resolved
We need to create a Procfile which will have commands like
web: java -Xmx4096m -jar ${application-jar name}.jar
We need to zip the application jar alongwith Procfile along with any files which we are passing through command line arguments while making our application run.
This zip file once we upload to s3 bucket then in elastic beanstalk this zip file is used and the application is run by the command we pass in Procfile

AWS Elastic Beanstalk - Running powershell command not executed on .ebextensions

I am running this command to install web socket protocols in my AWS Elastic Beanstalk EC2 server
commands:
01_install_websockets:
command: "powershell.exe Install-WindowsFeature -name Web-WebSockets"
ignoreErrors: false
02_install_iis_websockets_feature:
command: "powershell.exe Enable-WindowsOptionalFeature -Online -FeatureName IIS-WebSockets"
ignoreErrors: false
The command above was not executed in my server, running those script in the EC2 manually always works but doing this using .ebextensions does not work.
Here's the structure of my code.
And when this one is published, the .ebextensions is added at the root of the zip file
zip
- .ebextensions
- other files...
Please let me know what's missing here. I don't do any special configurations on the AWS EB.
I am able to run with following steps:
I am using container_commands but, I am confident it will work with commands as well.
---
container_commands:
"2":
command: powershell.exe -ExecutionPolicy Bypass -Command".\\.ebextensions\\IISScripts.ps1"
Zip file looks like below:
zip
- .ebextensions
- 01-windows.config
- IISScript.ps1
- other files...
EC2 instance configuration: Windows server 2019

How to upload and deploy zip file to AWS elastic beanstalk via CLI?

I do not want to use the console. No manual processes. I need a command line version, something that I can code in my continuous deployment scripts.
As part of the build process, I can output a ZIP file (be it on my local machine or in CI process, e.g: via bitbucket pipelines or AWS codedeploy VM instance).
I want a command like:
aws eb deploy my-app ./server.zip
That is, first upload my chosen zip file and then deploy it (doesn't have to be one command).
The official eb deploy does not seem to support this, nor have I been able to find any other method to do this.
Any ideas would be much appreciated :)
I don't think eb CLI supports uploading a ZIP and updating an environment but you can use a combination of AWS CLI commands.
Upload the ZIP to S3
Create an application version
Update the environment
Example,
aws s3 cp deploy.zip s3://mybucket/deploy.zip
aws elasticbeanstalk create-application-version --application-name my-app --version-label 12345 --source-bundle S3Bucket="mybucket",S3Key="deploy.zip"
aws elasticbeanstalk update-environment --application-name my-app --environment-name MyApp-env --version-label 12345
I was looking for this answer as well. I was able to find some AWS documentation that lets you use the Elastic Beanstalk CLI configuration to upload the zip.
https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/eb-cli3-configuration.html#eb-cli3-artifact
Deploying an artifact instead of the project folder
You can tell the EB CLI to deploy a ZIP file or WAR file that you generate as part of a separate build process by adding the following lines to .elasticbeanstalk/config.yml in your project folder.
deploy:
artifact: path/to/buildartifact.zip
If you configure the EB CLI in your Git repository, and you don't > commit the artifact to source, use the --staged option to deploy the latest build.
~/eb$ eb deploy --staged
I tested and it did work for me!

AWS CodeBuild - copy yaml file to S3 after successful build

I'm using CodeBuild to build Scala sbt project. during the build I'm doing the following steps.
checkout code from Git.
Install all sbt tools.
Build code.
Create Docker
Publish docker file to AWS ECR
Update K8s deployment file located in project root folder deployment/deployment.yaml with latest vesrion of published image using kustomize utility.
Publish this file to AWS S3 bucket to run further deployment on AWS EKS.
Unfortunately, the last step fails and I can't move this deployment file to AWS S3 bucket.
artifacts:
files:
- deployment/deployment.yaml
discard-paths: yes
base-directory: 'deployment'
What am I doing wrong?
base-directory: 'deployment'
... would mean that CodeBuild will look into 'deployment' directory for "deployment/deployment.yaml" which is probably wrong.
Try this:
artifacts:
files:
- deployment/deployment.yaml
discard-paths: yes
One trick I have found useful is to install 'tree' in my buildspec and inspect the tree structure of directory to make sure I am specifying the correct path.
In Install Phase:
- apt-get install tree
Later in Buildspec:
- tree .

How to increase the maximum size of the AWS lambda deployment package (RequestEntityTooLargeException)?

I upload my lambda function sources from AWS codebuild. My Python script uses NLTK so it needs a lot of data. My .zip package is too big and an RequestEntityTooLargeException occurs. I want to know how to increase the size of the deployment package sent via the UpdateFunctionCode command.
I use AWS CodeBuild to transform the source from a GitHub repository to AWS Lambda. Here is the associated buildspec file:
version: 0.2
phases:
install:
commands:
- echo "install step"
- apt-get update
- apt-get install zip -y
- apt-get install python3-pip -y
- pip install --upgrade pip
- pip install --upgrade awscli
# Define directories
- export HOME_DIR=`pwd`
- export NLTK_DATA=$HOME_DIR/nltk_data
pre_build:
commands:
- echo "pre_build step"
- cd $HOME_DIR
- virtualenv venv
- . venv/bin/activate
# Install modules
- pip install -U requests
# NLTK download
- pip install -U nltk
- python -m nltk.downloader -d $NLTK_DATA wordnet stopwords punkt
- pip freeze > requirements.txt
build:
commands:
- echo 'build step'
- cd $HOME_DIR
- mv $VIRTUAL_ENV/lib/python3.6/site-packages/* .
- sudo zip -r9 algo.zip .
- aws s3 cp --recursive --acl public-read ./ s3://hilightalgo/
- aws lambda update-function-code --function-name arn:aws:lambda:eu-west-3:671560023774:function:LaunchHilight --zip-file fileb://algo.zip
- aws lambda update-function-configuration --function-name arn:aws:lambda:eu-west-3:671560023774:function:LaunchHilight --environment 'Variables={NLTK_DATA=/var/task/nltk_data}'
post_build:
commands:
- echo "post_build step"
When I launch the pipeline, I have RequestEntityTooLargeException because there are too many data in my .zip package. See the build logs below:
[Container] 2019/02/11 10:48:35 Running command aws lambda update-function-code --function-name arn:aws:lambda:eu-west-3:671560023774:function:LaunchHilight --zip-file fileb://algo.zip
An error occurred (RequestEntityTooLargeException) when calling the UpdateFunctionCode operation: Request must be smaller than 69905067 bytes for the UpdateFunctionCode operation
[Container] 2019/02/11 10:48:37 Command did not exit successfully aws lambda update-function-code --function-name arn:aws:lambda:eu-west-3:671560023774:function:LaunchHilight --zip-file fileb://algo.zip exit status 255
[Container] 2019/02/11 10:48:37 Phase complete: BUILD Success: false
[Container] 2019/02/11 10:48:37 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: aws lambda update-function-code --function-name arn:aws:lambda:eu-west-3:671560023774:function:LaunchHilight --zip-file fileb://algo.zip. Reason: exit status 255
Everything works correctly when I reduce the NLTK data to download (I tried with only the packages stopwords and wordnet.
Does anyone have an idea to solve this "size limit problem"?
You cannot increase the deployment package size for Lambda. AWS Lambda limits are described in AWS Lambda developer guide. More information on how those limits work can be seen here. In essence, your unzipped package size has to be less than 250MB (262144000 bytes).
PS: Using layers doesn't solve sizing problem, though helps with management & maybe faster cold start. Package size includes the layers - Lambda layers.
A function can use up to 5 layers at a time. The total unzipped size of the function and all layers can't exceed the unzipped deployment package size limit of 250 MB.
Update Dec 2020 : As per AWS blog, as pointed by user jonnocraig in this answer, you can overcome these restrictions if you build a container for your application & run it on Lambda.
If anyone stumbles across this issue post December 2020, there's been a major update from AWS to support Lambda functions as container images (up to 10GB!!). More info here
AWS Lambda functions can mount EFS. You can load libraries or packages that are larger than the 250 MB package deployment size limit of AWS Lambda using EFS.
Detailed steps on how to set it up are here:
https://aws.amazon.com/blogs/aws/new-a-shared-file-system-for-your-lambda-functions/
On a high level, the changes include:
Create and setup EFS file system
Use EFS with lambda function
Install the pip dependencies inside EFS access point
Set the PYTHONPATH environment variable to tell where to look for the dependencies
The following are hard limits for Lambda (may change in future):
3 MB for in-console editing
50 MB zipped as package for upload
250 MB when unzipped including layers
A sensible way to get around this is to mount EFS from your Lambda. This can be useful not only for loading libraries, but also for other storage.
Have a look through these blogs:
https://aws.amazon.com/blogs/compute/using-amazon-efs-for-aws-lambda-in-your-serverless-applications/
https://aws.amazon.com/blogs/aws/new-a-shared-file-system-for-your-lambda-functions/
I have not tried this myself, but the folks at Zappa describe a trick that might help. Quoting from https://blog.zappa.io/posts/slim-handler:
Zappa zips up the large application and sends the project zip file up to S3. Second, Zappa creates a very minimal slim handler that just contains Zappa and its dependencies and sends that to Lambda.
When the slim handler is called on a cold start, it downloads the large project zip from S3 and unzips it in Lambda’s shared /tmp space. All subsequent calls to that warm Lambda share the /tmp space and have access to the project files; so it is possible for the file to only download once if the Lambda stays warm.
This way you should get 500MB in /tmp.
Update:
I have used the following code in the lambdas of a couple of projects, it is based on the method zappa used, but can be used directly.
# Based on the code in https://github.com/Miserlou/Zappa/blob/master/zappa/handler.py
# We need to load the layer from an s3 bucket into tmp, bypassing the normal
# AWS layer mechanism, since it is too large, AWS unzipped lambda function size
# including layers is 250MB.
def load_remote_project_archive(remote_bucket, remote_file, layer_name):
# Puts the project files from S3 in /tmp and adds to path
project_folder = '/tmp/{0!s}'.format(layer_name)
if not os.path.isdir(project_folder):
# The project folder doesn't exist in this cold lambda, get it from S3
boto_session = boto3.Session()
# Download zip file from S3
s3 = boto_session.resource('s3')
archive_on_s3 = s3.Object(remote_bucket, remote_file).get()
# unzip from stream
with io.BytesIO(archive_on_s3["Body"].read()) as zf:
# rewind the file
zf.seek(0)
# Read the file as a zipfile and process the members
with zipfile.ZipFile(zf, mode='r') as zipf:
zipf.extractall(project_folder)
# Add to project path
sys.path.insert(0, project_folder)
return True
This can then be called as follows (I pass the bucket with the layer to the lambda function via an env variable):
load_remote_project_archive(os.environ['MY_ADDITIONAL_LAYERS_BUCKET'], 'lambda_my_extra_layer.zip', 'lambda_my_extra_layer')
At the time when I wrote this code, tmp was also capped, I think to 250MB, but the call to zipf.extractall(project_folder) above can be replaced with extracting directly to memory: unzipped_in_memory = {name: zipf.read(name) for name in zipf.namelist()}
which I did for some machine learning models, I guess the answer of #rahul is more versatile for this though.
From the AWS documentation:
If your deployment package is larger than 50 MB, we recommend
uploading your function code and dependencies to an Amazon S3 bucket.
You can create a deployment package and upload the .zip file to your
Amazon S3 bucket in the AWS Region where you want to create a Lambda
function. When you create your Lambda function, specify the S3 bucket
name and object key name on the Lambda console, or using the AWS
Command Line Interface (AWS CLI).
You can use the AWS CLI to deploy the package, and instead of using the --zip-file argument to pass the deployment package, you can specify the object in the S3 bucket with the --code parameter. Ex:
aws lambda create-function --function-name my_function --code S3Bucket=my_bucket,S3Key=my_file
This aws wrangler zip file from github (https://github.com/awslabs/aws-data-wrangler/releases) includes many other libraries like pandas and pymysql. In my case it was the only layer I needed since it has so much other stuff. Might work for some people.
You can try the workaround used in the awesome serverless-python-requirements plugin.
Ideal solution is to use lambda layers if it solves the purpose. If the total dependency is greater than 250MB then you can sideload lesser used dependencies from S3 bucket during run time by utilizing the 512 MB provided in /tmp directory. The zipped dependencies are stored in S3 and lambda can fetch the files from S3 during initialisation. Unzip the dependecy pacakge and add the path to sys path.
Please note that the python dependencies need to be built on the Amazon Linux, which is the operating system for lambda containers. I used a EC2 instance to create the zip package.
You check the code used in serverless-python-requirements here
Before 2021, the best way was to deploy the jar file to S3, and create AWS lambda with it.
From 2021, AWS Lambda begin to support container image. Read here : https://aws.amazon.com/de/blogs/aws/new-for-aws-lambda-container-image-support/
So from now on, you should probably consider package and deploy your Lambda functions as container images(up to 10 GB).
The tips to use large lambda project into AWS is to use a docker image store in the AWS ECR service instead of a ZIP file. You can use a docker image up to 10GO.
The AWS documentation provide an example to help you here :
Create an image from an AWS base image for Lambda
May be late to the party but you can use a Docker Image to get around the lambda layer constraint. This can be done using serverless stack development or just through the console.
You cannot increase the package size, but you can use AWS Lambda layers to store some application dependencies.
https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html#configuration-layers-path
Before this layers a common used pattern to workaround this limitation was to download huge dependencies from S3.