aws-lambda-layer-kubectl is an AWS Lambda Layer that encapsulates all the required assets to interact with Amazon EKS control plane and help you directly kubectl
against Amazon EKS in AWS Lambda.
- Ships all the required assests including kubectl, aws-cli, make and jq Just include the layer and you get everything required.
- Helm 3 included.
- Amazon EKS authentication under the hood on bootstrap.
kubectl | 1.14.16 |
---|---|
awscli | 1.16.292 |
helm | 3.0.0 |
jq | 1.6 |
GNU Make | 3.82 |
You got the layer structure as below under /opt
in lambda custom runtime:
.
├── awscli
│ ├── PyYAML-5.1.2-py2.7.egg-info
│ ├── aws
│ ├── awscli
│ ├── awscli-1.16.292-py2.7.egg-info
│ ├── bin
│ ├── botocore
│ ├── botocore-1.13.28-py2.7.egg-info
│ ├── colorama
│ ├── colorama-0.4.1-py2.7.egg-info
│ ├── concurrent
│ ├── dateutil
│ ├── docutils
│ ├── docutils-0.15.2-py2.7.egg-info
│ ├── easy_install.py
│ ├── easy_install.pyc
│ ├── futures-3.3.0-py2.7.egg-info
│ ├── jmespath
│ ├── jmespath-0.9.4-py2.7.egg-info
│ ├── jq
│ ├── make
│ ├── pkg_resources
│ ├── pyasn1
│ ├── pyasn1-0.4.8-py2.7.egg-info
│ ├── python_dateutil-2.8.0-py2.7.egg-info
│ ├── rsa
│ ├── rsa-3.4.2-py2.7.egg-info
│ ├── s3transfer
│ ├── s3transfer-0.2.1-py2.7.egg-info
│ ├── six-1.13.0-py2.7.egg-info
│ ├── six.py
│ ├── six.pyc
│ ├── urllib3
│ ├── urllib3-1.25.7-py2.7.egg-info
│ ├── wheel
│ ├── wheel-0.29.0.dist-info
│ └── yaml
├── helm
│ └── helm
└── kubectl
└── kubectl
32 directories, 9 files
lambda runtime | runtime attribute name in CFN/SAM | Remarks |
---|---|---|
Custom Runtime | provided | you need bundle the bootstrap in your lambda function bundle(example) |
You may install the Layer from SAR
or just build it from scratch.
This is the recommended approach. We deploy the kubectl lambda layer straight from SAR(Serverless App Repository)
You may deploy it from the console, AWS CDK or CLI.
import cdk = require('@aws-cdk/core');
import sam = require('@aws-cdk/aws-sam');
import lambda = require('@aws-cdk/aws-lambda');
// Keep the class name stable please
export class AppStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const samApp = new sam.CfnApplication(this, 'SamLayer', {
location: {
applicationId: 'arn:aws:serverlessrepo:us-east-1:903779448426:applications/lambda-layer-kubectl',
semanticVersion: '2.0.0-beta1'
},
parameters: {
LayerName: `${this.stackName}-kubectl-layer`
}
})
const layerVersionArn = samApp.getAtt('Outputs.LayerVersionArn').toString();
new cdk.CfnOutput(this, 'LayerVerionArn', { value: layerVersionArn })
}
}
or play with it at https://play-with-cdk.com?s=99acb08caf74fc982ebfa931da476888
Alternatively, you may deploy it with AWS CLI.
$ APP_ID='arn:aws:serverlessrepo:us-east-1:903779448426:applications/lambda-layer-kubectl'
$ LATEST_VERSION=$(aws serverlessrepo get-application --application-id ${APP_ID} --query 'Version.SemanticVersion' --output text)
$ aws --region ${REGION_CODE_TO_DEPLOY} serverlessrepo create-cloud-formation-template \
--application-id ${APP_ID} \
--semantic-version ${LATEST_VERSION}
{
"Status": "PREPARING",
"TemplateId": "89be5908-520b-4911-bde7-71bf73040e47",
"CreationTime": "2019-02-20T14:51:56.826Z",
"SemanticVersion": "...",
"ExpirationTime": "2019-02-20T20:51:56.826Z",
"ApplicationId": "arn:aws:serverlessrepo:us-east-1:903779448426:applications/lambda-layer-kubectl",
"TemplateUrl": "..."
}
(change REGION_CODE_TO_DEPLOY
to the region code to deploy this layer(e.g. ap-northeast-1
or us-west-2
)
Copy the TemplateUrl
value and deploy with cloudformation create-stack
aws --region ${REGION_CODE_TO_DEPLOY} cloudformation create-stack --template-url {TemplateUrl} --stack-name {StackName} --capabilities CAPABILITY_AUTO_EXPAND \
--parameter ParameterKey=LayerName,ParameterValue=lambda-layer-kubectl
On stack create complete, get the stack outputs as below
$ aws --region ${REGION_CODE_TO_DEPLOY} cloudformation describe-stacks --stack-name {StackName} --query 'Stacks[0].Outputs'
[
{
"Description": "ARN for the published Layer version",
"ExportName": "LayerVersionArn-{StackName}",
"OutputKey": "LayerVersionArn",
"OutputValue": "arn:aws:lambda:ap-northeast-1:123456789012:layer:lambda-layer-kubectl:1"
}
]
Now you got your own private Lambda Layer Arn for lambda-layer-kubectl
.
- check out this repository
$ curl -L -o lambda-layer-kubectl.zip https://github.com/pahud/lambda-layer-kubectl/archive/master.zip
$ unzip lambda-layer-kubectl.zip
$ cd lambda-layer-kubectl-master
or just
$ git clone https://github.com/aws-samples/aws-lambda-layer-kubectl.git
- build the
layer.zip
bundle
# build the layer locally and bundle everything into a layer.zip file
$ make build
(this may take a moment to complete)
- edit the
Makefile
Name | Description | required to update |
---|---|---|
LAYER_NAME | Layer Name | |
LAYER_DESC | Layer Description | |
INPUT_JSON | input json payload file for lambda invocation | |
S3BUCKET | Your S3 bucket to store the intermediate Lambda bundle zip. Make sure the S3 bucket in the same region with your Lambda function to deploy. |
YES |
LAMBDA_REGION | The region code to deploy your Lambda function | |
LAMBDA_FUNC_NAME | Lambda function name | |
LAMBDA_ROLE_ARN | Lambda IAM role ARN | YES |
Please note your IAM role for Lambda will need eks:DescribeCluster
as well as other ec2 read-only privileges depending on what you intend to do in your Lambda function. You may attach an inline policy as below to your Lambda IAM role.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:DescribeTags",
"eks:DescribeCluster"
],
"Resource": "*"
}
]
}
- Deploy the Layer
# deploy and publish the layer.zip as a layer version
$ make sam-layer-deploy
This will deploy the layer.zip
and publish as a new layer version.
OK. Now your layer is ready.
Please copy the value of OutputValue
.
Now your kubectl layer is ready, you can write a Lambda function with custom runtime to run a bash script and execute the kubectl
executable provided from the layer.
Behind the scene, the Lambda custom runtime will execute the bootstrap
executable to generate kubeconfig
automatically(see details) followed by running the main.sh
and all we need to is simply implement our logic in the main.sh
. The following example demonstrates how to deploy a lambda custom runtime with a provided bootstrap
executable that invokes main.sh
and we just need to script in main.sh
to run regular kubectl
commands.
Let's deploy the provided lambda function sample with the provided Makefile.
prepare the function and populate into ./func.d
# copy everything required to ./func.d directory
$ make func-prep
you got the following files in ./func.d
directory
$ tree -L 2 ./func.d/
./func.d/
├── bootstrap
├── libs.sh
└── main.sh
0 directories, 3 files
Let's deploy our lambda func with SAM
. Let's say if our EKS cluster name is eksnrt
, we'd deploy the function like this:
$ CLUSTER_NAME=eksnrt make sam-deploy
If you check the lambda function you'll see an environment variable cluster_name=eksnrt
is assigned, which will be processed with kubectl
in Lambda.
- Enable Lambda function to call Amazon EKS master API
Update the aws-auth-cm.yaml
described in Amazon EKS User Guide - getting started. Add an extra rolearn
section as below to allow your Lambda function map its role as system:masters
in RBAC.
To kubeclt get nodes
, kubectl get pods
or kubectl apply -f REMOTE_URL
just edit main.sh
as below
#!/bin/bash
# pahud/lambda-layer-kubectl for Amazon EKS
# include the common-used shortcuts
source libs.sh
# with shortcuts(defined in libs.sh)
echo "[INFO] listing the nodes..."
get_nodes
echo "[INFO] listing the pods..."
get_pods
# or go straight with kubectl
echo "[INFO] listing the nodes..."
kubectl get no
echo "[INFO] listing the pods..."
kubectl get po
# to specify different ns
echo "[INFO] listing the pods..."
kubectl -n kube-system get po
# kubectl apply -f REMOTE_URL
kubectl apply -f http://SOME_REMOTE_URL
# kubectl delete -f REMOTE_URL
kubectl delete -f http://SOME_REMOTE_URL
exit 0
And publish your function again
$ CLUSTER_NAME=eksnrt make func-prep sam-package sam-deploy
Invoke
$ INPUT_YAML=nginx.yaml make invoke
Response
To pass through the local yaml
file to lambda and execute kubectl apply -f
#!/bin/bash
# pahud/lambda-layer-kubectl for Amazon EKS
# include the common-used shortcuts
source libs.sh
data=$(echo $1 | jq -r .data | base64 -d)
echo "$data" | kubectl apply -f - 2>&1
exit 0
Update the function
$ CLUSTER_NAME=eksnrt make func-prep sam-package sam-deploy
Invoke
$ INPUT_YAML=nginx.yaml make invoke
Response
To specify different cluster_name
with the default one in environment variable:
$ CLUSTER_NAME="another_cluster_name" INPUT_YAML=nginx.yaml make invoke
kubectl apply -f REMOTE_URL
like this
$ INPUT_YAML_URLS="URL1 URL2 URL3" make invoke
e.g.
I hope you find it useful and have fun with this project! Issues and PRs are very appreciated.
clean up the function
$ make sam-destroy
clean up the layer
$ make sam-layer-destroy
You're done!
check samples directory
In some cases, you may need cross-account access to different Amazon EKS clusters. The idea is to generate different kubeconfig files and feed the lambda function via environment variables. Check this sample for more details.
This sample code is made available under the MIT-0 license. See the LICENSE file.