벡터 데이터베이스: ECS-Fargate에서 Qdrant 클러스터

발행: (2025년 12월 31일 오후 12:36 GMT+9)
7 min read
원문: Dev.to

I’m happy to translate the article for you, but I’ll need the full text of the post (the content you’d like translated). Could you please paste the article’s body here? Once I have that, I’ll provide a Korean translation while preserving the original formatting, markdown, and code blocks.

언제 필요합니까?

  • 컴플라이언스 이유나 네트워크‑성능 제약으로 SaaS를 사용할 수 없을 때.
  • 벡터‑DB가 솔루션의 나머지와 동일한 AWS 계정에 있어야 할 때.
  • Kubernetes를 사용하고 싶지 않거나 (사용할 수 없을 때).

질문이 있나요? 왜 특정 설계 결정이 그렇게 되어야 하는지 자세히 보려면 article #2 를 참고하세요.
이 기사 (#1)는 CDK에 이미 익숙한 분들을 위해 빠르게 시작할 수 있는 CDK 스니펫에 초점을 맞춥니다.

이 모든 것(CDK, ECS 및 클러스터)이 벅차게 느껴지나요?
전문 서비스를 원하시면 Qdrant.tech 혹은 저/현재 근무 중인 회사(AWS 파트너)에게 문의하세요.

짧은 요약

  • 4‑ 또는 6‑노드 Qdrant 클러스터를 ECS에서 실행하고, 2‑3 AZ에 걸쳐 배포합니다.
  • 단순하게 유지: 가용성, 가동 시간 및 AZ‑밸런싱은 AWS에 맡깁니다.
  • 노드 장애/교체와 관계없이 전체 클러스터에 단일 엔드포인트를 사용합니다.
  • EBS는 사용하지 않고 EFS를 활용해 네이티브 스냅샷 및 데이터 보호를 구현합니다.
  • ALB + Qdrant‑native API 키를 통해 Qdrant 대시보드를 보안합니다.

Qdrant cluster diagram

어떻게 … ?

  • Article #2 – 최종 구현을 형성한 핵심 설계 및 주요 요구 사항에 대한 전체 세부 정보.
  • Article #3 – 스냅샷, 데이터 복원 및 백업 전략.
  • GitLab repo – 전체 CDK 구성 요소를 포함합니다.
  • Assumption – Qdrant의 GitHub 저장소에서 맞춤 Qdrant 컨테이너 이미지(Dockerfile)를 빌드할 것이라고 가정합니다. 합리적인 Dockerfile은 **article #4**을 참조하세요.

아래는 CDK 전문가를 위한 핵심 “레고‑블록”입니다. (각 선택의 이유는 기사 #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 #4docker 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. Dockerfile(기사 #4) 을 사용해 커스텀 Qdrant 이미지를 빌드합니다.
  3. 스택을 배포합니다 (cdk deploy).
  4. 단일 엔드포인트가 정상적인 Qdrant 노드에 연결되는지 확인합니다.
  5. ALB와 API‑키를 설정해 대시보드 접근을 구성합니다.

도움이 필요하신가요?

  • 전문 서비스 – 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에서 커스텀 Dockerfile을 사용해 Qdrant 컨테이너 이미지를 직접 빌드하는 것이 괜찮다고 생각합니다. 합리적이고 정당한 Dockerfile에 대해서는 article #4를 참조하세요.

끝.

Back to Blog

관련 글

더 보기 »