向量数据库:ECS-Fargate 上的 Qdrant 集群

发布: (2025年12月31日 GMT+8 11:36)
6 min read
原文: Dev.to

I’m happy to translate the article for you, but I’ll need the actual text of the post. Could you please paste the content you’d like translated (excluding the source link you’ve already provided)? Once I have the text, I’ll translate it into Simplified Chinese while preserving the original formatting, markdown, and code blocks.

何时需要它?

  • 当由于合规性原因或网络性能限制,SaaS 不可行时。
  • 当向量数据库必须与解决方案的其余部分位于同一个 AWS 账户时。
  • 当你不想(或不能)使用 Kubernetes 时。

有疑问吗? 请参阅 文章 #2,深入了解为何某些设计决策必须如此。
本文 (#1) 侧重于 CDK 代码片段,帮助你快速入门(针对已经熟悉 CDK 的人)。

所有这些(CDK、ECS 与集群)让人感到压力山大?
可从 Qdrant.tech 或我的当前雇主(AWS 合作伙伴)获取专业服务。

简短概述

  • 在 ECS 上运行 4‑ 或 6‑ 节点 Qdrant 集群,跨 2‑3 个可用区
  • 保持简单:让 AWS 处理可用性、正常运行时间和可用区平衡。
  • 使用 单一端点 访问整个集群,无论节点故障/更换。
  • 不使用 EBS —— 依赖 EFS 实现原生快照和数据保护。
  • 通过 ALB + Qdrant‑native API key 保护 Qdrant 仪表板。

Qdrant 集群示意图

我该如何 … ?

  • Article #2 – 对最终实现形成关键设计和关键需求的完整细节。
  • Article #3 – 快照、数据恢复和备份策略。
  • GitLab repo – 包含完整的 CDK 构造。
  • Assumption – 您将从 Qdrant 的 GitHub 仓库构建自定义 Qdrant 容器镜像(Dockerfile)。请参阅 article #4 获取合适的 Dockerfile。

以下是面向 CDK 专家的关键“积木”。(再次参阅 article #2,了解每个选择背后的 原因。)

关键变量

// Paths / names
bashScriptFromArticle4 = ".../local-path-inside-docker__to_bash-script-from-article-4...";

ecsClusterName      = `${baseName}-${cpuArchStr}`;
fargateContainerName = `${baseName}-${cpuArchStr}`;
fargateServiceName   = `ECSSvc-${fargateContainerName}`;
taskDefContainerName = `cont-${fargateContainerName}`;

domainName = `${ecsClusterName}.local`;
qdrantFQDN = `qdrant-node.${domainName}`;

// Secrets
nativeApiKeySecret = new aws_secretsmanager.Secret(...);
// excludeCharacters = "~`@#$%^&*+={}[]()|\\:;'\"”<>,/? ";

Fargate 任务定义

new aws_ecs.FargateTaskDefinition(this, "QdrantTaskDef", {
  family: fargateContainerName,               // Equivalent to task name
  cpu: ECS_FARGATE_CPU_SIZING + 512,
  memoryLimitMiB: ECS_FARGATE_MEMORY_SIZING_GB * 1024 + 1024,
  enableFaultInjection: basicProps.tier === "dev",
  ephemeralStorageGiB: 22,                    // Must be 21‑200 GiB
  runtimePlatform: {
    cpuArchitecture: ecsCpuArchitecture,
    operatingSystemFamily: aws_ecs.OperatingSystemFamily.LINUX,
  },
  volumes: [
    {
      name: fargateContainerName,               // Must be referenced in the Service
      efsVolumeConfiguration: {
        fileSystemId: efsFileSystem.fileSystemId,
        rootDirectory: "/",
        transitEncryption: "ENABLED",
        authorizationConfig: {
          accessPointId: efsAccessPoint.accessPointId,
          iam: "ENABLED",
        },
      },
    },
  ],
});

Fargate 服务

new aws_ecs.FargateService(this, "QdrantService", {
  cluster: myECSCluster,
  serviceName: `${fargateServiceName}-${label}`,
  taskDefinition: qdrantTaskDefinition,
  desiredCount: desiredCount,
  minHealthyPercent: 0,          // Allow the single task to be stopped during deployment
  maxHealthyPercent: 200,       // Allow 1 new task to start before stopping the old one
  vpcSubnets: {
    onePerAz: true,
    subnetType: aws_ec2.SubnetType.PRIVATE_WITH_EGRESS,
    availabilityZones: vpc.availabilityZones,
  },
  securityGroups: [fargateSvcSecurityGroup],
  assignPublicIp: false,
  enableExecuteCommand: true,    // Enable ECS Exec for debugging
  propagateTags: aws_ecs.PropagatedTagSource.SERVICE,
  availabilityZoneRebalancing: aws_ecs.AvailabilityZoneRebalancing.ENABLED,
  circuitBreaker: { enable: true, rollback: true }, // Deployment circuit breaker
});

Fargate 任务的容器

请参阅 article #4 获取 docker build 步骤。

const containerImage = aws_ecs.ContainerImage.fromEcrRepository(ecrRepo, qdrantImageTag);

// Add container to task definition
const dockerLabels = {
  "app.cluster": ecsClusterName,
  "app.service": fargateServiceName,
  "app.task-definition": fargantContainerName, // must match the task family name
  "app.component": "vector-database",
  "app.version": cdkContextBuildQdrantImageTag,
  "app.environment": basicProps.tier,
};

const portMappings = [
  { containerPort: 6333, protocol: aws_ecs.Protocol.TCP },
  { containerPort: 6334, protocol: aws_ecs.Protocol.TCP }, // Qdrant API & gRPC
];

下一步

  1. 克隆 GitLab 仓库,其中包含 CDK 构件。
  2. 构建自定义 Qdrant 镜像,使用第 4 篇文章中的 Dockerfile。
  3. 部署 堆栈(cdk deploy)。
  4. 验证 单个端点是否解析到健康的 Qdrant 节点。
  5. 配置 ALB 和 API‑key 以访问仪表盘。

需要帮助?

  • 专业服务 – Qdrant.tech 或我的现任雇主(AWS 合作伙伴)。
  • 进一步阅读 – 上文链接的第 2、3、4 篇文章。

构建愉快! 🚀

容器定义

const portMappings = [
  { containerPort: 6333, protocol: aws_ecs.Protocol.TCP, name: 'qdrant-rest', appProtocol: aws_ecs.AppProtocol.http },
  { containerPort: 6334, protocol: aws_ecs.Protocol.TCP, name: 'qdrant-grpc', appProtocol: aws_ecs.AppProtocol.http },
  { containerPort: 6335, protocol: aws_ecs.Protocol.TCP, name: 'qdrant-cluster', appProtocol: aws_ecs.AppProtocol.http },
];

const containerEnvironmentVariables = {
  // runtime environment‑variables used by Qdrant‑VectorDB docker‑container
  QDRANT__CLUSTER__ENABLED: "true",
  QDRANT__SERVICE__API_KEY: nativeApiKeySecret.secretValue.unsafeUnwrap(),
};

qdrantPrimaryNodeTaskDefinition.addContainer('QdrantContainer', {
  containerName: taskDefContainerName,
  image: containerImage,
  user: "1000:1000",
  command: ['/bin/sh', '-c', bashScriptFromArticle4],
  cpu: constantsCdk.ECS_FARGATE_CPU_SIZING,
  memoryLimitMiB: ECS_FARGATE_MEMORY_SIZING_GB * 1024, // in MB
  environment: containerEnvironmentVariables,
  dockerLabels: { ...dockerLabels, 'app.instance': 'primary-node' },
  portMappings,
  essential: true,
  logging: containerLogs,
  healthCheck: commonInsideContainerHealthCheck,
});

安全组

const fargateSvcSecurityGroup = new aws_ec2.SecurityGroup(
  cdkScope,
  'QdrantSecurityGroupForFargate',
  {
    vpc,
    securityGroupName: `${ecsClusterName}-SvcInbound-${fargateContainerName}`,
    description: `For FARGATE-service - inbound 6333,6334 only, NO outbound. Cluster: ${ecsClusterName}, Container: ${fargateContainerName}`,
    allowAllOutbound: false, // Deny/Allow – Explicitly block all outbound traffic
  }
);

// Inbound rules for Qdrant ports
fargateSvcSecurityGroup.addIngressRule(
  aws_ec2.Peer.ipv4(vpc.vpcCidrBlock),
  aws_ec2.Port.tcp(6333),
  'Allow inbound traffic on port 6333 (Qdrant REST API)'
);

// Outbound HTTPS for ECR image pulling
fargateSvcSecurityGroup.addEgressRule(
  aws_ec2.Peer.anyIpv4(),
  aws_ec2.Port.tcp(443),
  'Allow outbound HTTPS for ECR image pulling, whether or NOT using VPC Endpoints'
);

// Cluster‑replication traffic
fargateSvcSecurityGroup.addIngressRule(
  fargateSvcSecurityGroup,
  aws_ec2.Port.tcp(6334),
  'Allow INTRA‑CLUSTER Replication traffic on port 6334 (Qdrant gRPC API)'
);
fargateSvcSecurityGroup.addEgressRule(
  fargateSvcSecurityGroup,
  aws_ec2.Port.tcp(6334),
  'Allow INTRA‑CLUSTER Replication traffic on port 6334 (Qdrant gRPC API)'
);
fargateSvcSecurityGroup.addIngressRule(
  fargateSvcSecurityGroup,
  aws_ec2.Port.tcp(6335),
  'Allow INTRA‑CLUSTER Replication traffic on port 6335 (Qdrant Cluster‑Replication traffic)'
);
fargateSvcSecurityGroup.addEgressRule(
  fargateSvcSecurityGroup,
  aws_ec2.Port.tcp(6335),
  'Allow INTRA‑CLUSTER Replication traffic on port 6335 (Qdrant Cluster‑Replication traffic)'
);

// Allow Fargate tasks to access EFS
for (const efsSecurityGroup of efsSecurityGroups) {
  efsSecurityGroup.addIngressRule(
    fargateSvcSecurityGroup,
    aws_ec2.Port.tcp(2049),
    'Allow NFS access from Fargate tasks'
  );
  fargateSvcSecurityGroup.addEgressRule(
    efsSecurityGroup,
    aws_ec2.Port.tcp(2049),
    'Allow NFS access to EFS'
  );
}

其他相关文章

  • Get‑Startedarticle #1 – 本文。
  • Designarticle #2 – 关于关键设计与关键需求的完整细节,这些决定了最终实现。
  • Snapshotsarticle #3 – 快照和数据恢复的讨论。
  • Dockerfile – 一个单独的 GitLab 仓库包含完整的 CDK 构造。
    • 假设:您可以接受从 Qdrant 的 GitHub 自定义构建 Qdrant 容器镜像(使用自定义 Dockerfile)。请参阅 article #4 了解合理/可辩护的 Dockerfile

结束。

Back to Blog

相关文章

阅读更多 »