Migrate AWS Lambda to Knative over AWS EKS (TypeScript with nodejs14)

Memo of the migrating steps

Create docker images

  • Assume your function is in path functions/FUNC_FOLDER/app.ts and export function lambdaHandler

  • Change the labmda function to set region explicitely before executing the lambda

// e.g., put in in constants.ts and then import it to your lambda
import AWS from 'aws-sdk';
if (!process.env.AWS_DEFAULT_REGION) {
    throw new Error('[ERROR][process.env.AWS_DEFAULT_REGION ] process.env.AWS_DEFAULT_REGION  must be not empty')

AWS.config.update({ region: process.env.AWS_DEFAULT_REGION });
  • We need to containerize our AWS Lambda functions into containers with layers
FROM public.ecr.aws/lambda/nodejs:14
# Alternatively, you can pull the base image from Docker Hub: amazon/aws-lambda-nodejs:12

# the function entry point is in dist/functions/FUNC_FOLDER/
# with name app.js, exported function lambdaHandler
COPY package.json dist/functions/FUNC_FOLDER/. ${LAMBDA_TASK_ROOT}
RUN mkdir -p /opt 
## assume your common layer is here
COPY dist/common  /opt/nodejs

# Install NPM dependencies for function
RUN npm install; cp -r node_modules /opt/nodejs/
RUN ls /opt/nodejs/

# Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile)
CMD [ "app.lambdaHandler" ]  
  • Prepare env file for AWS credentials
# .env.knative
  • Build the docker image and serve
# typescript compilation
# build and serve
docker build -t hello-world . 
docker run --env-file .env.knative -p 9000:8080 hello-world
  • Test

    • Create testing file
      • Assume the file path ./lambda-test/FUNC_FOLDER/event.EVENT_NAME.json
        "headers": {
            "Authorization": "Bearer eyJhbGciOiJSUzI1Ni*****"
        "body": "",
        "queryStringParameters": {},
        "httpMethod": "GET",
        "path": "/FUNC_FOLDER/EVENT_NAME"
    curl -X POST  -H \"Content-Type: application/json\"  \"http://localhost:9000/2015-03-31/functions/function/invocations\" -d @./lambda-test/FUNC_FOLDER/event.EVENT_NAME.json

    You should see the return by now

Install EKS

eksctl create cluster

Istio and Knative


curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.13.2 sh -
istio-1.13.2/istioctl install --set profile=default -y
kubectl apply -f istio-1.13.2/samples/addons/prometheus.yaml
kubectl apply -f istio-1.13.2/samples/addons/jaeger.yaml
kubectl apply -f istio-1.13.2/samples/addons/kiali.yaml
kubectl apply -f istio-1.13.2/samples/addons/grafana.yaml
kubectl -n istio-system get svc kiali


brew install kn
kubectl create namespace knative-serving
kubectl label namespace knative-serving istio-injection=enabled
kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.3.0/serving-crds.yaml
kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.3.0/serving-core.yaml
kubectl apply -l knative.dev/crd-install=true -f https://github.com/knative/net-istio/releases/download/knative-v1.3.0/istio.yaml
kubectl apply -f https://github.com/knative/net-istio/releases/download/knative-v1.3.0/net-istio.yaml

kubectl get pods -n knative-serving

kubectl patch configmap/config-network \
  --namespace knative-serving \
  --type merge \
  --patch '{"data":{"ingress.class":"istio.ingress.networking.knative.dev"}}'

kubectl --namespace istio-system get service istio-ingressgateway

Route 53

  • Make sure to add a CNAME with your new wildcard domain
    e.g. *.eks.xiaofang.me CNAME ****-****.us-east-1.elb.amazonaws.com
kubectl patch configmap/config-domain \
  --namespace knative-serving \
  --type merge \
  --patch '{"data":{"eks.xiaofang.me":""}}'

Test Knative

kn service -n default create hello \
--image gcr.io/knative-samples/helloworld-go \
--port 80 \
--env TARGET=World \

kn service list 
curl http://hello.default.eks.xiaofang.me 

Enable auto TLS

  • TBD

Deploy your AWS lambda docker images into Knative

  • Push docker to AWS ECR