使用LocalStack和Docker开发和测试AWS云应用程序

在现代应用开发中,在将云应用程序部署到生产环境之前,在本地进行测试可以帮助您更快、更有信心地发布。这种方法涉及在本地模拟服务,早期识别和修复问题,并快速迭代,而不会产生成本或面临完整云环境的复杂性。像 LocalStack 这样的工具在这个过程中变得非常宝贵,使您能够模拟AWS服务并将应用程序容器化,以创建一致、隔离的测试环境。

在本指南中,您将学习如何:

  • 使用 Docker 启动一个 LocalStack 容器
  • 从非容器化应用程序连接到LocalStack
  • 从容器化应用程序连接到LocalStack

什么是LocalStack?

LocalStack 是一个云服务模拟器,它在您的笔记本电脑上的单个容器中运行。它提供了一种强大、灵活且经济高效的方式来本地测试和开发基于 AWS 的应用程序。

为什么使用 LocalStack?

在本地模拟AWS服务允许您测试您的应用程序如何与S3、Lambda和DynamoDB等服务交互,而无需连接到真实的AWS云。您可以快速进行开发迭代,避免在此阶段部署到云端的成本和复杂性。

通过在本地模拟这些服务的行为,LocalStack 实现了更快的反馈循环。您的应用程序可以与外部 API 交互,但所有操作都在本地运行,无需处理云配置或网络延迟。

这使得验证集成和测试基于云的场景变得更加容易,而无需在实时环境中配置IAM角色或策略。您可以在本地模拟复杂的云架构,并在准备就绪时将更改推送到AWS。

使用 Docker 运行 LocalStack

LocalStack的官方Docker镜像提供了一种方便的方式在您的开发机器上运行LocalStack。它是免费使用的,不需要任何API密钥即可运行。您甚至可以使用LocalStack Docker扩展来使用带有图形用户界面的LocalStack。

先决条件

要遵循本操作指南,需要满足以下先决条件:

启动 LocalStack

通过以下步骤启动LocalStack的快速演示:

  1. 首先 克隆一个示例应用程序。打开终端并运行以下命令:

    $ git clone https://github.com/dockersamples/todo-list-localstack-docker
    $ cd todo-list-localstack-docker
    
  2. 启动 LocalStack

    运行以下命令以启动LocalStack。

    $ docker compose -f compose-native.yml up -d
    

    此Compose文件还包括所需Mongo数据库的规范。您可以通过访问Docker Desktop仪表板来验证服务是否已启动并运行。

    Diagram showing the LocalStack and Mongo container up and running on Docker Desktop
  3. 通过选择容器并检查日志来验证LocalStack是否已启动并运行。

    Diagram showing the logs of LocalStack container
  4. 创建一个本地Amazon S3存储桶

    当你使用LocalStack创建一个本地S3存储桶时,你实际上是在模拟在AWS上创建一个S3存储桶。这让你能够测试和开发与S3交互的应用程序,而无需实际的AWS账户。

    要创建本地Amazon S3存储桶,您需要在系统上安装awscli-local包。这个包提供了awslocal命令,它是AWS命令行界面的一个轻量级封装,用于与LocalStack一起使用。它允许您在本地机器上针对模拟环境进行测试和开发,而无需访问真实的AWS服务。您可以了解更多关于此实用程序的信息 这里

    $ pip install awscli-local
    

    在LocalStack环境中使用以下命令创建一个新的S3存储桶:

    $ awslocal s3 mb s3://mysamplebucket
    

    命令 s3 mb s3://mysamplebucket 告诉 AWS CLI 创建一个新的 S3 存储桶(mb 代表 make bucket),命名为 mysamplebucket

    您可以通过在Docker Desktop仪表板上选择LocalStack容器并查看日志来验证S3存储桶是否已创建。日志表明您的LocalStack环境已正确配置,您现在可以使用mysamplebucket来存储和检索对象。

    Diagram showing the logs of LocalStack that highlights the S3 bucket being created successfully

在开发中使用 LocalStack

现在你已经熟悉了LocalStack,是时候看看它的实际应用了。在这个演示中,你将使用一个包含React前端和Node.js后端的示例应用程序。这个应用程序栈使用了以下组件:

  • React: 一个用户友好的前端,用于访问待办事项列表应用程序
  • 节点:负责处理HTTP请求的后端。
  • MongoDB: 一个用于存储所有待办事项列表数据的数据库
  • LocalStack: 模拟Amazon S3服务并存储和检索图像。
Diagram showing the tech stack of the sample todo-list application that includes LocalStack, frontend and backend services

从非容器化应用程序连接到LocalStack

现在是时候将您的应用程序连接到LocalStack了。位于backend/目录中的index.js文件是后端应用程序的主要入口点。

代码与LocalStack的S3服务交互,该服务通过由S3_ENDPOINT_URL环境变量定义的端点访问,通常在本地开发中设置为http://localhost:4556

来自AWS SDK的S3Client被配置为使用这个LocalStack端点,以及同样来自环境变量的测试凭证(AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY)。这种设置使应用程序能够在本地模拟的S3服务上执行操作,就像它与真实的AWS S3交互一样,使代码在不同的环境中具有灵活性。

代码使用multermulter-s3来处理文件上传。当用户通过/upload路由上传图片时,文件直接存储在由LocalStack模拟的S3存储桶中。存储桶名称从环境变量S3_BUCKET_NAME中获取。每个上传的文件都会通过在原始文件名后附加当前时间戳来赋予一个唯一的名称。然后,路由返回本地S3服务中上传文件的URL,使其可以像托管在真实的AWS S3存储桶上一样访问。

让我们看看它的实际效果。首先启动Node.js后端服务。

  1. 切换到 backend/ 目录

    $ cd backend/
    
  2. 安装所需的依赖项:

    $ npm install
    
  3. 设置AWS环境变量

    位于backend/目录中的.env文件已经包含了LocalStack用于模拟AWS服务的占位符凭据和配置值。AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY是占位符凭据,而S3_BUCKET_NAMES3_ENDPOINT_URL是配置设置。由于这些值已经为LocalStack正确设置,因此不需要进行任何更改。

    提示

    鉴于您在Docker容器中运行Mongo,而后端Node应用程序在主机上本地运行,请确保在您的.env文件中设置了MONGODB_URI=mongodb://localhost:27017/todos

    MONGODB_URI=mongodb://localhost:27017/todos
    AWS_ACCESS_KEY_ID=test
    AWS_SECRET_ACCESS_KEY=test
    S3_BUCKET_NAME=mysamplebucket
    S3_ENDPOINT_URL=http://localhost:4566
    AWS_REGION=us-east-1

    虽然AWS SDK通常可能使用以AWS_开头的环境变量,但这个特定的应用程序在index.js文件中(位于backend/目录下)直接引用了以下S3_*变量来配置S3Client。

    const s3 = new S3Client({
      endpoint: process.env.S3_ENDPOINT_URL, // Use the provided endpoint or fallback to defaults
      credentials: {
        accessKeyId: process.env.AWS_ACCESS_KEY_ID || 'default_access_key', // Default values for development
        secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || 'default_secret_key',  
      },
    });
  4. 启动后端服务器:

    $ node index.js
    

    您将看到后端服务已在端口5000成功启动的消息。

启动前端服务

要启动前端服务,请打开一个新的终端并按照以下步骤操作:

  1. 导航到frontend目录:

    $ cd frontend
    
  2. 安装所需的依赖项

    $ npm install
    
  3. 启动前端服务

    $ npm run dev
    

    到目前为止,你应该看到以下消息:

    VITE v5.4.2  ready in 110 ms
    ➜  Local: http://localhost:5173/
    ➜  Network: use --host to expose
    ➜  press h + enter to show help
    

    您现在可以通过 http://localhost:5173访问该应用程序。继续,通过选择图像文件并点击上传按钮来上传图像。

    Diagram showing a working todo-list application

    您可以通过检查LocalStack容器日志来验证图像是否已上传到S3存储桶:

    Diagram showing the logs of the LocalStack that highlights image uploaded to the emulated S3 bucket

    200状态码表示putObject操作(涉及将对象上传到S3存储桶)在LocalStack环境中成功执行。LocalStack记录此条目以提供对正在执行的操作的可见性。它有助于调试并确认您的应用程序与模拟的AWS服务正确交互。

    由于LocalStack旨在本地模拟AWS服务,此日志条目显示您的应用程序在本地沙箱环境中执行云操作时按预期运行。

从容器化的Node应用连接到LocalStack

现在你已经学会了如何将非容器化的Node.js应用程序连接到LocalStack,是时候探索在容器化环境中运行完整应用程序堆栈所需的更改了。为此,你将创建一个Compose文件,指定所有所需的服务——前端、后端、数据库和LocalStack。

  1. 检查Docker Compose文件。

    以下Docker Compose文件定义了四个服务:backendfrontendmongodblocalstackbackendfrontend服务是您的Node.js应用程序,而mongodb提供数据库,localstack模拟了像S3这样的AWS服务。

    backend 服务依赖于 localstackmongodb 服务,确保它们在启动之前正在运行。它还使用 .env 文件来设置环境变量。前端服务依赖于后端服务并设置 API URL。mongodb 服务使用持久卷进行数据存储,localstack 配置为运行 S3 服务。此设置允许您使用类似 AWS 的服务在本地开发和测试您的应用程序。

    services:
      backend:
        build:
          context: ./backend
          dockerfile: Dockerfile
        ports:
          - 5000:5000
        depends_on:
          - localstack
          - mongodb
        env_file:
          - backend/.env
    
      frontend:
        build:
          context: ./frontend
          dockerfile: Dockerfile
        ports:
          - 5173:5173
        depends_on:
          - backend
        environment:
          - REACT_APP_API_URL=http://backend:5000/api
    
      mongodb:
        image: mongo
        container_name: mongodb
        volumes:
          - mongodbdata:/data/db
        ports:
          - 27017:27017
    
      localstack:
        image: localstack/localstack
        container_name: localstack
        ports:
          - 4566:4566
        environment:
          - SERVICES=s3
          - GATEWAY_LISTEN=0.0.0.0:4566
        volumes:
          - ./localstack:/docker-entrypoint-initaws.d"
    
    volumes:
      mongodbdata:
  2. 修改backend/目录下的.env文件,使资源使用内部网络名称连接。

    提示

    根据之前的Compose文件,应用程序将使用主机名localstack连接到LocalStack,而Mongo将使用主机名mongodb进行连接。

    MONGODB_URI=mongodb://mongodb:27017/todos
    AWS_ACCESS_KEY_ID=test
    AWS_SECRET_ACCESS_KEY=test
    S3_BUCKET_NAME=mysamplebucket
    S3_ENDPOINT_URL=http://localstack:4566
    AWS_REGION=us-east-1
  3. 停止正在运行的服务

    确保您通过按终端中的“Ctrl+C”停止上一步中的Node前端和后端服务。此外,您还需要通过在Docker Desktop仪表板中选择它们并选择“删除”按钮来停止LocalStack和Mongo容器。

  4. 通过在克隆的项目目录的根目录下执行以下命令来启动应用程序堆栈:

    $ docker compose -f compose.yml up -d --build
    

    片刻之后,应用程序将启动并运行。

  5. 手动创建一个S3存储桶

    AWS S3 存储桶不是由 Compose 文件预先创建的。运行以下命令以在 LocalStack 环境中创建一个新的存储桶:

    $ awslocal s3 mb s3://mysamplebucket
    

    该命令创建了一个名为 mysamplebucket 的 S3 存储桶。

    打开 http://localhost:5173 以访问完整的待办事项应用程序并开始将图像上传到Amazon S3存储桶。

    提示

    为了优化性能并减少开发期间的上传时间,请考虑上传较小的图像文件。较大的图像可能需要更长时间处理,并可能影响应用程序的整体响应性。

回顾

本指南引导您使用LocalStack和Docker设置本地开发环境。您已经学会了如何在本地测试基于AWS的应用程序,从而降低成本并提高开发工作流程的效率。