Code Monkey home page Code Monkey logo

aws-lambda-layer-kubectl's Introduction

lambda-layer-kubectl

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.

Features

  • 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.

Current Version

kubectl 1.14.16
awscli 1.16.292
helm 3.0.0
jq 1.6
GNU Make 3.82

Layer structure

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

Supported Lambda Runtime

lambda runtime runtime attribute name in CFN/SAM Remarks
Custom Runtime provided you need bundle the bootstrap in your lambda function bundle(example)

HOWTO

You may install the Layer from SAR or just build it from scratch.

OPTION #1 - Install from SAR(Serverless App Repository)

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.

Deploy from SAR console

Region Click and Deploy
ap-northeast-1
ap-east-1
ap-northeast-2
ap-northeast-3
ap-south-1
ap-southeast-1
ap-southeast-2
ca-central-1
eu-central-1
eu-north-1
eu-west-1
eu-west-2
eu-west-3
me-south-1
sa-east-1
us-east-1
us-east-2
us-west-1
us-west-2

Deploy with AWS CDK

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

Deploy with AWS CLI

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.

OPTION #2 - Build from scratch

  1. 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
  1. 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)

  1. 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

Required Policy for Lambda IAM Role

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": "*"
        }
    ]
}
  1. 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.

Write your first Lambda function with the kubectl lambda layer

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.

  1. 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.

Test and Validate

To kubeclt get nodes, kubectl get pods or kubectl apply -f REMOTE_URL just edit main.shas 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

clean up the function

$ make sam-destroy

clean up the layer

$ make sam-layer-destroy

You're done!

More Samples

check samples directory

Cross-Accounts Access

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.

License Summary

This sample code is made available under the MIT-0 license. See the LICENSE file.

aws-lambda-layer-kubectl's People

Contributors

doublej472 avatar jpeddicord avatar pahud avatar swoldemi avatar walkley avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.