引言

在现代云计算环境中,Lambda 函数是一种常见的无服务器计算服务,用于构建和执行应用程序的功能。为了实现 Lambda 函数的更新控制,我们可以使用 Jenkins,一个流行的持续集成和持续交付(CI/CD)工具。本文将介绍如何在 Jenkins 中通过参数化构建过程和 Extended Choice Parameter 插件,实现对特定 Lambda 函数的自动化构建与部署。

Jenkins 构建 Lambda 函数的意义与目的

Lambda 函数的构建和部署通常涉及多个步骤,包括代码上传、依赖解析、更新函数代码、发布新版本等。手动执行这些步骤既繁琐又容易出错。通过使用 Jenkins,我们可以实现以下目标:

  1. 自动化构建: 将 Lambda 函数的构建过程自动化,减少手动操作,提高效率。
  2. 参数化控制: 使用 Jenkins 的 Extended Choice Parameter 插件,通过参数化控制构建过程,使用户能够选择要构建和部署的 Lambda 函数。
  3. 集成 AWS 服务: 通过 AWS 的 Boto3 SDK,实现 Jenkins 与 AWS 服务的集成,包括 Secrets Manager 和 Lambda。
  4. 实时通知: 使用 DingDing 机器人,实现 Lambda 函数部署成功后的实时通知,提高可视化和沟通效果。

Jenkins 构建 Lambda 函数的实现代码详解

Python 部署脚本

#!/usr/bin/python3
import boto3
import requests
import json,os

def get_secret(secret_name, region_name):
    """
    从AWS Secrets Manager获取指定的secret。
    """
    client = boto3.client(service_name='secretsmanager', region_name=region_name)
    return json.loads(client.get_secret_value(SecretId=secret_name)['SecretString'])

def send_dingding_message(lambda_name, token, version):
    """
    向DingDing发送一条消息,通知Lambda函数部署成功。
    """
    headers = {'Content-Type': 'application/json'}
    data = {
        "msgtype": "markdown",
        "markdown": {
            "title": f"Restart {lambda_name} Success",
            "text": f"<font face='黑体' color='#00EC00'>Restart {lambda_name} VERSION:{version} Success</font>\n"
        }
    }
    response = requests.post(f"https://oapi.dingtalk.com/robot/send?access_token={token}", headers=headers, data=json.dumps(data))
    print(response.text)

def update_lambda_function_and_get_version(lambda_name, s3_bucket, s3_key, region):
    """
    使用boto3更新Lambda函数的代码并发布新版本,然后返回新版本号。
    """
    client = boto3.client('lambda', region_name=region)
    response = client.update_function_code(
        FunctionName=lambda_name,
        S3Bucket=s3_bucket,
        S3Key=s3_key,
        Publish=True
    )
    return response['Version']

# 从Secrets Manager获取DingDing token
token = get_secret('base', 'us-east-1')['BUILD1_TOKEN']

# 定义Lambda函数的配置
lambda_config = {
    "S-iot-cvm-account": [("us-east-1", "pro-codebuild", "lambda-zip/pro/S-iot-cvm-account.zip")],
    "Govee-Skill-Handle-Prod": [
        ("eu-west-1", "pro-ew1-codebuild", "lambda-zip/pro/S-iot-alexa-skills.zip"),
        ("us-east-1", "pro-ue1-codebuild", "lambda-zip/pro/S-iot-alexa-skills.zip"),
        ("us-west-2", "pro-uw2-codebuild", "lambda-zip/pro/S-iot-alexa-skills.zip")
    ],
    "cloud9-iot-rule-intercept-intercept-R8PQYULWSH7M": [("us-east-1", "pro-codebuild", "lambda-zip/pro/S-iot-rule.zip")],
    "google-assistant-iot-hanlder-prod": [("us-east-1", "pro-codebuild", "lambda-zip/pro/S-iot-google-actions.zip")]
}

# 从Jenkins环境变量获取Lambda函数的名称
lambda_names = os.environ['LAMBDA_NAMES'].split(',')

# 更新Lambda函数并发送DingDing消息
for lambda_name in lambda_names:
    if lambda_name in lambda_config:
        for region, s3_bucket, s3_key in lambda_config[lambda_name]:
            version = update_lambda_function_and_get_version(lambda_name, s3_bucket, s3_key, region)
            send_dingding_message(lambda_name, token, version)
    else:
        print(f"Warning: No configuration found for {lambda_name}")
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.

Shell部署脚本

#!/bin/bash

get_secret() {
  secret_name=$1
  region_name=$2
  aws secretsmanager get-secret-value --secret-id $secret_name --region $region_name --query 'SecretString' --output text
}

send_dingding_message() {
  lambda_name=$1
  token=$2
  version=$3
  headers='Content-Type: application/json'
  data="{\"msgtype\": \"markdown\", \"markdown\": {\"title\": \"Restart $lambda_name Success\", \"text\": \"<font face='黑体' color='#00EC00'>Restart $lambda_name VERSION:$version Success</font>\"}}"
  curl -s -X POST "https://oapi.dingtalk.com/robot/send?access_token=$token" -H "$headers" -d "$data"
}

update_lambda_function_and_get_version() {
  lambda_name=$1
  region=$2
  s3_bucket=$3
  s3_key=$4
  aws lambda update-function-code --function-name $lambda_name --region $region --s3-bucket $s3_bucket --s3-key $s3_key --publish | jq -r .Version
}

# 从Secrets Manager获取DingDing token
token=$(get_secret 'base' 'us-east-1' | jq -r .BUILD1_TOKEN)

# 定义Lambda函数的配置
lambda_config=(
  "S-iot-cvm-account:us-east-1:pro-codebuild:lambda-zip/pro/S-iot-cvm-account.zip"
  "Govee-Skill-Handle-Prod:eu-west-1:pro-ew1-codebuild:lambda-zip/pro/S-iot-alexa-skills.zip"
  "Govee-Skill-Handle-Prod:us-east-1:pro-ue1-codebuild:lambda-zip/pro/S-iot-alexa-skills.zip"
  "Govee-Skill-Handle-Prod:us-west-2:pro-uw2-codebuild:lambda-zip/pro/S-iot-alexa-skills.zip"
  "cloud9-iot-rule-intercept-intercept-R8PQYULWSH7M:us-east-1:pro-codebuild:lambda-zip/pro/S-iot-rule.zip"
  "google-assistant-iot-hanlder-prod:us-east-1:pro-codebuild:lambda-zip/pro/S-iot-google-actions.zip"
)

# 从Jenkins环境变量获取Lambda函数的名称
IFS=',' read -ra lambda_names <<< "$LAMBDA_NAMES"

# 更新Lambda函数并发送DingDing消息
for lambda_config_entry in "${lambda_config[@]}"; do
  IFS=':' read -ra config <<< "$lambda_config_entry"
  lambda_name=${config[0]}
  region=${config[1]}
  s3_bucket=${config[2]}
  s3_key=${config[3]}
  
  if [[ " ${lambda_names[@]} " =~ " $lambda_name " ]]; then
    version=$(update_lambda_function_and_get_version $lambda_name $region $s3_bucket $s3_key)
    send_dingding_message $lambda_name $token $version
  else
    echo "Warning: No configuration found for $lambda_name"
  fi
done
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.

注意:

  • 在 Shell 中,数组的声明和使用方式与 Python 不同。上面的 lambda_config 数组包含了 Lambda 函数的配置信息。
  • 使用 jq 工具来解析 JSON 数据,确保其在系统上可用。如果没有安装,请根据系统环境选择合适的安装方式。
  • LAMBDA_NAMES 环境变量应该包含您要部署的 Lambda 函数的名称,以逗号分隔。

使用 Extended Choice Parameter 进行参数化构建

在 Jenkins Job 的配置中,使用 Extended Choice Parameter 插件,定义了一个名为 LAMBDA_NAMES 的参数,其值为需要构建和部署的 Lambda 函数的名称列表。

Name: LAMBDA_NAMES
Parameter Type: Check Boxes
Number of Visible Items: 10
Delimiter:,
Quote Value:  S-iot-cvm-account,Govee-Skill-Handle-Prod,cloud9-iot-rule-intercept-intercept-R8PQYULWSH7M,google-assistant-iot-hanlder-prod
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

总结

通过 Jenkins 构建 Lambda 函数的自动化流程,我们实现了对 Lambda 函数更新控制的一体化解决方案。使用参数化构建,我们可以轻松选择并部署特定的 Lambda 函数,同时通过 DingDing 机器人实时通知,提高了构建过程的可视化和沟通效果。这种自动化流程不仅减轻了开发人员的负担,还提高了整个团队的工作效率。

在实际应用中,可以根据团队的需求进行更多定制和扩展,例如添加更多的构建步骤、日志记录、错误处理等。通过 Jenkins 构建 Lambda 函数的自动化流程,将使开发团队更加专注于业务逻辑的实现,提高开发效率,降低出错风险。