> For the complete documentation index, see [llms.txt](https://developer.harness.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.harness.io/continuous-delivery/use-continuous-delivery/deploy-services-on-different-platforms/serverless/serverless-lambda-cd-quickstart.md).

# Serverless.com framework for AWS Lambda

Deploy a Serverless Lambda application to AWS Lambda using Harness.

This topic shows you how to deploy a Serverless Lambda application to AWS Lambda using Harness.

In this topic, you use a publicly-available `serverless.yaml` file and artifact and deploy them to your AWS Lambda service using a Harness Pipeline.

New to Serverless.com Framework? For more information, go to [Tutorial: Your First Serverless Framework Project](https://www.serverless.com/framework/docs/tutorial) from Serverless.

## What you will learn from this topic

* How to [add a `serverless.yaml` file](#add-the-manifest) and [ZIP artifact](#add-the-artifact) to a Harness Pipeline stage.
* How to [define your AWS Lambda service](#define-the-infrastructure) as the deployment target, using [containerized](#containerized-steps) or [non-containerized](#non-containerized-steps) steps.
* How to [deploy the Serverless application](#deploy-and-review) to Lambda and review the deployment.
* Understand [Serverless framework support](#serverless-framework-support) and [Limitations](#limitations), including supported versions and images.

## Overview <a href="#overview" id="overview"></a>

Setting up a Serverless Lambda application involves the following steps:

1. Add a `serverless.yaml` file and ZIP artifact to a Harness Pipeline stage.
2. Define your AWS Lambda service as the deployment target.
3. Deploy the Serverless application to Lambda.

### Serverless Lambda deployment overview <a href="#visual-summary" id="visual-summary"></a>

{% embed url="<https://youtu.be/BiFpg13yJbQ>" %}

## Containerized and non-containerized <a href="#containerized-and-non-containerized" id="containerized-and-non-containerized"></a>

You have two options for deploying a Serverless.com Framework Lambda application:

* **Containerized:** Deploy your Serverless Lambda application in Harness using containerized steps that allow you to select the Serverless image to use for each step.

  For more information about containerized step groups, go to [Containerize step groups](/continuous-delivery/use-continuous-delivery/cd-building-blocks/cd-steps/containerized-steps/containerized-step-groups.md).
* **Non-containerized:** Deploy your Serverless Lambda application in Harness using one or more Serverless versions running on one or more Harness Delegates.

You select whether to use a containerized or non-containerized method in the **Execution** section of your pipeline Deploy stage. This topic covers both methods.

<details>

<summary>Why containerized?</summary>

Not all teams use the same version of the Serverless.com framework. Also, teams use different versions of Serverless packages. This can result in different versions being installed on different delegates, and requires that users select which delegate to use via delegate tags.

Rather than installing and cleaning up the various Serverless versions on delegates, you can use containerized steps to spin up a fresh container with parameters like:

* Serverless.com version
* Serverless plugins
* Jobs execution using Serverless.

Once a containerized step is run, Harness terminates the container.

</details>

## Before you begin <a href="#before-you-begin" id="before-you-begin"></a>

Review [Harness Key Concepts](https://developer.harness.io/harness-platform/new-to-harness-platform/overview) to establish a general understanding of Harness.

This quickstart requires the following:

* **GitHub account:** This quickstart uses a publicly available `serverless.yaml` file, but GitHub requires that you use a GitHub account for fetching files.
* **(Non-containerized) Harness Delegate with Serverless installed:** The Harness Delegate is a worker process that performs all deployment tasks. Typically, you will install a Kubernetes delegate in your own cluster.
  * You can use a cluster hosted on a cloud platform or run one in minikube using Docker Desktop locally. The installation steps are the same.
  * The delegate pod(s) must have Serverless installed. This quickstart adds the Serverless installation script using the delegate environment variable `INIT_SCRIPT` to the delegate YAML file later in this quickstart.
* **(Containerized) Kubernetes cluster and namespace where each container will run:** Each containerized step runs in a Kubernetes cluster you provide.
* **AWS User account with required policy:** Serverless deployments require an AWS User with specific AWS permissions, as described in [AWS Credentials](https://www.serverless.com/framework/docs/providers/aws/guide/credentials) from Serverless.com. To create the AWS User, do the following:
  * Log in to your AWS account and go to the Identity & Access Management (IAM) page.
  * Click **Users**, and then **Add user**. Enter a name. Enable **Programmatic access** by selecting the checkbox. Click **Next** to go to the **Permissions** page. Do one of the following:
    * View and copy the API Key and Secret to a temporary place. You need them when setting up the Harness AWS Connector later in this quickstart.
    * **Full Admin Access:** Click **Attach existing policies directly**. Search for and select **AdministratorAccess**, and then click **Next: Review**. Verify the settings and click **Create user**.
    * **Limited Access:** Click **Create policy**. Select the **JSON** tab, and add the JSON using the following code from the [Serverless gist](https://gist.github.com/ServerlessBot/7618156b8671840a539f405dea2704c8) IAMCredentials.json:

<details>

<summary>IAMCredentials.json</summary>

```json
{
  "Statement": [
    {
      "Action": [
        "apigateway:*",
        "cloudformation:CancelUpdateStack",
        "cloudformation:ContinueUpdateRollback",
        "cloudformation:CreateChangeSet",
        "cloudformation:CreateStack",
        "cloudformation:CreateUploadBucket",
        "cloudformation:DeleteStack",
        "cloudformation:DeleteChangeSet",
        "cloudformation:Describe*",
        "cloudformation:EstimateTemplateCost",
        "cloudformation:ExecuteChangeSet",
        "cloudformation:Get*",
        "cloudformation:List*",
        "cloudformation:UpdateStack",
        "cloudformation:UpdateTerminationProtection",
        "cloudformation:ValidateTemplate",
        "dynamodb:CreateTable",
        "dynamodb:DeleteTable",
        "dynamodb:DescribeTable",
        "dynamodb:DescribeTimeToLive",
        "dynamodb:UpdateTimeToLive",
        "ec2:AttachInternetGateway",
        "ec2:AuthorizeSecurityGroupIngress",
        "ec2:CreateInternetGateway",
        "ec2:CreateNetworkAcl",
        "ec2:CreateNetworkAclEntry",
        "ec2:CreateRouteTable",
        "ec2:CreateSecurityGroup",
        "ec2:CreateSubnet",
        "ec2:CreateTags",
        "ec2:CreateVpc",
        "ec2:DeleteInternetGateway",
        "ec2:DeleteNetworkAcl",
        "ec2:DeleteNetworkAclEntry",
        "ec2:DeleteRouteTable",
        "ec2:DeleteSecurityGroup",
        "ec2:DeleteSubnet",
        "ec2:DeleteVpc",
        "ec2:Describe*",
        "ec2:DetachInternetGateway",
        "ec2:ModifyVpcAttribute",
        "events:DeleteRule",
        "events:DescribeRule",
        "events:ListRuleNamesByTarget",
        "events:ListRules",
        "events:ListTargetsByRule",
        "events:PutRule",
        "events:PutTargets",
        "events:RemoveTargets",
        "iam:AttachRolePolicy",
        "iam:CreateRole",
        "iam:DeleteRole",
        "iam:DeleteRolePolicy",
        "iam:DetachRolePolicy",
        "iam:GetRole",
        "iam:PassRole",
        "iam:PutRolePolicy",
        "iam:TagRole",
        "iot:CreateTopicRule",
        "iot:DeleteTopicRule",
        "iot:DisableTopicRule",
        "iot:EnableTopicRule",
        "iot:ReplaceTopicRule",
        "kinesis:CreateStream",
        "kinesis:DeleteStream",
        "kinesis:DescribeStream",
        "lambda:*",
        "logs:CreateLogGroup",
        "logs:DeleteLogGroup",
        "logs:DescribeLogGroups",
        "logs:DescribeLogStreams",
        "logs:FilterLogEvents",
        "logs:GetLogEvents",
        "logs:PutSubscriptionFilter",
        "s3:GetBucketLocation",
        "s3:CreateBucket",
        "s3:DeleteBucket",
        "s3:DeleteBucketPolicy",
        "s3:DeleteObject",
        "s3:DeleteObjectVersion",
        "s3:GetObject",
        "s3:GetObjectVersion",
        "s3:ListAllMyBuckets",
        "s3:ListBucket",
        "s3:PutBucketNotification",
        "s3:PutBucketPolicy",
        "s3:PutBucketTagging",
        "s3:PutBucketWebsite",
        "s3:PutEncryptionConfiguration",
        "s3:PutObject",
        "sns:CreateTopic",
        "sns:DeleteTopic",
        "sns:GetSubscriptionAttributes",
        "sns:GetTopicAttributes",
        "sns:ListSubscriptions",
        "sns:ListSubscriptionsByTopic",
        "sns:ListTopics",
        "sns:SetSubscriptionAttributes",
        "sns:SetTopicAttributes",
        "sns:Subscribe",
        "sns:Unsubscribe",
        "states:CreateStateMachine",
        "states:DeleteStateMachine"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ],
  "Version": "2012-10-17"
}
```

The `s3:GetBucketLocation` action is required for a custom S3 bucket only.

</details>

* AWS OIDC connectors are supported for Serverless V2 deployments starting with delegate version `857xx` or later.

## Use AWS IRSA for Harness AWS connector credentials <a href="#use-aws-irsa-for-harness-aws-connector-credentials" id="use-aws-irsa-for-harness-aws-connector-credentials"></a>

The **Use IRSA** option allows the Harness Kubernetes delegate in AWS EKS to use a specific IAM role when making authenticated requests to resources. This option is also necessary if the delegate uses IRSA on an EKS cluster with OIDC Provider.

{% hint style="info" %}
This configuration has been tested exclusively on clusters created with eksctl. If you create the cluster by another method, such as Terraform or CloudFormation, you might encounter unknown issues.
{% endhint %}

By default, the Harness Kubernetes delegate uses a ClusterRoleBinding to the **default** service account. Instead, with this option, you can use AWS [IAM roles for service accounts (IRSA)](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) to associate a specific IAM role with the service account used by the Harness Kubernetes delegate.

1. Verify your firewall policy and make sure to allowlist all AWS endpoints for the services you use. For more details, go to [view AWS service endpoints](https://docs.aws.amazon.com/general/latest/gr/rande.html#view-service-endpoints).
2. Modify your delegate YAML, as described in the following section.

<details>

<summary>Configure delegate YAML for IRSA</summary>

To configure the delegate YAML for IRSA, do the following:

1. Create the IAM role with the policies you want the Delegate to use. The policies you select depend on what AWS resources you are deploying via the delegate.
2. In the cluster where the delegate will be installed, create a service account and attach the IAM role to it. The following example creates a new service account in the cluster where you will install the delegate and attaches the IAM policy to it:

   ```bash
   eksctl create iamserviceaccount \
       --name=cdp-admin \
       --namespace=harness-delegate-ng \
       --cluster=test-eks \
       --attach-policy-arn=<policy-arn> \
       --approve \
       --override-existing-serviceaccounts \
       --region=us-east-1
   ```
3. In Harness, download the Harness Kubernetes delegate YAML file. For instructions, go to [Install a Kubernetes delegate](https://developer.harness.io/harness-platform/troubleshooting-and-resources/tutorials/install-delegate).
4. Open the delegate YAML file in a text editor.
5. Add the service account with access to IAM role to the delegate YAML. There are two sections in the Delegate YAML that you must update:

   1. Update the `ClusterRoleBinding` by replacing the subject name `default` with the name of the service account with the attached IAM role, for example:

      ```yaml
      ---
      apiVersion: rbac.authorization.k8s.io/v1beta1
      kind: ClusterRoleBinding
      metadata:
        name: harness-delegate-cluster-admin
      subjects:
        - kind: ServiceAccount
          name: default           # Change to relevant service account name, such as myserviceaccount
          namespace: harness-delegate-ng
      roleRef:
        kind: ClusterRole
        name: cluster-admin
        apiGroup: rbac.authorization.k8s.io
      ---
      ```
   2. Add `serviceAccountName` to `Deployment.template.spec`. For example:

   ```yaml
   ...
       spec:
         serviceAccountName: myserviceaccount  # New line. Use the same service account name you used in the ClusterRole Binding.
         containers:
         - image: harness/delegate:latest
           imagePullPolicy: Always
           name: harness-delegate-instance
           ports:
            - containerPort: 8080
   ...
   ```

   <div data-gb-custom-block data-tag="hint" data-style="info" class="hint hint-info"><p>For legacy delegate, add <code>serviceAccountName</code> to the Statefulset spec.</p></div>
6. Save the delegate YAML file.
7. If you have not already installed the delegate, [Install the Kubernetes delegate](https://developer.harness.io/harness-platform/troubleshooting-and-resources/tutorials/install-delegate) in your EKS cluster and register the delegate with Harness. When you install the delegate in the cluster, the SA you added is used, and the environment variables `AWS_ROLE_ARN` and `AWS_WEB_IDENTITY_TOKEN_FILE` are added automatically by EKS.

</details>

## Serverless framework support <a href="#serverless-framework-support" id="serverless-framework-support"></a>

Harness supports the following Serverless framework versions and artifact types:

* Harness supports Serverless framework 1.82 and later.
* Harness supports Serverless framework CLI versions 2.x.x, 3.x.x, and 4.18.0.
* Harness supports all language runtimes that Serverless supports.
* Harness supports ZIP files and Docker image artifacts only.
  * ZIP files are supported with JFrog Artifactory.
  * Docker images are supported with AWS ECR.

### Serverless v4 support <a href="#serverless-v4-support" id="serverless-v4-support"></a>

{% hint style="warning" %}
**BREAKING CHANGE**

Serverless V4 CLI requires authentication. Any CLI-based scripts or processes require an extra input. Upgrading to V4 could be a breaking change for your pipeline.
{% endhint %}

**Features:**

Serverless V4 provides the following:

* Authenticate using the environment variable `SERVERLESS_ACCESS_KEY`.
* You can roll back from V4 to V3 if something goes wrong.
* Supports the use of the Node.js 22 runtime.

Harness does not recommend switching to Serverless V4 for existing deployments that use Serverless V3.

For limitations when using Serverless V4, including custom config file restrictions, go to [Limitations](#limitations).

### Containerized step images <a href="#containerized-step-images" id="containerized-step-images"></a>

Harness provides two sets of images for containerized Serverless steps: the old images and the new Serverless images.

### Old images <a href="#old-images" id="old-images"></a>

Harness supports different images for Prepare Rollback, Package, Deploy, and Rollback in a Serverless deployment:

* Prepare Rollback: [`harnessdev/serverless-preparerollback:<LATEST_TAG>`](https://hub.docker.com/r/harnessdev/serverless-preparerollback)
* Package: [`harnessdev/serverless-package:<LATEST_TAG>`](https://hub.docker.com/r/harnessdev/serverless-package)
* Deploy: [`harnessdev/serverless-deploy:<LATEST_TAG>`](https://hub.docker.com/r/harnessdev/serverless-deploy)
* Rollback: [`harnessdev/serverless-rollback:<LATEST_TAG>`](https://hub.docker.com/r/harnessdev/serverless-rollback)

Harness recommends that you use the new images, which support multiple runtimes.

### New Serverless images <a href="#new-serverless-images" id="new-serverless-images"></a>

Harness supports [multiple runtime images](https://hub.docker.com/r/harness/serverless-plugin/tags) for **nodejs24**, **nodejs22**, **nodejs20**, **nodejs18**, **java25**, **java21**, **java17**, **java8**, **python3.14**, **python3.13**, **python3.12**, **python3.11**, **ruby3.4**, **ruby3.3** and **ruby3.2**. These are Linux AMD64 images.

Unlike the old images, a single new image can handle all the Serverless steps.

Two flavors of images are available: one with Serverless installed and one without Serverless installed.

**Serverless V3 Images**

The following table lists Serverless Framework V3 images (version 3.39.0):

| **Runtimes**    | **With Serverless Installed**                                                                                                                                                                                                                         | **Without Serverless Installed**                                                                                                                                                                                                        | **Version**        |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
| **nodejs 24**   | [harness/serverless-plugin:nodejs24.x-3.39.0-1.3.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/nodejs24.x-3.39.0-1.3.0-beta-linux-amd64/images/sha256-6c4b591244468afa533e9a4518eb267b2f738fbc283c81c3d003f8da1050e623) | [harness/serverless-plugin:nodejs24.x-1.3.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/nodejs24.x-1.3.0-beta-linux-amd64/images/sha256-44555f608c8540a49c87e1b1cc584e050ed73a0b3232f45e36edd3cf2096ef51) | nodejs v24.x       |
| **nodejs 22**   | [harness/serverless-plugin:nodejs22.x-3.39.0-1.1.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/nodejs22.x-3.39.0-1.1.0-beta-linux-amd64/images/sha256-aea2e5f4bea0d55cc54f98530910a95ec056474de5fc4a3e4f993e43a351bcbf) | [harness/serverless-plugin:nodejs22.x-1.1.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/nodejs22.x-1.1.0-beta-linux-amd64/images/sha256-745550b16c387abd32d9d4db9c91170649ddb0632b2151c86a60ba7ad346a38a) | nodejs v22.14.0    |
| **nodejs 20**   | [harness/serverless-plugin:nodejs20.x-3.39.0-1.1.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/nodejs20.x-3.39.0-1.1.0-beta-linux-amd64/images/sha256-87c380c39159ee07fc96eb1544acd54f16c40c7fe05475921d56e4b0ca644517) | [harness/serverless-plugin:nodejs20.x-1.1.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/nodejs20.x-1.1.0-beta-linux-amd64/images/sha256-f4f5895d2a09b217f5e8a6f25991e9525b0e78756127af161bc195729fc103a2) | nodejs v20.19.0    |
| **nodejs 18**   | [harness/serverless-plugin:nodejs18.x-3.39.0-1.1.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/nodejs18.x-3.39.0-1.1.0-beta-linux-amd64/images/sha256-a6c80afa3cd0c2f1be0134d25b3c11704fb5d37dac4d487b6140d009eb90d1c6) | [harness/serverless-plugin:nodejs18.x-1.1.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/nodejs18.x-1.1.0-beta-linux-amd64/images/sha256-205eec0eeb5e8e41658c0d1ab02bd069a2cf757df9610bbcdc18fbb7ced89341) | nodejs v18.20.7    |
| **java 25**     | [harness/serverless-plugin:java25-3.39.0-1.3.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/java25-3.39.0-1.3.0-beta-linux-amd64/images/sha256-f56169d0acdc3e8af4f533f7f811489ee3346de1a9cb92d88e9b74f1e2c71d97)         | [harness/serverless-plugin:java25-1.3.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/java25-1.3.0-beta-linux-amd64/images/sha256-f73932afb1b028e72d7283d5fe60843653877322fdbfec1a4d8fe154ecd22f06)         | openjdk 25.x       |
| **java 21**     | [harness/serverless-plugin:java21-3.39.0-1.1.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/java21-3.39.0-1.1.0-beta-linux-amd64/images/sha256-42d7a638fa133e5b24653bbd605ece67367ec4b4e610d24631631e7dd1e063d5)         | [harness/serverless-plugin:java21-1.1.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/java21-1.1.0-beta-linux-amd64/images/sha256-d2d0c0dee723d18632c7cecc1e9dcafa4005942b733fa5830ddd21553dfc6255)         | openjdk 21.0.6     |
| **java 17**     | [harness/serverless-plugin:java17-3.39.0-1.1.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/java17-3.39.0-1.1.0-beta-linux-amd64/images/sha256-017b10a289756c5bebfc082575c09ecfecd1dfa52ff8925ed30d6f3a11e01add)         | [harness/serverless-plugin:java17-1.1.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/java17-1.1.0-beta-linux-amd64/images/sha256-d21899c9ac944e0d55ef2efe435137ff9c7b833aea6c9fcf88be818b3e248344)         | openjdk 17.0.11    |
| **java 8**      | [harness/serverless-plugin:java8.al2-3.39.0-1.1.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/java8.al2-3.39.0-1.1.0-beta-linux-amd64/images/sha256-e7df6d9c8647a55944cdcb3101ac2e1f27a071f2562ee768cb36de373f990720)   | [harness/serverless-plugin:java8.al2-1.1.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/java8.al2-1.1.0-beta-linux-amd64/images/sha256-501055e82063e660fd10c14da59212d77fad6586dc041d25bc740e8175dd5b8f)   | openjdk 1.8.0\_372 |
| **python 3.14** | [harness/serverless-plugin:python3.14-3.39.0-1.3.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/python3.14-3.39.0-1.3.0-beta-linux-amd64/images/sha256-a4b42d1a62d942182f0ec24baf5ec4891eeb1d5db2ad2a34ff67467c83f99d1a) | [harness/serverless-plugin:python3.14-1.3.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/python3.14-1.3.0-beta-linux-amd64/images/sha256-8c2127d40da72e33e905f38197bb38f73379d4b09a65e2848f03b5ca75297230) | Python 3.14.x      |
| **python 3.13** | [harness/serverless-plugin:python3.13-3.39.0-1.3.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/python3.13-3.39.0-1.3.0-beta-linux-amd64/images/sha256-af7e0392906d564c3be41945d5fdf7d9e1740bf1d358cd97ba2e706c842cfc17) | [harness/serverless-plugin:python3.13-1.3.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/python3.13-1.3.0-beta-linux-amd64/images/sha256-dc4337065fdfd3f691adbe806c5fe3cebecc43fdf51488d07589aec788835ccd) | Python 3.13.x      |
| **python 3.12** | [harness/serverless-plugin:python3.12-3.39.0-1.1.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/python3.12-3.39.0-1.1.0-beta-linux-amd64/images/sha256-617ccd746b0efde9e7ef65addb47e2a7c4845ffe142dd9cb4ca78f8976185c79) | [harness/serverless-plugin:python3.12-1.1.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/python3.12-1.1.0-beta-linux-amd64/images/sha256-15888fc51e89a9b70ea36761d4f367a034e7629726d79e71a728d046ab1716b3) | Python 3.12.9      |
| **python 3.11** | [harness/serverless-plugin:python3.11-3.39.0-1.0.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/python3.11-3.39.0-1.0.0-beta-linux-amd64/images/sha256-47c1e7121d0b0163928c99480bcea106fb59b8c51921844eb5ee0326f3b5a3d2) | [harness/serverless-plugin:python3.11-1.1.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/python3.11-1.1.0-beta-linux-amd64/images/sha256-7897343bb1a005b532df4f4204a6641199a89d1cb246a5a7100981d8c7172129) | Python 3.11.11     |
| **ruby 3.4**    | [harness/serverless-plugin:ruby3.4-3.39.0-1.3.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/ruby3.4-3.39.0-1.3.0-beta-linux-amd64/images/sha256-b71448ef2886a3a741c5cbb7bd8b428b15a18528e2043c698f23fe414e2de133)       | [harness/serverless-plugin:ruby3.4-1.3.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/ruby3.4-1.3.0-beta-linux-amd64/images/sha256-98e3a63afda976a1603c43a269b3a94af89e33bcec44d6ebfcbc97bd74a38676)       | ruby 3.4.x         |
| **ruby 3.3**    | [harness/serverless-plugin:ruby3.3-3.39.0-1.3.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/ruby3.3-3.39.0-1.3.0-beta-linux-amd64/images/sha256-bca512cc4121992e61bb96da9a25039318429ef0f8e0c204e05ee7994cb32434)       | [harness/serverless-plugin:ruby3.3-1.3.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/ruby3.3-1.3.0-beta-linux-amd64/images/sha256-b14e75f7ba09efad53b4aad3ebb5f5b09b5315b46146c7009b08330deb8566ae)       | ruby 3.3.x         |
| **ruby 3.2**    | [harness/serverless-plugin:ruby3.2-3.39.0-1.1.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/ruby3.2-3.39.0-1.1.0-beta-linux-amd64/images/sha256-c9aa6fe805586b608dc377c747e9046d41825317e7eb7afcfacad3af05dd8f8b)       | [harness/serverless-plugin:ruby3.2-1.0.0-beta-linux-amd64](https://hub.docker.com/layers/harness/serverless-plugin/ruby3.2-1.0.0-beta-linux-amd64/images/sha256-e564accd3315707dcbf6e04159a3202dba0f05b0484025354490abc1c71d48ba)       | ruby 3.2.8         |

{% hint style="info" %}
**Serverless V4 images**

Serverless V4 images are supported for the following types:

* NodeJS22
* NodeJS18
* Python
* Ruby
* Java

For a full list of the images, go to the [serverless plugin repo in Docker Hub](https://hub.docker.com/r/harness/serverless-plugin/tags).
{% endhint %}

For ECR users, you can access these images via the [ECR Image Repository for Serverless Plugin](https://gallery.ecr.aws/harness/harness/serverless-plugin).

For GAR users, you can access these images via:

* US region: [GAR Image Repository for Serverless Plugin (US)](https://console.cloud.google.com/artifacts/docker/gar-prod-setup/us/harness-public/harness%2Fserverless-plugin?invt=Ab2GnQ\&inv=1)
* Europe region: [GAR Image Repository for Serverless Plugin (Europe)](https://console.cloud.google.com/artifacts/docker/gar-prod-setup/europe/harness-public/harness%2Fserverless-plugin?inv=1\&invt=Ab5cNA)

The following image describes the runtime image variants: one with Serverless installed and one without Serverless installed.

![](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-72fd99b6872f266a07b4289871ae1bc94381fea4%2Fmultiple-runtime-image-serverless.png?alt=media)

{% hint style="info" %}
**Note**

These images can only be used in a [containerized step](#containerized-steps).
{% endhint %}

{% hint style="info" %}
If you are using images that do not have Serverless installed and you wish to install it during the execution, you must provide the path where you install your Serverless package. You can set the path using environment variable `PLUGIN_SERVERLESS_EXECUTABLE_PATH` in your serverless step.
{% endhint %}

### Build your own image <a href="#build-your-own-image" id="build-your-own-image"></a>

You can also build your own image based on the base image provided by Harness and use it in the Serverless deployments.

**How this pipeline works:**

Harness provides a base image that has the Serverless plugin binary. The pipeline takes a pre-built scratch image containing the Serverless plugin binary and creates a properly tagged final image that combines it with the appropriate runtime.

For an in-depth explanation on how to build your own image, go to [Serverless Framework image build](/continuous-delivery/use-continuous-delivery/deploy-services-on-different-platforms/serverless/serverless-image-build.md).

## Create the Deploy stage <a href="#create-the-deploy-stage" id="create-the-deploy-stage"></a>

Pipelines are collections of stages. This quickstart creates a new Pipeline and adds a single stage.

{% hint style="info" %}
**Create a Project for your new CD Pipeline:** if you do not already have a Harness Project, create a Project for your new CD Pipeline. Make sure that you add the **Continuous Delivery** module to the Project. For more information, go to [Create Organizations and Projects](https://developer.harness.io/harness-platform/new-to-harness-platform/get-started).
{% endhint %}

1. In your Harness Project, click **Deployments**, and then click **Create a Pipeline**.
2. Enter the name **Serverless Quickstart** and click **Start**. Your Pipeline appears.
3. Click **Add Stage** and select **Deploy**.
4. Enter the name **Deploy Service**, make sure **Service** is selected, and then click **Set Up Stage**.

   ![](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-dddf96859e981a8e804febf9ce8a7270e4dc3e56%2Fserverless-lambda-cd-quickstart-110.png?alt=media)

   The new stage settings appear.
5. In **About the** **Service**, click **New Service**.
6. Give the Service the name **quickstart** and click **Save**.

![](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-7ce7ba0de12364a58cb5ea5b0bcb4f727c892b43%2Fserverless-lambda-cd-quickstart-111.png?alt=media)

{% hint style="info" %}
Review Harness Services and Service Definitions. A Harness Service represents your microservice or app logically. You can add the same Service to as many stages as you need. Service Definitions represent your artifacts, manifests, and variables physically. They are the actual files and variable values. By separating Services and Service Definitions, you can propagate the same Service across stages while changing the artifacts, manifests, and variables with each stage.
{% endhint %}

After you create a Service, it is persistent and you can use it throughout the stages of this or any other Pipeline in the Project.

## Add the manifest <a href="#add-the-manifest" id="add-the-manifest"></a>

Add a `serverless.yaml` for your deployment. This quickstart uses [the publicly-available serverless.yaml file](https://github.com/wings-software/harness-docs/tree/main/serverless/artifacts) available from Harness.

To add the manifest, do the following:

1. In **Service Definition**, in **Deployment Type**, select **Serverless Lambda**.
2. In **Manifests**, click **Add Manifest**.
3. Select **Serverless Lambda Manifest**, and click **Continue**.
4. In **Specify Serverless Lambda Manifest Store**, select **GitHub**, and then click **New GitHub Connector**. The **Git Connector** settings appear. Enter the following settings:

   * **Name:** `serverless`
   * **URL Type:** `Repository`
   * **Connection Type:** `HTTP`
   * **GitHub Repository URL:** `https://github.com/wings-software/harness-docs.git`
   * **Username:** Enter your GitHub account username.
   * In **Personal Access Token**, click **Create or Select a Secret**.
     * Click **New Secret Text**.
     * In **Secret Name**, enter a name for the secret, such as **github-pat**.
     * In **Secret Value**, paste in a GitHub Personal access token. When you are logged in to GitHub, these tokens are listed in your [GitHub token settings](https://github.com/settings/tokens). For steps on setting up a GitHub PAT, go to [Creating a personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) from GitHub.
     * Make sure your PAT has the **repo** scope selected:

   ![](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-504b98725a747e6007be0bb9f8d26e39b675641a%2FrepoScope.png?alt=media)
5. Select **Connect through Harness Platform**.
6. Click **Finish**.
7. Back in **Specify Serverless Lambda Manifest Store**, click **Continue**.
8. In **Manifest Details**, enter the following.
   * **Manifest Identifier:** `serverless`
   * **Git Fetch Type:** `Latest from Branch`.
   * **Branch:** `main`
   * **Folder Path:** `serverless/artifacts`
   * In **Advanced**, **Serverless Config File Path** is available. Use this setting when your Serverless manifest is not named `serverless.yml|.yaml|.js|.json`. This option is the same as the `--config` option in `serverless deploy`. For more information, go to [AWS - deploy](https://www.serverless.com/framework/docs/providers/aws/cli-reference/deploy) from Serverless.

The `serverless.yaml` manifest appears in Harness.

{% hint style="info" %}
You can also use AWS S3 or Harness Local File Store as your manifest provider. For information on how to configure those manifests, go to [Manifest Providers for Serverless Lambda](/continuous-delivery/use-continuous-delivery/deploy-services-on-different-platforms/serverless/manifest-sources-for-serverless-lambda.md).
{% endhint %}

![](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-ddfbf277e739a8623170991f925ed99fe018f4ba%2Fserverless-lambda-cd-quickstart-112.png?alt=media)

<details>

<summary>Example serverless.yaml file for Serverless V1</summary>

```yaml
service: <+service.name>
frameworkVersion: "2 || 3"

provider:
  name: aws
  runtime: nodejs12.x
functions:
  hello:
    handler: handler.hello
    events:
      - httpApi:
          path: /tello
          method: get
package:
  artifact: <+artifact.path>
plugins:
  - serverless-deployment-bucket@latest
```

The [Harness expression](https://developer.harness.io/harness-platform/use-harness-platform/variables-and-expressions/harness-variables) `<+artifact.path>` appears in `artifact: <+artifact.path>`. The expression `<+artifact.path>` tells Harness to get the artifact from **Artifacts** section of the Service. The artifact is added next.

The expression `<+service.name>` uses the Harness Service name for the deployed service name.

For Docker images, you use the expression `<+artifact.image>`.

</details>

<details>

<summary>Example serverless.yaml file for Serverless V2</summary>

```yaml
service: {{.Values.serviceName}}
frameworkVersion: "2 || 3"

provider:
  name: aws
  runtime: nodejs12.x
functions:
  hello:
    handler: handler.hello
    events:
      - httpApi:
          path: /tello
          method: get
package:
  artifact: {{.Values.artifact.path}}
plugins:
  - serverless-deployment-bucket@latest
```

A corresponding `values.yaml` file that is added in the same place as the manifest resolves variables such as `{{.Values.serviceName}}`. Follow the preceding steps to add a manifest, but at step 3 select **Values YAML** instead. The following is an example of a `values.yaml` file for the manifest:

```yaml
serviceName: goldenpipeline
artifact: 
  path: /my-artifact
```

</details>

{% hint style="info" %}
The preceding `values.yaml` approach applies to **containerized (V2) steps only**. For non-containerized (V1) steps, Harness resolves expressions directly in the manifest, so a separate `values.yaml` file is not required.

The `PLUGIN_RESOLVE_WITH_VALUES_MANIFEST` environment variable referenced in earlier versions of this documentation is no longer applicable for containerized steps. The V1/V2 step type determines how expressions are resolved, as described above.
{% endhint %}

## Add the artifact <a href="#add-the-artifact" id="add-the-artifact"></a>

Next, add your Serverless artifact. This quickstart adds a publicly available artifact to your service using Artifactory. Other artifact sources are also available.

### Artifact sources <a href="#artifact-sources" id="artifact-sources"></a>

The following artifact sources are available for Serverless deployments:

* [**Harness Artifact Registry**](/continuous-delivery/use-continuous-delivery/cd-building-blocks/services/artifact-sources.md#harness-artifact-registry). Harness supports docker images stored in Harness Artifact Registry as your Serverless deployment artifacts.
* [**Artifactory**](https://developer.harness.io/harness-platform/use-harness-platform/connectors/artifact-repositories/add-an-artifactory-connector). Harness supports ZIP files stored in Artifactory as your Serverless deployment artifacts.
* [**AWS S3**](https://developer.harness.io/harness-platform/use-harness-platform/connectors/cloud-providers/add-aws-connector). Harness supports ZIP files stored in an S3 bucket for your Serverless deployment artifacts.
* [**ECR**](https://developer.harness.io/harness-platform/use-harness-platform/connectors/cloud-providers/add-aws-connector). Harness supports docker images stored in ECR as your Serverless deployment artifacts.

### Add the artifact with Artifactory <a href="#add-the-artifact-with-artifactory" id="add-the-artifact-with-artifactory"></a>

This guide adds a publicly available artifact to your Service. The artifact is a ZIP file with a JavaScript function hosted in Artifactory.

This quickstart adds a new Artifactory Connector and installs a Harness Kubernetes Delegate in a Kubernetes cluster. The delegate is a worker process that performs the deployment operations. The delegate uses the URL and credentials you provide in the Connector to connect to Artifactory and fetch the artifact at runtime.

To add the artifact, do the following:

1. In **Artifact**, click **Add Primary**.
2. In **Specify Artifact Repository Type**, select **Artifactory**, and click **Continue**.
3. In **Artifactory Repository**, click **New Artifactory Connector**.
4. In **Create or Select an Existing Connector**, click **New Artifactory Connector**.
5. Enter a name for the Connector, such as **JFrog Serverless**. Click **Continue**.
6. In **Details**, in **Artifactory Repository URL**, enter `https://harness.jfrog.io/artifactory/`.
7. In **Authentication**, select **Anonymous**.

   ![](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-64cb74c2f738bb52f4edd2d9c1fa7ded52f47e19%2Fserverless-lambda-cd-quickstart-113.png?alt=media)
8. In **Connect to the provider**, select **Connect through a Harness Delegate**, and then select **Continue**. Harness does not recommend using the **Connect through Harness Platform** option here because you need a delegate later for connecting to your target environment. The **Connect through Harness Platform** option is a quick way to make connections without using delegates.

   Expand the following section for more information about installing delegates.

<details>

<summary>Install a new delegate</summary>

1. In **Delegates Setup**, select **Install new Delegate**. The delegate wizard appears.
2. In the **New Delegate** dialog, in **Select where you want to install your Delegate**, select **Kubernetes**.
3. In **Install your Delegate**, select **Kubernetes Manifest**.
4. Enter a delegate name.
   * Delegate names must be unique within a namespace and should be unique in your cluster.
   * A valid name includes only lowercase letters and does not start or end with a number.
   * You can use the dash character ("-") as a separator between letters.
5. At a terminal, run the following cURL command to copy the Kubernetes YAML file to the target location for installation:

```bash
curl -LO https://raw.githubusercontent.com/harness/delegate-kubernetes-manifest/main/harness-delegate.yaml
```

6. Open the `harness-delegate.yaml` file. Find and specify the following placeholder values as described:

| **Value**                   | **Description**                                                                                                                                                                                                                                                                                                                                                                                  |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `PUT_YOUR_DELEGATE_NAME`    | Name of the delegate.                                                                                                                                                                                                                                                                                                                                                                            |
| `PUT_YOUR_ACCOUNT_ID`       | Harness account ID.                                                                                                                                                                                                                                                                                                                                                                              |
| `PUT_YOUR_MANAGER_ENDPOINT` | URL of your cluster. Go to the following table of Harness clusters and endpoints.                                                                                                                                                                                                                                                                                                                |
| `PUT_YOUR_DELEGATE_TOKEN`   | Delegate token. To find it, go to **Account Settings** > **Account Resources**, select **Delegate**, and select **Tokens**. For more information on how to add your delegate token to the harness-delegate.yaml file, go to [Secure delegates with tokens](https://developer.harness.io/harness-platform/use-harness-platform/delegates/delegate/secure-delegates/secure-delegates-with-tokens). |

Your Harness manager endpoint depends on your Harness SaaS cluster location. Use the following table to find the Harness manager endpoint in your Harness SaaS cluster.

| **Harness cluster location** | **Harness Manager endpoint**    |
| ---------------------------- | ------------------------------- |
| SaaS prod-1                  | <https://app.harness.io>        |
| SaaS prod-2                  | <https://app.harness.io/gratis> |
| SaaS prod-3                  | <https://app3.harness.io>       |

7. Install the delegate by running the following command:

```bash
kubectl apply -f harness-delegate.yaml
```

The successful output looks like the following:

```
namespace/harness-delegate-ng unchanged
clusterrolebinding.rbac.authorization.k8s.io/harness-delegate-cluster-admin unchanged
secret/<DELEGATE_NAME>-account-token created
deployment.apps/<DELEGATE_NAME> created
service/delegate-service configured
role.rbac.authorization.k8s.io/upgrader-cronjob unchanged
rolebinding.rbac.authorization.k8s.io/upgrader-cronjob configured
serviceaccount/upgrader-cronjob-sa unchanged
secret/<DELEGATE_NAME>-upgrader-token created
configmap/<DELEGATE_NAME>-upgrader-config created
cronjob.batch/<DELEGATE_NAME>-upgrader-job created
```

8. Select **Verify** to make sure that the delegate is installed properly.

</details>

9. Back in **Set Up Delegates**, your new delegate and its tags appear in the list of delegates.
10. Select the **Connect using Delegates with the following Tags** option.
11. Enter the tag of the new delegate and click **Save and Continue**.

![](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-9f33dd786509a4700076de487dc119b460ec6b76%2Fserverless-lambda-cd-quickstart-118.png?alt=media)

12. In **Connection Test**, the connection is successful. Click **Finish**.

![](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-cb605fe39a69049072413674049894f906ebe656%2Fserverless-lambda-cd-quickstart-119.png?alt=media)

### Install Serverless on the delegate <a href="#install-serverless-on-the-delegate" id="install-serverless-on-the-delegate"></a>

For a **non-containerized** execution, you need to edit the YAML to install Serverless when the delegate pods are created. To install Serverless on the delegate, do the following:

1. Open the delegate YAML in a text editor.
2. Locate the Environment variable `INIT_SCRIPT` in the `StatefulSet` (Legacy Delegate) or `Deployment` (Harness Delegate) object:

   ```yaml
   ...
       - name: INIT_SCRIPT
         value: ""
   ...
   ```
3. Replace the value with the following Serverless installation script (the Harness Delegate uses the Red Hat Universal Base Image (UBI)).

   The following is an example using microdnf and npm:

   ```yaml
   ...
       - name: INIT_SCRIPT
       value: |-
           #!/bin/bash

           # Install Node.js and npm on the Red Hat UBI image using Microdnf
           microdnf install -y nodejs

           # Install the Serverless Framework using npm
           npm install -g serverless@2.50.0
   ...

   ```

   The following is an example using yum and npm:

   ```yaml
   ...
       - name: INIT_SCRIPT
       value: |-
           #!/bin/bash

           # Install Node.js and npm on the Red Hat UBI image
           yum install -y nodejs

           # Install the Serverless Framework using npm
           npm install -g serverless@2.50.0
   ...

   ```

If the delegate OS does not support `apt` (Red Hat Linux), you can edit this script to install `npm`. The rest of the code should remain the same. If you are using Harness Delegate, the base image is Red Hat UBI. Save the YAML file as **harness-delegate.yml**.

### Configure the artifact settings <a href="#add-the-artifact-1" id="add-the-artifact-1"></a>

To configure the artifact settings, do the following:

1. Back in **Artifactory Repository**, click **Continue**.
2. Enter the following artifact settings and click **Submit**. The following image shows how the Artifactory settings correspond to **Artifact Details**.
   * **Repository:** `lambda`
   * **Artifact Directory:** `serverless`
   * **Artifact Details:** `Value`
   * **Artifact Path:** `handler.zip`. When you click one of the settings, the delegate fetches artifact metadata from Artifactory.
3. Click **Submit**.

   The artifact appears in the Service.

   ![](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-929c9e4611e9d24be0f32b352481ef12aabd3580%2Fserverless-lambda-cd-quickstart-120.png?alt=media)
4. Click **Continue** to view the **Infrastructure**.

After you configure the Service, define the target for the deployment.

## Define the infrastructure <a href="#define-the-infrastructure" id="define-the-infrastructure"></a>

You define the target infrastructure for your deployment in the **Environment** settings of the pipeline stage. You can define an environment separately and select it in the stage, or create the environment within the stage **Environment** tab.

There are two methods of specifying the deployment target infrastructure:

* **Pre-existing:** The target infrastructure already exists and you need to provide the required settings.
* **Dynamically provisioned:** The target infrastructure is dynamically provisioned on-the-fly as part of the deployment process.

For details on Harness provisioning, go to [Provisioning overview](/continuous-delivery/use-continuous-delivery/provision-infrastructure/provisioning-overview.md).

### Pre-existing infrastructure <a href="#pre-existing-infrastructure" id="pre-existing-infrastructure"></a>

This quickstart adds an AWS Connector to connect Harness with your Lambda service. To define the pre-existing infrastructure, do the following:

1. In **Infrastructure**, select the option to add an AWS Connector.
2. In **Infrastructure Details**, in **Specify your environment**, click **New Environment**. As with a Service, you can create a new Environment or select an existing one. This quickstart creates a new one.
3. In **New Environment**, enter a name, select **Pre-Production**, and click **Save**. The new Environment appears.
4. In **Infrastructure Definition**, click **AWS**.
5. In **Amazon Web Services Details**, click **Connector**.
6. In **Create or Select an Existing Connector**, click **New Connector**.
7. Enter the following and click **Save and Continue**.
   * **Name:** `AWS Serverless`
   * **Credentials:** `AWS Access Key`. Enter the AWS access key for the AWS User you created with the required policies in [Before you begin](#before-you-begin).
   * Enter the secret key as a [Harness Text Secret](https://developer.harness.io/harness-platform/use-harness-platform/secrets/add-use-text-secrets). The Harness Delegate uses these credentials to authenticate Harness with AWS at deployment runtime.
   * **Delegates Setup:** `Only use Delegates with all of the following tags`.
   * Select the delegate you added earlier in this quickstart.
8. The **Connection Test** verifies the connection. Click **Finish**.
9. Back in **Amazon Web Services Details**, in **Region**, enter the region for your AWS Lambda service, such as **us-east-1**.
10. In **Stage**, enter the name of the stage in your service that you want to deploy to, such as **dev**. This is the same as the `--stage` option in the `serverless deploy` command.

    ![](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-89e5ae0060e80d89054397b783cd19b5ff7428a9%2Fserverless-lambda-cd-quickstart-121.png?alt=media)

    When you run your deployment, these settings are used in the logs. For example: `serverless deploy list --stage dev --region us-east-1`.
11. Click **Continue**. The **Execution** steps appear.

### Dynamically provisioned infrastructure <a href="#dynamically-provisioned-infrastructure" id="dynamically-provisioned-infrastructure"></a>

Harness supports multiple provisioner types, including Terraform, CloudFormation, Shell Script, and so on. Go to [Provision Infrastructure](/continuous-delivery/use-continuous-delivery/provision-infrastructure.md) to explore the available provisioners and configure provisioning based on your requirements.

The following is a summary of the steps to dynamically provision the target infrastructure for a deployment:

1. **Add dynamic provisioning to the CD stage**:
   1. In a Harness Deploy stage, in **Environment**, enable the option **Provision your target infrastructure dynamically during the execution of your Pipeline**.
   2. Select the type of provisioner that you want to use.

      Harness automatically adds the provisioner steps for the provisioner type you selected.
   3. Configure the provisioner steps to run your provisioning scripts.
   4. Select or create a Harness infrastructure in **Environment**.
2. **Map the provisioner outputs to the Infrastructure Definition**:
   1. In the Harness infrastructure, enable the option **Map Dynamically Provisioned Infrastructure**.
   2. Map the provisioning script/template outputs to the required infrastructure settings.

**Supported provisioners**

The following provisioners are supported for Serverless.com Framework Lambda deployments:

* Terraform
* Terragrunt
* Terraform Cloud
* CloudFormation
* Shell Script

**Adding dynamic provisioning to the stage**

To add dynamic provisioning to a Harness pipeline Deploy stage, do the following:

1. In a Harness Deploy stage, in **Environment**, enable the option **Provision your target infrastructure dynamically during the execution of your Pipeline**.
2. Select the type of provisioner that you want to use.

   Harness automatically adds the necessary provisioner steps.
3. Set up the provisioner steps to run your provisioning scripts.

For documentation on each of the required steps for the provisioner you selected, go to the following topics:

* Terraform:
  * [Terraform Plan](/continuous-delivery/use-continuous-delivery/provision-infrastructure/terraform-infra/run-a-terraform-plan-with-the-terraform-plan-step.md)
  * [Terraform Apply](/continuous-delivery/use-continuous-delivery/provision-infrastructure/terraform-infra/run-a-terraform-plan-with-the-terraform-apply-step.md)
  * [Terraform Rollback](/continuous-delivery/use-continuous-delivery/provision-infrastructure/terraform-infra/rollback-provisioned-infra-with-the-terraform-rollback-step.md). To display the Terraform Rollback step, toggle the **Rollback** setting.
* [Terragrunt](/continuous-delivery/use-continuous-delivery/provision-infrastructure/terragrunt-howtos.md)
* [Terraform Cloud](/continuous-delivery/use-continuous-delivery/provision-infrastructure/terraform-infra/terraform-cloud-deployments.md)
* CloudFormation:
  * [Create Stack](/continuous-delivery/use-continuous-delivery/provision-infrastructure/cloudformation-infra/provision-with-the-cloud-formation-create-stack-step.md)
  * [Delete Stack](/continuous-delivery/use-continuous-delivery/provision-infrastructure/cloudformation-infra/remove-provisioned-infra-with-the-cloud-formation-delete-step.md)
  * [Rollback Stack](/continuous-delivery/use-continuous-delivery/provision-infrastructure/cloudformation-infra/rollback-provisioned-infra-with-the-cloud-formation-rollback-step.md). To display the Rollback Stack step, toggle the **Rollback** setting.
* [Shell Script](/continuous-delivery/use-continuous-delivery/provision-infrastructure/shell-script-provisioning.md)

**Mapping provisioner output**

After you set up dynamic provisioning in the stage, you must map outputs from your provisioning script/template to specific settings in the Harness Infrastructure Definition used in the stage.

1. In the same CD Deploy stage where you enabled dynamic provisioning, select or create (**New Infrastructure**) a Harness infrastructure.
2. In the Harness infrastructure, in **Select Infrastructure Type**, select **AWS** if it is not already selected.
3. In **Amazon Web Services Details**, enable the option **Map Dynamically Provisioned Infrastructure**.

   A **Provisioner** setting is added and configured as a runtime input.
4. Map the provisioning script/template outputs to the required infrastructure settings.

To provision the target deployment infrastructure, Harness needs specific infrastructure information from your provisioning script. You provide this information by mapping specific Infrastructure Definition settings in Harness to outputs from your template/script.

For Serverless.com framework Lambda, Harness needs the following settings mapped to outputs:

* Region
* Stage

{% hint style="info" %}
Ensure the **Region** and **Stage** settings are set to the **Expression** option.
{% endhint %}

For example, the following is a snippet of a CloudFormation template that provisions the infrastructure for a Serverless.com Framework Lambda deployment and includes the required outputs:

```yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: CloudFormation template for provisioning Serverless Framework infrastructure

Parameters:
  StageName:
    Type: String
    Default: dev
    Description: The stage name for the Serverless deployment

Resources:
  ServerlessDeploymentBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "${AWS::StackName}-deployment-bucket"
      AccessControl: Private

  ServerlessDeploymentApplication:
    Type: AWS::Serverless::Application
    Properties:
      Location:
        ApplicationId: arn:aws:serverlessrepo:us-east-1:112758395563:applications/awslabs/serverless-application-model
        SemanticVersion: 1.1.0
      Parameters:
        BucketName: !Ref ServerlessDeploymentBucket
        ObjectVersion: !Ref ServerlessDeploymentVersion
        AutoPublishAlias: !Ref StageName

  ServerlessDeploymentVersion:
    Type: AWS::S3::BucketVersioning
    Properties:
      BucketName: !Ref ServerlessDeploymentBucket

Outputs:
  region_name:
    Value: !Ref AWS::Region
    Description: AWS region where the Serverless Framework application is deployed

  stage_name:
    Value: !Ref StageName
    Description: The stage name for the Serverless deployment
```

In the Harness Infrastructure Definition, you map outputs to their corresponding settings using expressions in the format `<+provisioner.OUTPUT_NAME>`, such as `<+provisioner.region_name>`.

<figure><img src="https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-75602cfb2659a5231cc4c2cea1e7e6995d0b7950%2Fded18c31118528f146d29b1570264a4a637b61957c93093e62bb47a77593564d.png?alt=media" alt=""><figcaption><p>Click to view full size image</p></figcaption></figure>

## Containerized steps <a href="#containerized-steps" id="containerized-steps"></a>

This section describes how to set up the stage **Execution** when you are using containerized steps.

### Authentication with AWS <a href="#authentication-with-aws" id="authentication-with-aws"></a>

AWS authentication occurs in the Harness AWS connector used in the Infrastructure Definition and when using AWS ECR or S3 for the Harness service artifact.

For infrastructure authentication, when the pipeline stage's containerized steps run, Harness passes the AWS access key (`PLUGIN_AWS_ACCESS_KEY`) and secret key (`PLUGIN_AWS_SECRET_KEY`) you configured in your AWS connector(s) as environment variables into the containers.

The container images pick up the access and secret keys based on these specific environment variables.

For ECR artifacts, Harness passes in the `PLUGINS_ECR_AWS_ACCESS_KEY` and `PLUGINS_ECR_AWS_SECRET_KEY` as environment variables.

For S3 artifacts, Harness passes in the `PLUGIN_S3_AWS_ACCESS_KEY` and `PLUGIN_S3_AWS_SECRET_KEY` as environment variables.

For more information on how to use a Serverless Harness Connector with a containerized step group, go to [Using Serverless.com Harness Connectors with Containerized Step Groups](/continuous-delivery/use-continuous-delivery/cd-building-blocks/cd-steps/containerized-steps/containerized-step-groups.md#using-aws-sam-and-serverlesscom-harness-connectors-with-containerized-step-groups).

### Step group <a href="#step-group" id="step-group"></a>

Harness adds the step group and steps needed for a deployment automatically when you select the stage execution strategy in the **Execution** section.

To configure the step group, do the following:

1. Open the step group.
2. In **Kubernetes Cluster**, add a Harness Kubernetes Cluster connector to connect to the cluster where the containers run.
3. In **Namespace**, enter an existing namespace in the cluster.

For information on the remaining step group settings, go to [Containerize step groups](/continuous-delivery/use-continuous-delivery/cd-building-blocks/cd-steps/containerized-steps/containerized-step-groups.md).

**Harness Docker Registry connector for all steps**

In most steps in the containerized step group, you must provide a Harness connector to a container registry and an image for the container step to run.

You can create the connector in any of the steps and then select it in the other steps, or you can create it separately and select it in all of the steps.

You select the image to use in each step separately.

For steps on adding a Docker Registry connector, go to [Docker Connector Settings Reference](https://developer.harness.io/harness-platform/use-harness-platform/connectors/artifact-repositories/ref-artifact-repositories/docker-registry-connector-settings-reference).

### Download Manifests step <a href="#download-manifests-step" id="download-manifests-step"></a>

The Download Manifests step triggers a Git clone step for each manifest in the Harness service in the **Service** section of the stage.

<details>

<summary>Example: Log of a Download Manifest step</summary>

```
[DEBUG] setting default home directory
+ git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: 	git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint: 	git branch -m <name>
Initialized empty Git repository in /harness/iden/.git/
+ git remote add origin https://github.com/**************/manifest.git
+ set +x
+ git fetch --depth=50 origin +refs/heads/main:
From https://github.com/**************/manifest
 * branch            main       -> FETCH_HEAD
 * [new branch]      main       -> origin/main
+ git checkout -b main origin/main
Switched to a new branch 'main'
branch 'main' set up to track 'origin/main'.
+ exit 0
```

</details>

{% hint style="info" %}
**Note**

The artifact is downloaded at each step. The default value is `true` for all the steps. To prevent the download in a Serverless step, set the environment variable `PLUGIN_DOWNLOAD_ARTIFACT` to `false` in that step.
{% endhint %}

**Serverless directory path**

After the Download Manifest step, you can access the directory where the manifest has been downloaded using the expression `<+serverlessV2.serverlessDirectoryPath>`.

For example, you can add a [Run](/continuous-delivery/use-continuous-delivery/cd-building-blocks/cd-steps/containerized-steps/run-step.md) or [Shell Script](/continuous-delivery/use-continuous-delivery/cd-building-blocks/cd-steps/utilities/shell-script-step.md) step with the following script:

```bash
cd <+serverlessV2.serverlessDirectoryPath>
pwd
exit 1
```

{% hint style="info" %}
**Note**

Because this is a containerized step and each step acts like a pod, the path of the directory where your manifest is downloaded looks like `/harness/Manifest identifier/Folder Path`. If your manifest identifier is `m1` in your Service YAML, use the expression `<+manifests.m1.identifier>` to access your manifest identifier. Use the expression `<+manifests.m1.store.folderPath>` to access the folder path that you defined in your manifest.
{% endhint %}

### Serverless Prepare Rollback step <a href="#serverless-prepare-rollback-step" id="serverless-prepare-rollback-step"></a>

The Serverless Prepare Rollback step describes the CloudFormation stack and gets its current state. This information is stored and passed to the Serverless Rollback Step, and used in the case of rollback.

Harness recommends that you use the latest Harness image that supports [multiple runtimes](#containerized-step-images). You can use another image, hosted in your own Docker registry.

To configure the Serverless Prepare Rollback step, do the following:

1. Open the Serverless Prepare Rollback step.
2. In **Container Registry**, add a Harness Docker Registry connector to connect to Docker Hub.
3. In **Image**, enter the path, image, and tag for the image you want to run in this step. For example, you can specify: [`harness/serverless-plugin:nodejs20.x-3.39.0-1.0.0-beta-linux-amd64`](https://hub.docker.com/r/harness/serverless-plugin/tags).

For information on the remaining settings, go to [Common settings for all steps](#common-settings-for-all-steps).

### Serverless Package step <a href="#serverless-package-step" id="serverless-package-step"></a>

This step performs the Serverless [package command](https://www.serverless.com/framework/docs/providers/aws/cli-reference/package).

You can use the latest Harness image that supports [multiple runtimes](#containerized-step-images). You can use another image, hosted in your own Docker registry.

To configure the Serverless Package step, do the following:

1. Open the Serverless Package step.
2. In **Container Registry**, add a Harness Docker Registry connector to connect to Docker Hub.
3. In **Image**, enter the path, image, and tag for the image you want to run in this step. For example: [`harness/serverless-plugin:nodejs20.x-3.39.0-1.0.0-beta-linux-amd64`](https://hub.docker.com/r/harness/serverless-plugin/tags).

For information on the remaining settings, go to [Common settings for all steps](#common-settings-for-all-steps).

<details>

<summary>Example: Log from the Serverless Package step</summary>

```
Found package.json in directory :
/harness/iden
Doing npm install -C /harness/iden
npm WARN read-shrinkwrap This version of npm is compatible with lockfileVersion@1, but package-lock.json was generated for lockfileVersion@2. I'll try to do my best with it!
updated 1 package and audited 1 package in 8.694s
found 0 vulnerabilities

Framework Core: 3.30.1
Plugin: 6.2.3
SDK: 4.3.2

Populating manifest with artifact values
Setting up AWS config credentials..

✔ Profile "default" has been configured
Config Credential command executed successfully..
Skipping downloading artifact step as it is not needed..
Serverless Package Starting..


serverless package --stage stage1 --region us-east-1


Packaging newcheckstrynew for stage stage1 (us-east-1)

✔ Service packaged (1s)
Serverless Package Command succeeded

```

</details>

### Serverless Deploy step <a href="#serverless-deploy-step" id="serverless-deploy-step"></a>

This step performs the Serverless [deploy command](https://www.serverless.com/framework/docs/providers/aws/cli-reference/deploy).

The Serverless stage and AWS region are taken from the Harness Infrastructure Definition configured in the Harness pipeline stage's **Environment** section.

You can use the latest Harness image that supports [multiple runtimes](#containerized-step-images). You can use another image, hosted in your own Docker registry.

To configure the Serverless Deploy step, do the following:

1. Open the Serverless Deploy step.
2. In **Container Registry**, add a Harness Docker Registry connector to connect to Docker Hub.
3. In **Image**, enter the path, image, and tag for the image you want to run in this step. For example: [`harness/serverless-plugin:nodejs20.x-3.39.0-1.0.0-beta-linux-amd64`](https://hub.docker.com/r/harness/serverless-plugin/tags).

For information on the remaining settings, go to [Common settings for all steps](#common-settings-for-all-steps).

<details>

<summary>Example: Log from the Serverless Deploy step</summary>

```
Framework Core: 3.30.1
Plugin: 6.2.3
SDK: 4.3.2

Setting up AWS config credentials..

✔ Profile "default" has been configured
Config Credential command executed successfully..
Serverless Deployment Starting..


serverless deploy --stage stage1 --region us-east-1


Deploying newcheckstrynew to stage stage1 (us-east-1)

✔ Service deployed to stack newcheckstrynew-stage1 (104s)

endpoints:
  GET - https://<API_ID>.execute-api.us-east-1.amazonaws.com/time
  GET - https://<API_ID>.execute-api.us-east-1.amazonaws.com/time1
functions:
  currentTime54: newcheckstrynew-stage1-currentTime54
  currentTime55: newcheckstrynew-stage1-currentTime55
Serverless Deployment succeeded

```

</details>

### Serverless Rollback step <a href="#serverless-rollback-step" id="serverless-rollback-step"></a>

Toggle the **Execution**/**Rollback** setting in **Execution** to display the Serverless Rollback step.

The Serverless Rollback step reads the CloudFormation stack name and state generated by the Serverless Prepare Rollback step and performs rollback, if needed.

You can use the latest Harness image that supports [multiple runtimes](#containerized-step-images). You can use another image, hosted in your own Docker registry.

To configure the Serverless Rollback step, do the following:

1. Open the Serverless Rollback step.
2. In **Container Registry**, add a Harness Docker Registry connector to connect to Docker Hub.
3. In **Image**, enter the path, image, and tag for the image you want to run in this step. For example: [`harness/serverless-plugin:nodejs20.x-3.39.0-1.0.0-beta-linux-amd64`](https://hub.docker.com/r/harness/serverless-plugin/tags).

For information on the remaining settings, go to [Common settings for all steps](#common-settings-for-all-steps).

### Common settings for all steps <a href="#common-settings-for-all-steps" id="common-settings-for-all-steps"></a>

All of the containerized steps include the following settings:

* **Image Pull Policy:** Select an option to set the pull policy for the image:
  * **Always:** The kubelet queries the container image registry to resolve the name to an image digest every time the kubelet launches a container. If the kubelet encounters an exact digest cached locally, it uses its cached image; otherwise, the kubelet downloads (pulls) the image with the resolved digest, and uses that image to launch the container.
  * **If Not Present:** The image is pulled only if it is not already present locally.
  * **Never:** The image is assumed to exist locally. No attempt is made to pull the image.
* **Privileged:** The standard `privileged` property for Kubernetes `securityContext`.
  * When this setting is enabled, it grants the container elevated privileges within the underlying host environment. This means that the container has access to all Linux kernel capabilities and devices, similar to running processes outside the container. It effectively removes the isolation provided by the container runtime and can potentially pose security risks if not used carefully.
* **Environment Variables:** You can inject environment variables into a container and use them in the **Command** script. You must input a **Name** and **Value** for each variable.
  * You can reference environment variables in the **Command** script by their name. For example, a Bash script would use `$var_name` or `${var_name}`, and a Windows PowerShell script would use `$Env:varName`.
* **Pre Execution Command:** The Pre Execution command runs before your Serverless step. Use this field to install any dependencies needed before the plugin logic executes. For example, you can install any package spec via npm.

{% hint style="warning" %}
The Pre Execution command runs only with the latest [Harness runtime support images](#containerized-step-images).
{% endhint %}

## Non-containerized steps <a href="#non-containerized-steps" id="non-containerized-steps"></a>

This section describes how to set up the stage **Execution** when you are using non-containerized steps.

### Add a Serverless AWS Lambda Deploy step <a href="#add-a-serverless-aws-lambda-deploy-step" id="add-a-serverless-aws-lambda-deploy-step"></a>

In **Execution**, you add the steps that define how Harness deploys your Serverless Lambda service.

Harness automatically adds two Serverless Lambda steps to **Execution**:

* **Serverless Lambda Deploy:** This step performs the deployment.
* **Serverless Lambda Rollback:** This step performs a rollback in the event of a deployment failure. To display this step, toggle the **Execution**/**Rollback** setting.

![](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-9a77c26625013fd750df55fb3f22d1429970ea26%2Fserverless-lambda-cd-quickstart-122.png?alt=media)

To configure the Serverless Lambda Deploy step, do the following:

1. In **Execution**, click **Serverless Lambda Deploy**.
2. Click the **Advanced** tab and select the delegate that you installed in **Delegate Selector**.

   ![](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-1a678c5e01b005d27db603e8045f4de866e2ea42%2Fserverless-lambda-cd-quickstart-123.png?alt=media)

   If you have only one delegate installed in your Project, this step is not necessary. If you have multiple delegates, make sure the Serverless Lambda Deploy step uses the delegate where you installed Serverless.
3. Click **Apply Changes**.

The pipeline is ready to deploy.

### Serverless deploy command options <a href="#serverless-deploy-command-options" id="serverless-deploy-command-options"></a>

In **Serverless Deploy Command Options**, you can add any `serverless deploy` command options. For the list of options, go to [Serverless AWS - Deploy](https://www.serverless.com/framework/docs/providers/aws/cli-reference/deploy).

The deployment logs show the options added to the serverless deploy command.

For example, if you add `--conceal` in **Serverless Deploy Command Options**, the logs show the following:

```bash
serverless deploy --stage dev --region us-east-1 --conceal
```

## Deploy and review <a href="#deploy-and-review" id="deploy-and-review"></a>

To deploy and review the results, do the following:

1. Save your Pipeline, click **Run**, and then click **Run Pipeline**. The Pipeline executes.
2. In the **Serverless AWS Lambda Deploy** step, click **Input** to view the deployment inputs:

   ![](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-f38515334c406000c8dd4c1853a061988f5f87ed%2Fserverless-lambda-cd-quickstart-124.png?alt=media)
3. Click **Output** to view what is deployed:

   ![](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-88933d8486dcda1d7da4b1ebb02580e596cf1d39%2Fserverless-lambda-cd-quickstart-125.png?alt=media)
4. Click **Details** or **Console View** to view the logs.

The logs show the successful deployment:

```
Deploying..

Serverless Deployment Starting..
serverless deploy --stage dev --region us-east-1
Serverless: Deprecation warning: Support for Node.js versions below v12 will be dropped with next major release. Please upgrade at https://nodejs.org/en/
            More Info: https://www.serverless.com/framework/docs/deprecations/#OUTDATED_NODEJS
Serverless: Deprecation warning: Resolution of lambda version hashes was improved with better algorithm, which will be used in next major release.
            Switch to it now by setting "provider.lambdaHashingVersion" to "20201221"
            More Info: https://www.serverless.com/framework/docs/deprecations/#LAMBDA_HASHING_VERSION_V2
Serverless: Packaging service...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service artifactFile file to S3 (721 B)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
.........
Serverless: Stack update finished...
Service Information
service: myfunction
stage: dev
region: us-east-1
stack: myfunction-dev
resources: 11
api keys:
  None
endpoints:
  GET - https://<API_ID>.execute-api.us-east-1.amazonaws.com/tello
functions:
  hello: myfunction-dev-hello
layers:
  None

Deployment completed successfully.
```

You have deployed a function using Serverless Lambda and Harness.

## Clean up <a href="#clean-up" id="clean-up"></a>

For steps on deleting the Delegate, go to [Delete a delegate](https://developer.harness.io/harness-platform/use-harness-platform/delegates/delegate/manage-delegates/delete-a-delegate).

## Additional Serverless Lambda considerations <a href="#notes" id="notes"></a>

After you complete the quickstart, the following information can help you extend your Harness Serverless Lambda deployments.

### Serverless manifest supports Harness secrets and expressions <a href="#serverless-manifest-supports-harness-secrets-and-expressions" id="serverless-manifest-supports-harness-secrets-and-expressions"></a>

Harness supports injecting secrets and expressions into your `serverless.yaml`, but how this works depends on whether you are using **non-containerized (V1)** or **containerized (V2)** steps. Using the wrong approach is a common source of confusion.

**Non-containerized steps: expressions work directly in the manifest**

For non-containerized deployments, Harness resolves built-in expressions directly inside `serverless.yaml` on the manager side before passing the file to the Serverless CLI. Expressions such as `<+artifact.path>`, `<+artifact.image>`, and `<+service.name>` work as-is, as in the following example:

```yaml
service: <+service.name>
frameworkVersion: "2 || 3"

provider:
  name: aws
  runtime: nodejs12.x
functions:
  hello:
    handler: handler.hello
    events:
      - httpApi:
          path: /tello
          method: get
package:
  artifact: <+artifact.path>
plugins:
  - serverless-deployment-bucket@latest
```

**Containerized steps: expressions require a values file**

{% hint style="warning" %}
**Harness expressions do not work directly in the manifest for containerized steps**

If you place Harness expressions such as `<+artifact.path>` directly inside a `serverless.yaml` used with containerized steps, **they are not resolved**. The Serverless CLI receives the literal string (for example, `<+artifact.path>`), attempts to locate a file at that path, and fails with a file-not-found error. Nothing in the error message indicates that an unresolved expression is the root cause.

Containerized steps always use Go templating with a `values.yaml` file. Harness expressions placed directly in the manifest are not resolved.
{% endhint %}

For containerized deployments, use **Go template syntax** in `serverless.yaml` and supply a separate `values.yaml` file, the same pattern used by Kubernetes manifests in Harness. Harness resolves the `values.yaml` first (where Harness expressions work freely), then substitutes those values into the manifest before deployment.

**Step 1:** In `serverless.yaml`, reference values using Go template syntax, as in the following example:

```yaml
service: {{.Values.serviceName}}
frameworkVersion: "2 || 3"

provider:
  name: aws
  runtime: nodejs12.x
functions:
  hello:
    handler: handler.hello
    events:
      - httpApi:
          path: /tello
          method: get
package:
  artifact: {{.Values.artifact.path}}
plugins:
  - serverless-deployment-bucket@latest
```

**Step 2:** Add a `values.yaml` file in the same manifest folder. Harness expressions work here, as in the following example:

```yaml
serviceName: <+service.name>
artifact:
  path: <+artifact.path>
```

To add the values file in Harness, follow the same steps used to add the manifest (go to [Add the manifest](#add-the-manifest)), but at step 3 select **Values YAML** instead of **Serverless Lambda Manifest**.

For more information on Harness expressions and secrets, go to the following topics:

* [Add and Reference Text Secrets](https://developer.harness.io/harness-platform/use-harness-platform/secrets/add-use-text-secrets)
* [Built-in Harness Variables Reference](https://developer.harness.io/harness-platform/use-harness-platform/variables-and-expressions/harness-variables)
* [Input sets and overlays](https://developer.harness.io/harness-platform/use-harness-platform/pipelines/input-sets)

### Supported stores for Serverless Lambda YAML files <a href="#supported-stores-for-serverless-lambda-yaml-files" id="supported-stores-for-serverless-lambda-yaml-files"></a>

Harness can fetch your YAML files and packaged code from the following stores:

* AWS S3 buckets
  * You can store the `serverless.yml` and the artifact code in AWS S3, including in the same bucket.
  * You can use the ZIP format to retrieve the `serverless.yaml` and the packaged code that has been bundled in a ZIP file and published in S3.
  * Harness extracts the `serverless.yaml` file and uses it for deployment.
  * For S3, you use a Harness AWS Connector. The IAM role permissions required by Harness for S3 are described in [AWS Connector Settings Reference](https://developer.harness.io/harness-platform/use-harness-platform/connectors/cloud-providers/add-aws-connector/aws-connector-settings-reference#aws-s3).
* Git providers

### Rollback timestamps <a href="#rollback-timestamps" id="rollback-timestamps"></a>

In a Serverless CLI rollback (`serverless rollback --timestamp timestamp`), you must manually identify and select the timestamp of the last successful deployment. This can be difficult because you need to know which timestamp to use. With multiple developers deploying, there is the possibility of rolling back to the wrong version.

Harness avoids this issue by automatically identifying the last successful deployment using its timestamp. If a rollback occurs, Harness automatically rolls back to that deployment.

The deployment logs show the timestamps:

```
Serverless: Listing deployments:
Serverless: -------------
Serverless: Timestamp: 1653065606430
Serverless: Datetime: 2022-05-20T16:53:26.430Z
Serverless: Files:
Serverless: - compiled-cloudformation-template.json
Serverless: - myfunction.zip
Serverless: -------------
Serverless: Timestamp: 1653344285842
Serverless: Datetime: 2022-05-23T22:18:05.842Z
Serverless: Files:
Serverless: - artifactFile
Serverless: - compiled-cloudformation-template.json
Serverless: -------------
Serverless: Timestamp: 1653415240343
Serverless: Datetime: 2022-05-24T18:00:40.343Z
Serverless: Files:
Serverless: - artifactFile
Serverless: - compiled-cloudformation-template.json
```

If there is no change in code, Serverless does not deploy anything new. The logs show `Serverless: Service files not changed. Skipping deployment...`.

This is similar to how rollback is performed in the Serverless CLI, but Harness performs rollback automatically and always uses the timestamp of the last successful deployment.

During a Harness rollback, the logs show the timestamp used to roll back to the last successful deployment (`rollback --timestamp 1653415240343 --region us-east-1 --stage dev`):

```
Rollback..

Serverless Rollback Starting..
serverless rollback --timestamp 1653415240343 --region us-east-1 --stage dev
Serverless: Deprecation warning: Support for Node.js versions below v12 will be dropped with next major release. Please upgrade at https://nodejs.org/en/
            More Info: https://www.serverless.com/framework/docs/deprecations/#OUTDATED_NODEJS
Serverless: Deprecation warning: Resolution of lambda version hashes was improved with better algorithm, which will be used in next major release.
            Switch to it now by setting "provider.lambdaHashingVersion" to "20201221"
            More Info: https://www.serverless.com/framework/docs/deprecations/#LAMBDA_HASHING_VERSION_V2
Serverless: Updating Stack...

Rollback completed successfully.
```

### Versioning <a href="#versioning" id="versioning"></a>

Serverless Lambda deployments are versioned using the timestamp of their deployment. This versioning has no relation to the [versioning in AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/configuration-versions.html).

### Sidecar artifacts <a href="#sidecar-artifacts" id="sidecar-artifacts"></a>

You reference sidecar artifacts with the format `<+artifacts.sidecars.[artifact_Id]>`.

The artifact ID comes from the Artifact Details:

![](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-e22c98da591d2cc64cd727ee5b87f79953b60a77%2Fserverless-lambda-cd-quickstart-126.png?alt=media)

The artifact list also shows it:

![](https://3694223630-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fy1JhZ4oKIppwY7d5AhPj%2Fuploads%2Fgit-blob-349bc8ca5b7af45a62e22a7a9c1cd800087da77f%2Fserverless-lambda-cd-quickstart-127.png?alt=media)

**Docker sidecars**

The following is an example of a `serverless.yaml` file referencing primary and sidecar artifacts:

```yaml
functions:
  hello:
    image: <+artifact.image>
  hello1:
    image: <+artifacts.sidecars.mysidecar>
```

**Non-container sidecars**

The following is an example of a `serverless.yaml` file referencing primary and sidecar artifacts:

```yaml
service: <SERVICE_NAME>
frameworkVersion: "2.35.0"

provider:
  name: aws
  runtime: java8

package:
  artifact: <+artifact.path>

functions:
  currentTime:
    handler: com.serverless.Handler
    events:
      - httpApi:
          path: /time
          method: get
    layers:
      # Ref name is generated by TitleCasing the layer name & appending LambdaLayer
      - { Ref: CommonLibsLambdaLayer }

layers:
  commonLibs:
    package:
      artifact: <+artifacts.sidecars.mysidecar>
```

**Plugin support**

Harness supports Serverless plugins in your `serverless.yaml` file.

You add the plugin using the standard Serverless `plugins` format, and Harness adds the plugin at runtime, as in the following example:

```yaml
service: <+service.name>
frameworkVersion: "2 || 3"

provider:
  name: aws
  runtime: nodejs12.x
functions:
  hello:
    handler: handler.hello
    events:
      - httpApi:
          path: /tello
          method: get
package:
  artifact: <+artifact.path>
plugins:
  - serverless-deployment-bucket@latest
```

### Serverless YAML for files and images <a href="#serverless-yaml-for-files-and-images" id="serverless-yaml-for-files-and-images"></a>

The `serverless.yaml` format for files (for example, ZIP, JAR, WAR) is different from the format for Docker images.

**Serverless YAML for files**

The following example shows the format for files:

```yaml
service: example-service
frameworkVersion: "2 || 3"

provider:
  name: aws
  runtime: nodejs12.x
functions:
  hello:
    handler: handler.hello
    events:
      - httpApi:
          path: /tello
          method: get
package:
  artifact: <+artifact.path>
plugins:
  - serverless-deployment-bucket@latest
```

**Serverless YAML for Docker images**

The following example shows the format for Docker images:

```yaml
service: example-service
frameworkVersion: "2 || 3"

provider:
  name: aws

functions:
  hello:
    image: <+artifact.image>
```

## Limitations <a href="#limitations" id="limitations"></a>

Note the following limitation when you use Serverless Framework v4.

### Custom config file limitation in Serverless V4 <a href="#custom-config-file-limitation-in-serverless-v4" id="custom-config-file-limitation-in-serverless-v4"></a>

When using Serverless Framework v4, you cannot use a custom config file (via the `--config` argument or **Serverless Config File Path** setting) and keep a `serverless.yml` file in the root directory at the same time.

**Issue description:**

When you provide a custom serverless manifest file using the `--config` argument (or the **Serverless Config File Path** setting in Harness), the Serverless v4 CLI continues to attempt to access the default `serverless.yml` file if it exists in the same directory. If the default `serverless.yml` file has an invalid structure, the deployment fails with a JSON parsing error, even though a valid custom config file was specified.

**Workaround:**

To use a custom config file with Serverless Framework v4, do not have a `serverless.yml` file in the same directory as your custom config file. Remove or rename the default `serverless.yml` file before running any serverless commands.

**Example scenario:**

The following scenario illustrates the limitation:

* You have a custom config file: `serverless-custom.yml`
* You specify it using **Serverless Config File Path** in Harness or `--config serverless-custom.yml`
* If `serverless.yml` also exists in the same directory with invalid content, the deployment fails
* **Solution:** Delete or move the `serverless.yml` file from the directory

This is a known behavior of Serverless Framework v4 and not a Harness-specific issue.

## Next steps <a href="#next-steps" id="next-steps"></a>

For frequently asked questions about Serverless Lambda deployments in Harness, go to [Serverless Lambda deployments FAQs](/continuous-delivery/use-continuous-delivery/deploy-services-on-different-platforms/serverless/serverless-deployment-faqs.md).

{% @harness-feedback/feedback %}
