AWS – Lambda: kubectl

An example of how you can create entities in Kubernetes using AWS Lambda.

The function will be in Python3, so we will use Kubernetes Python Client

More usage examples can be found here.

Since AWS Lambda does not support this package, we will pack the “kubernetes” and “boto3” modules in our function.

“boto3” is needed to access AWS SSM, where kubeconfig will be stored

 

Preparation

Create a directory for the lambda and go to it:

mkdir lambda
cd lambda

 

Next you will need “virtualenv“, if it is not there, you can install it using “pip3“:

pip3 install virtualenv

 

Create a virtual environment and activate it:

python3 -m virtualenv .
source bin/activate

 

And install the necessary modules:

pip3 install kubernetes
pip3 install boto3

 

Next, we only need the contents of this directory:

$VIRTUAL_ENV/lib/python3.7/site-packages

 

python3.7” – replace with your version of Python

 

It will be more convenient to look at the environment path and copy the contents to a separately created directory, no longer in a virtual environment:

echo $VIRTUAL_ENV/lib/python3.7/site-packages
/private/tmp/lambda/lib/python3.7/site-packages

 

Let’s create a directory for lambda, which we will already directly download and copy our modules:

mkdir ~/lambda_upload
cp -R /private/tmp/lambda/lib/python3.7/site-packages/. ~/lambda_upload/

 

SSM Parameter Store

In the AWS console, go to “Systems Manager” -> “Parameter Store

 

And create a parameter with the type “SecureString” and copy the contents of the “kubeconfig” file as the value. If this is an EKS, first create a service account so that it does not require AWS authorization, as in the example below:

Kubeconfig with AWS authorization:

...
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1alpha1
      args:
      - --region
      - eu-central-1
      - eks
      - get-token
      - --cluster-name
      - artem-services-stage-eks
      command: aws

 

Function

Now in the directory “~/lambda_upload” create a file called “lambda_function.py” and paste the following text into it:

lambda_function.py:

import os
import time
import random
import string
import boto3

from kubernetes import config
from kubernetes.client import Configuration
from kubernetes.client.api import core_v1_api
from kubernetes.client.rest import ApiException
from kubernetes.stream import stream

# Get Kubeconfig from SSM
def get_kube_config():
    awsRegion = os.environ['AWS_REGION']
    ssmParameter = os.environ['SSM']

    ssm = boto3.client('ssm', region_name=awsRegion)
    parameter = ssm.get_parameter(Name=ssmParameter, WithDecryption=True)

    kubeconfig = open( '/tmp/kubeconfig.yaml', 'w' )
    kubeconfig.write(parameter['Parameter']['Value'])
    kubeconfig.close()

# Generate random string for unique name of Pod
def randomString(stringLength=8):
    letters = string.ascii_lowercase + string.digits
    return ''.join(random.choice(letters) for i in range(stringLength))

def exec_commands(api_instance):
    name = "busybox-" + randomString()
    namespace = "default"
    resp = None

    print("Creating pod...")

    pod_manifest = {
        'apiVersion': 'v1',
        'kind': 'Pod',
        'metadata': {
            'name': name
        },
        'spec': {
            'containers': [{
                'image': 'busybox',
                'name': 'busybox',
                "args": [
                    "/bin/sh",
                    "-c",
                    "while true;do date;sleep 5; done"
                ]
            }]
        }
    }
    resp = api_instance.create_namespaced_pod(body=pod_manifest, namespace=namespace)

    while True:
        resp = api_instance.read_namespaced_pod(name=name, namespace=namespace)
        if resp.status.phase == 'Pending' or resp.status.phase == 'Running':
            print("Done. Pod " + name + " was created.")
            break
        time.sleep(1)

def main(event, context):
    get_kube_config()

    config.load_kube_config(config_file="/tmp/kubeconfig.yaml")
    c = Configuration()
    c.assert_hostname = False
    Configuration.set_default(c)
    core_v1 = core_v1_api.CoreV1Api()

    exec_commands(core_v1)


if __name__ == '__main__':
    main()

 

Now all the contents of the directory can be packed into a “zip” archive and loaded into the Lambda function.

In a variable environment, create 2 variables in which indicate your AWS Region and the name of the SSM Parameter Store that you created earlier.

 

Lambda functions require read permissions from SSM, so attach the following policy to the role that Lambda uses:

arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess

 

After starting the function, it will create a pod named “busybox-” + the generated string of 8 characters. There is no pod status check, since this script is planned to be used for EKS Fargate, so as not to wait 1-2 minutes until the Fargate instance will running, so in any of the conditions, “Pending” or “Running“, we consider that the pod was successful created.

Tagged: Tags

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments