首页 > 解决方案 > 使用 AWS-CDK 部署时无法从 Lambda 服务连接到 Elasticache Redis 集群

问题描述

在过去的几天里,我一直在尝试使用 aws-cdk(typescript) 复制我们现有的 AWS VPC,我发现从 nodejs lambda 函数连接到 Redis 很困难。我遵循了有关创建新 VPC、设置私有/公共/隔离子网以及将服务部署到各自子网的标准教程。

我用来尝试实现此目的的代码如下:

import { NodejsFunction } from "@aws-cdk/aws-lambda-nodejs";
import * as elasticache from "@aws-cdk/aws-elasticache";
import * as apiGateway from "@aws-cdk/aws-apigateway";
import * as rds from "@aws-cdk/aws-rds";
import * as iam from "@aws-cdk/aws-iam";
import * as ec2 from "@aws-cdk/aws-ec2";
import * as cdk from "@aws-cdk/core";
import * as path from "path";
import * as dotenv from "dotenv";

const some_service_path =
  "/some/service/path";

const env = dotenv.config({
  path: path.join(some_service_path, "env", ".production.env"),
});

export class TestStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const vpc = new ec2.Vpc(this, "VPC", {
      subnetConfiguration: [
        {
          cidrMask: 24,
          name: "ingress",
          subnetType: ec2.SubnetType.PUBLIC,
        },
        {
          cidrMask: 24,
          name: "application",
          subnetType: ec2.SubnetType.PRIVATE_WITH_NAT,
        },
        {
          cidrMask: 28,
          name: "rds",
          subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
        },
      ],
    });


    const rdsSubnetIds = vpc.selectSubnets({
      subnetGroupName: "rds",
    }).subnetIds;


    const redisClusterSubnetGroup = new elasticache.CfnSubnetGroup(
      this,
      "RedisClusterPrivateSubnetGroup",
      {
        subnetIds: rdsSubnetIds,
        cacheSubnetGroupName: "cluster-subnet",
        description: "Sandboxed redis cluster",
      }
    );

    const redisReplicationGroup = new elasticache.CfnReplicationGroup(
      this,
      "company-redis-replication-sandbox",
      {
        replicasPerNodeGroup: 2,
        numNodeGroups: 3,
        cacheSubnetGroupName: redisClusterSubnetGroup.cacheSubnetGroupName,
        replicationGroupDescription: "company Redis replication group",
        replicationGroupId: "company-redis-replication-group",
        securityGroupIds: [vpc.vpcDefaultSecurityGroup],
        authToken: "authtoken",
        cacheNodeType: "cache.t2.micro",
        transitEncryptionEnabled: true,
        atRestEncryptionEnabled: true,
        multiAzEnabled: true,
        engine: "redis",
      }
    );
    redisReplicationGroup.addDependsOn(redisClusterSubnetGroup);

    const entry = path.join(__dirname, "service", "handler.ts");


    const { subnets: applicationSubnet } = vpc.selectSubnets({
      subnetGroupName: "application",
    });

    const someServiceLambda = new NodejsFunction(this, "some-service", {
      runtime: lambda.Runtime.NODEJS_14_X,
      vpcSubnets: { subnets: applicationSubnet },
      entry: entry,
      handler: "graphqlHandler",
      environment: {
        ...env.parsed,
        REDIS_HOST: redisReplicationGroup.attrConfigurationEndPointAddress,
        REDIS_PORT: redisReplicationGroup.attrConfigurationEndPointPort,
        REDIS_PASSWORD: "authtoken",
        REDIS_MODE: "cluster",
        REDIS_USE_TLS: "true",
      },
      vpc,
    });

    new apiGateway.LambdaRestApi(this, "someServiceEndpoint", {
      handler: someServiceLambda,
    });
  }
}



该服务是一个依赖于节点模块 IORedis 的 ApolloGQL 应用程序。当我从浏览器访问 lambda 函数时,GraphQL 游乐场正确加载;但是,当我尝试运行连接到 Redis 集群的突变时,我收到以下 IORedis 错误:

ERROR   [ioredis] Unhandled error event: ClusterAllFailedError: Failed to refresh slots cache.
    at tryNode (/var/task/index.js:88946:27)
    at /var/task/index.js:88963:15
    at Timeout.<anonymous> (/var/task/index.js:89178:20)
    at Timeout.run (/var/task/index.js:84969:20)
    at listOnTimeout (internal/timers.js:559:11)
    at processTimers (internal/timers.js:500:7)

任何帮助将不胜感激。

标签: node.jstypescriptamazon-web-servicesamazon-ec2aws-cdk

解决方案


推荐阅读