AWS CDK - 无法通过 Cloudfront 域访问 ALB



我正在尝试使用AWS- cdk部署一个相当基本的Nodejs CRUD API到AWS。该服务在docker容器中运行,我将其部署到位于ALB后面的ECS Fargate集群中。我在Route53中也有一个域,我正在尝试使用。

我遇到的问题是我似乎无法通过域访问ALB。我可以通过HTTP使用其默认的AWS DNS (xxx.us -west-2.elb.amazonaws.com/)直接访问ALB,但是当我试图通过域访问它时,我得到504个超时。

我对AWS和CDK很陌生,所以我肯定我在这里错过了一些明显的东西。任何建议或推荐的资源/示例将不胜感激。下面是我的CDK代码:

import { Stack, StackProps } from "aws-cdk-lib";
import { Construct } from "constructs";
import * as Cloudfront from "aws-cdk-lib/aws-cloudfront";
import * as CloudfrontOrigins from "aws-cdk-lib/aws-cloudfront-origins";
import * as Route53 from "aws-cdk-lib/aws-route53";
import * as Route53Targets from "aws-cdk-lib/aws-route53-targets";
import * as ACM from "aws-cdk-lib/aws-certificatemanager";
import * as EC2 from "aws-cdk-lib/aws-ec2";
import * as ECS from "aws-cdk-lib/aws-ecs";
import * as EcsPatterns from "aws-cdk-lib/aws-ecs-patterns";
interface Props extends StackProps {
domainName: string;
dockerDir: string;
}
export class AppStack extends Stack {
constructor(scope: Construct, id: string, { domainName, dockerDir, ...rest }: Props) {
super(scope, id, rest);
const hostedZone = Route53.HostedZone.fromLookup(this, `${id}_Zone`, {
domainName,
});
const vpc = new EC2.Vpc(this, `${id}_Vpc`, { maxAzs: 2 });
const cluster = new ECS.Cluster(this, `${id}_Ec2Cluster`, { vpc });
cluster.addCapacity(`${id}_DefaultAutoScalingGroup`, {
instanceType: EC2.InstanceType.of(
EC2.InstanceClass.T3,
EC2.InstanceSize.MICRO
),
minCapacity: 1,
maxCapacity: 3,
});
const certificate = new ACM.DnsValidatedCertificate(
this,
`${id}_SiteCertificate`,
{
domainName,
hostedZone,
region: "us-east-1",
}
);

const fargateService = new EcsPatterns.ApplicationLoadBalancedFargateService(
this,
`${id}_FargateLoadBalancedService`,
{
cluster,
desiredCount: 1,
publicLoadBalancer: true,
taskImageOptions: {
image: ECS.ContainerImage.fromAsset(dockerDir),
containerPort: 8000,
environment: {
PORT: '8000',
},
},
}
);

const distribution = new Cloudfront.Distribution(
this,
`${id}_SiteDistribution`,
{
certificate,
domainNames: [domainName],
minimumProtocolVersion: Cloudfront.SecurityPolicyProtocol.TLS_V1_2_2021,
defaultBehavior: {
origin: new CloudfrontOrigins.HttpOrigin(
fargateService.loadBalancer.loadBalancerDnsName
),
compress: false,
cachePolicy: Cloudfront.CachePolicy.CACHING_DISABLED,
allowedMethods: Cloudfront.AllowedMethods.ALLOW_ALL,
},
}
);


new Route53.ARecord(this, `${id}_SiteAliasRecord`, {
recordName: domainName,
target: Route53.RecordTarget.fromAlias(
new Route53Targets.CloudFrontTarget(distribution)
),
zone: hostedZone,
});
}
}

这个类在我的bin/infra中创建。ts文件:

#!/usr/bin/env node
import "source-map-support/register";
import * as cdk from "aws-cdk-lib";
import * as path from "path";
import { AppStack } from "../lib/AppStack";
const appId = `MyApp`;
const app = new cdk.App();
new AppStack(app, `${appId}Stack`, {
dockerDir: path.resolve(__dirname, "..", "api"), // contains the Dockerfile
domainName: 'mydomain.com',
env: {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION,
},
});

这里是Dockerfile,如果它有用的话。

FROM node:16-alpine as builder
ENV NODE_ENV build
USER node
WORKDIR /home/node
COPY package*.json ./
RUN npm i
COPY --chown=node:node . .
RUN npm run build 
&& npm prune --production
# ---
FROM node:16-alpine
ENV PORT 8000
ENV NODE_ENV production
# Add curl for healthcheck
RUN apk --no-cache add curl
USER node
WORKDIR /home/node
COPY --from=builder --chown=node:node /home/node/package*.json ./
COPY --from=builder --chown=node:node /home/node/node_modules/ ./node_modules/
COPY --from=builder --chown=node:node /home/node/dist/ ./dist/
EXPOSE 8000
CMD ["node", "dist/main.js"]
HEALTHCHECK CMD curl -f http://localhost:8000/api/healthcheck || exit 1

当我通过我的域访问我的服务时,为什么我得到504错误?或者我可以去哪里更好地了解我错过了什么?

CloudFront默认情况下与它的源通信HTTPS(端口443)。默认情况下,ALB(无论由ApplicationLoadBalancedFargateService构造显式或隐式创建)侦听HTTP(端口80),除非显式设置为HTTPS。由于您的ALB未配置为侦听HTTPS, CloudFront将尝试与仅侦听HTTP的ALB进行HTTPS对话。

要解决这个问题,将origin.protocolPolicy设置为OriginProtocolPolicy.HTTP_ONLY,这指示CloudFront与您的ALB交谈HTTP。请注意,下面的代码使用CDK v2,而且,我使用LoadBalancerV2Origin而不是HttpOrigin,尽管两者应该工作相同。

const lb = new elbv2.ApplicationLoadBalancer(this, 'LB', {
vpc,
internetFacing: true,
});
new cloudfront.Distribution(this, 'myDist', {
defaultBehavior: {
new origins.LoadBalancerV2Origin(loadBalancer, {
protocolPolicy: cloudfront.OriginProtocolPolicy.HTTP_ONLY,
})
},
});

最新更新