亚马逊AWS官方博客

基于 Amazon EKS 部署高可用 Dify

生成式 AI(Generative AI)和大语言模型(LLM)不仅大大提升了个人的信息获取和工作效率,也正在重塑企业应用。很多企业正在探索基于 LLM、RAG 和 Agent 的 GenAI 应用,通过与私域数据和现有的应用结合,来打造更创新、更具价值和更个性化的用户体验。

LangChain 是构建 GenAI 应用的非常流行的选择,它是一个非常流行的开源框架,提供了工具和组件,如数据加载、提示词模板、数据检索、RAG 引擎和 Agent 等,简化了构建基于 LLM 应用程序的过程。LangChain 的目标客户是开发者,使用此框架需要具有开发经验。可以把 LangChain 想象为有着锤子、钉子的工具箱。与之相比,Dify 提供了更接近生产需要的完整方案,Dify 好比是一套脚手架,并且经过了精良的工程设计和软件测试。

关于 Dify

Dify 是一款开源的大语言模型(LLM)应用开发平台。它融合了后端即服务(Backend as Service)和 LLMOps 的理念,使开发者可以快速搭建生产级的生成式 AI 应用。即使你是非技术人员,也能参与到生成式 AI 应用的定义和数据运营过程中。

Dify 由一个专业的全职团队和社区共同打造。你可以基于任何模型自部署各类 GenAI 应用,在灵活和安全的基础上,同时保持对数据的完全控制。

由于 Dify 内置了构建 LLM 应用所需的关键技术栈,包括对数百个模型的支持、直观的 Prompt 编排界面、高质量的 RAG 引擎、稳健的 Agent 框架、灵活的流程编排,并同时提供了一套易用的界面和 API。这为开发者节省了许多重复造轮子的时间,使其可以专注在创新和业务需求上。

截止本文创作时至,Dify 在 Github 有超过 4.4 万颗 Star。且看 Dify CEO 的官方介绍:

我们的社区用户对 Dify 的产品评价可以归结为简单、克制、迭代迅速。
——路宇,Dify.AI CEO

Dify 架构及核心组件

Dify 提供了三种使用模式:商业化版本 Dify Cloud(SaaS 模式),自建 Dify 社区版(免费),自建企业版。本文主要介绍如何基于 Amazon EKS 自建高可用 Dify 社区版。

下图为基于 Amazon EKS 部署 Dify 的架构。

Dify on EKS 架构图

Dify 包括 3 个业务服务组件 api / worker / web (Frontend),以及 6 个基础组件 vector db / db / redis / nginx / ssrf_proxy / sandbox。为了实现生产级高可用性,我们使用多个 Amazon 托管服务用作基础组件,包括 Amazon S3,ElastiCache for Redis,Aurora PostgreSQL,ALB 等。Dify 支持多种向量数据库产品,包括 OpenSearch,Zilliz/Milvus,Qrdrant,Weaviate 等,本文使用部署在 EKS 中的 Milvus。

Dify on EKS 部署

一、前置条件

Dify 有几个关键组件需要提前部署,包括:

本方案中的所有组件都支持使用 Graviton3 芯片的 EC2 实例,在部署时选择 Graviton3 实例可以获得更高的性价比。在 Milvus on Graviton3 博客中,测试结果显示 Graviton3 可以实现高达 31% 的性价比提升。

二、Dify on EKS 部署步骤

Dify 官方支持 Docker Composer,以及源码部署的方式:https://docs.dify.ai/v/zh-hans/getting-started/install-self-hosted,但是这两种方式未能照顾到高可用环境,更多是用于开发和测试环境的快速部署。

作为生产高可用环境,推荐以 Helm Charts 的方式部署在 EKS 上。本文使用该 Chart 进行部署:https://github.com/douban/charts/tree/master/charts/dify。但在部署的时候需要做一些调整,比如使用 S3 替代 minio 用作对象存储,使用 AWS Application Load Balancer 用作 EKS Ingress,使用 Aurora PostgreSQL 替代内置 PostgreSQL 等,使用 ElastiCache for Redis 代替内置 Redis。

部署中要使用到 AWS AK/SK、数据库的账号密码等敏感信息,我们使用 K8S Secret 进行存储,并推荐使用 Amazon KMS 进行加密:https://docs.thinkwithwp.com/eks/latest/userguide/enable-kms.html

请注意,进行以下步骤前,请确保已经完成前置条件。

  1. 安装 Helm,参考 https://helm.sh/docs/intro/install/
  2. 添加 Helm repo
    helm repo add douban https://douban.github.io/charts/
    helm update
    
  3. 确保 kubectl 可以连接到您的 EKS 集群。使用如下命令创建 Secret 对象,用于存储 AWS AK/SK 及 PostgreSQL,Milvus 和 Redis 的密码。这些密码需要转换为 base64 编码,可以使用 echo -n "<password>" | base64 命令快速获取 base64 编码。SECRET_KEY 是 Dify 用来安全地签名会话 cookie 并加密数据库中的敏感信息的密钥,可以使用 openssl rand -base64 42 命令生成强密钥。MILVUS_PASSWORD 可以在 Milvus 向量数据库中进行设置,默认为 Milvus。ElastiCache for Redis 除了用作缓存,也被用作 Celery 的消息队列,CELERY_BROKER_URL 就是用来配置 Celery 的 Broker,格式为 redis://<redis_username>:<redis_password>@<redis_host>:<redis_port>/<redis_database>,因为这个 URL 中涉及到 Redis 的密码,所以我们将其放在 Secret 中。
    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: Secret
    metadata:
      name: dify
    type: Opaque
    data:
      SECRET_KEY: <Replace your SECRET KEY here>
      S3_ACCESS_KEY: <Replace your S3 ACCESS KEY here>
      S3_SECRET_KEY: <Replace your S3 SECRET KEY here>
      DB_PASSWORD: <Replace your PostgreSQL PASSWORD here>
      MILVUS_PASSWORD: <Replace your MILVUS PASSWORD here>
      REDIS_PASSWORD: <Replace your REDIS PASSWORD here>
      CELERY_BROKER_URL: <Replace your CELERY BROKER URL here>
    EOF
    
  4. 创建 values.yaml。需要替换 <>中的内容,包括 host, image tag, vector store, MILVUS_HOSTS3_ENDPOINT, S3_REGION, S3_BUCKET_NAME, DB_USERNAME, DB_HOST, REDIS_HOSTingress 等。我们禁用了 Dify 自带的对象存储 minio, Redis 和 PostgreSQL,使用 S3, ElastiCache for Redis 和 Amazon Aurora 替代。
  • host: ALB 对应的自定义域名,建议开启 TLS,host 需要保持和 DNS 提供商注册的自定义域名一致。
  • image tag:查看 https://github.com/langgenius/dify/releases,建议选择最新版本的 Dify。
  • vector storeMILVUS_HOST:向量数据库配置。可选的配置有如下选项,本次案例使用的是 Milvus。
    • weaviate
    • qdrant
    • milvus
    • zilliz,与 milvus 一致
    • OpenSearch
    • tidb_vector
  • S3_ENDPOINT, S3_REGIONS3_BUCKET_NAME:修改为您自己的 S3 endpoint, region, bucket name。
  • DB_HOST, DB_USERNAMEDB_DATABASE:修改为您自己的 PostgreSQL 数据库的信息,本例子中使用的是 Aurora PostgreSQL。
  • REDIS_HOSTREDIS_USERNAME:修改为您自己的 ElastiCache for Redis 的信息,建议开启密码认证,同时设置 REDIS_USE_SSLtrue
  • ingress:您的 EKS 的 Ingress 配置,我们使用 AWS Load Balancer Controller 来创建 Ingress。强烈建议开启 HTTPS,并进行对应的设置,详见:https://docs.thinkwithwp.com/eks/latest/userguide/aws-load-balancer-controller.html。开启 HTTPS 同时需要设置 enableTLStrue,并将 alb.ingress.kubernetes.io/certificate-arn 替换为域名的 ACM 证书 ARN。请确保您的 EKS Ingress 是正常工作的。
    global:
      host: "<your domain name>"
      enableTLS: true
    
      image:
        # Set to the latest version of dify
        # Check the version here: https://github.com/langgenius/dify/releases
        # If not set, Using the default value in Chart.yaml
        tag: "0.7.2"
      extraBackendEnvs:
      # The log output level. Default is INFO. For production environments, it's recommended to set this to ERROR
      - name: LOG_LEVEL
        value: "ERROR"
      - name: SECRET_KEY
        valueFrom:
          secretKeyRef:
            name: dify
            key: SECRET_KEY
      # milvus
      - name: VECTOR_STORE
        value: "milvus"
      - name: MILVUS_HOST
        value: "<your Milvus endpoint>"
      - name: MILVUS_PORT
        value: "19530"
      - name: MILVUS_USER
        value: "root"
      - name: MILVUS_PASSWORD
        valueFrom:
          secretKeyRef:
            name: dify
            key: MILVUS_PASSWORD
      - name: MILVUS_SECURE
        value: "false"
      # External S3 bucket
      - name: S3_ENDPOINT
        value: "https://s3.<your region code>.amazonaws.com"
      - name: S3_REGION
        value: "<your region code>"
      - name: S3_BUCKET_NAME
        value: "<your bucket name>"
      - name: S3_ACCESS_KEY
        valueFrom:
          secretKeyRef:
            name: dify
            key: S3_ACCESS_KEY
      - name: S3_SECRET_KEY
        valueFrom:
          secretKeyRef:
            name: dify
            key: S3_SECRET_KEY
      # External postgresql
      - name: DB_USERNAME
        value: "<your postgres username>"
      - name: DB_PASSWORD
        valueFrom:
          secretKeyRef:
            name: dify
            key: DB_PASSWORD
      - name: DB_HOST
        value: "<your postgres endpoint>"
      - name: DB_PORT
        value: "5432"
      - name: DB_DATABASE
        value: "<your postgres database>"
      # External Redis
      - name: REDIS_HOST
        value: "<your redis endpoint>"
      - name: REDIS_PORT
        value: "6379"
      - name: REDIS_DB
        value: "0"
      - name: REDIS_USE_SSL
        value: "true"
      - name: REDIS_USERNAME
        value: "<your redis username>"
      # it is adviced to use secret to manage you sensitive info including password
      - name: REDIS_PASSWORD
        valueFrom:
         secretKeyRef:
           name: dify
           key: REDIS_PASSWORD
      # CELERY_BROKER_URL, format: "redis://<redis_username>:<redis_password>@<redis_host>:<redis_port>/<redis_database>"
      - name: CELERY_BROKER_URL
        valueFrom:
          secretKeyRef:
            name: dify
            key: CELERY_BROKER_URL
      - name: BROKER_USE_SSL
        value: "true"
    
    ingress:
      enabled: true
      className: "alb"
      annotations:
        kubernetes.io/ingress.class: "alb" # Annotation: set ALB ingress type
        alb.ingress.kubernetes.io/scheme: "internet-facing" #Places the load balancer on public subnets
        alb.ingress.kubernetes.io/target-type: "ip" #The Pod IPs should be used as the target IPs (rather than the node IPs)
        alb.ingress.kubernetes.io/certificate-arn: "<your domain URL certificate ARN>"
        alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
        alb.ingress.kubernetes.io/ssl-redirect: '443'
    
    minio:
      embedded: false
    
    postgresql:
      embedded: false
    
    redis:
      embedded: false
    
  1. 执行如下命令进行安装。
    helm install dify douban/dify -f values.yaml
  2. Dify 的核心服务如 api, worker, frontend, sandbox 默认配置为一个副本,为了提高高可性,需要增加副本数量。使用以下配置创建 new_values.yaml,并运行 helm upgrade dify douban/dify --reuse-values -f new_values.yaml 命令进行更新。
    frontend:
      replicaCount: 2
    
    api:
      replicaCount: 2
    
    worker:
      replicaCount: 2
    
    sandbox:
      replicaCount: 2
    
  1. 验证安装。使用 kubectl get ingress 命令获取 endpoint,如果能正确获取,浏览器打开 HOSTS 即可访问。
    NAME   CLASS   HOSTS                  ADDRESS                                 PORTS   AGE
    dify   alb     dify.yourcompany.com   dify-xxxx.us-west-2.elb.amazonaws.com   80, 443 10d
    

Dify 登陆界面,部署成功

总结

本文基于 Amazon EKS,自建部署了 Dify 社区版,使用 Amazon S3,Aurora Postgre SQL,ElastiCache for Redis 等替代了 Dify 内置对象存储,PostgreSQL 和 Redis,并且增加了 Dify 核心服务的副本数量,实现了生产级别高可用。

关于 Dify 的使用,请参考亚马逊云科技博客 https://thinkwithwp.com/cn/blogs/china/get-started-with-generative-ai-by-integrating-bedrock-claude3-with-dify/。鼓励感兴趣的读者亲自动手尝试。

参考资料

本篇作者

吴万涛

亚马逊云科技解决方案架构师,负责亚马逊云科技云上解决方案架构设计和咨询,十几年 IT 行业从业经历,在网络、应用架构、容器等领域有丰富的经验。

白雪尧

亚马逊云科技解决方案架构师,毕业于瑞典皇家理工学院,曾任职于 SAP、微软的开发、技术支持部门。对现代化应用架构、数据分析有丰富经验,对 HPC/半导体设计行业有行业经验。