发布于 2026-01-05 5 阅读
0

如何使用 LocalStack 在本地模拟 AWS 呢?🤷‍♂️ 算了吧。

如何使用 LocalStack 在本地模拟 AWS

🤷‍♂️ 不。

如果你和我一样,你会尽可能避免登录 AWS 控制台。你是否已为 IAM 根用户设置了双因素身份验证,并正确配置了 S3 存储桶的 CORS 和 ACL 设置?

🤷‍♂️ 不。

我也倾向于让本地开发环境尽可能接近生产环境。此外,我一直在寻找填满我那小硬盘空间的新方法。要说实现上述所有目标的最佳途径,我想不出比在我的电脑里部署一堆 S3 服务器更好的办法了。

本教程将介绍如何在 Node 应用中配置LocalStack。LocalStack允许你在计算机上模拟多种 AWS 服务,但本示例中我们仅使用 S3。此外,LocalStack 并非 Node 专属,因此即使你不使用 Node,本教程的大部分内容仍然适用。本教程还会简要介绍 Docker——如果你不了解 Docker 的工作原理,也不用担心,我也不了解。

您可以查看已完成代码的演示仓库。

这种方法的一些优点包括:

  • 您可以离线工作
  • 你不需要团队成员共享的“开发”存储桶。
  • 您可以轻松地擦拭和更换本地水桶。
  • 您无需担心支付 AWS 使用费用。
  • 您无需登录 AWS 😛

初始设置

首先,我们需要安装一些东西。

  1. 如果尚未安装Docker ,请安装它。
  2. 安装AWS CLI。虽然我们不会使用“真正的”AWS,但我们会用它来与本地 Docker 容器通信。
  3. 安装完 AWS CLI 后,运行aws configure命令创建凭证。即使我们是在与“虚拟”本地服务通信,仍然需要凭证。您可以输入真实凭证(如此处所述),也可以输入虚拟凭证。Localstack 要求提供这些信息,但实际上并不验证它们。感谢@alexiswilke在评论中指出我漏掉了这一步!
  4. 创建几个文件。为你的项目创建一个新目录,并在该目录中:touch index.js docker-compose.yml .env && mkdir .localstack
  5. 将图像添加到项目目录并将其重命名为test-upload.jpg
  6. npm init首先,要设置 package.json 文件,然后……npm install aws-sdk dotenv

Docker

(免责声明:我不是 Docker 专家。如果各位有任何改进建议或想更好地解释本文内容,请在评论区留言!)

Docker 配置

你可以直接从命令行运行 Localstack,但我喜欢用 Docker,因为它让我感觉自己很厉害。而且用 Docker 也很好,因为你不用担心在系统上安装 Localstack。我更喜欢用 docker-compose 来配置。以下是配置:

docker-compose.yml



version: '3.2'
services:
  localstack:
    image: localstack/localstack:latest
    container_name: localstack_demo
    ports:
      - '4563-4599:4563-4599'
      - '8055:8080'
    environment:
      - SERVICES=s3
      - DEBUG=1
      - DATA_DIR=/tmp/localstack/data
    volumes:
      - './.localstack:/tmp/localstack'
      - '/var/run/docker.sock:/var/run/docker.sock'


Enter fullscreen mode Exit fullscreen mode

(2019年8月10日更新:LocalStack现在支持更多端口,上面的yaml文件已更新以反映这一点。感谢@arqez在评论中提到这一点。)

让我们来分析一下这些句子:

image: localstack/localstack:latest

使用Dockerhub 上的最新Localstack 镜像

container_name: localstack_demo

这样就为我们的容器赋予了一个特定的名称,我们可以在后面的 CLI 中引用它。

ports: '4563-4599:4563-4599''8055:8080'

当你的 Docker 容器启动时,它会打开几个端口。左侧的数字你的本地端口绑定到容器内的端口,也就是右侧localhost的数字。大多数情况下,这两个数字可以相同,例如10 ...8080:8080localhost:80808055:8080http://localhost:80558080

这条命令的'4563-4584:4563-4584'作用相同,但它绑定的是一系列端口。Localstack 使用这些特定的端口号作为各种 API 的端点。稍后我们会详细介绍。

environment

这些是提供给容器的环境变量。LocalStack 将使用这些变量在内部进行一些设置:

  • SERVICES=s3您可以定义一个要模拟的 AWS 服务列表。在本例中,我们只使用了 S3,但您也可以添加其他 API,例如SERVICES=s3,lambda……更多相关信息请参阅 Localstack 文档。
  • DEBUG=1:🧻 把所有日志都给我看看!
  • DATA_DIR=/tmp/localstack/data这是 Localstack内部保存数据的目录。更多内容将在下文中介绍:

volumes

'./.localstack:/tmp/localstack'

还记得大约两秒前设置的那个DATA_DIR吗?就像我们之前配置端口时使用的语法一样,这允许你的容器访问你硬盘的一部分。左边是你电脑的目录,右边是容器所在的目录。/tmp/localstack/datalocalhost:container

在这里,我们告诉容器使用我们的.localstack目录作为其/tmp/localstack. 这就像一个符号链接,或者一个神奇的传送门之类的东西。

在我们的例子中,这确保了容器创建的任何数据在容器重启后仍然存在。请注意,该位置会/tmp被频繁清除,因此不适合存储此类数据。如果您想将其放置在更安全的位置,请另行查找。

  • '/var/run/docker.sock:/var/run/docker.sock'

启动我们的集装箱

现在我们的容器docker-compose.yml状态良好,我们可以启动它了:docker-compose up -d

为了确认它是否正常工作,我们可以访问http://localhost:8055查看 Localstack 的 Web 用户界面。目前它看起来几乎是空白的:

空的 Localstack 用户界面

同样,我们的 S3 端点http://localhost:4572将显示一些基本的 AWS 信息:

空的 S3 桶

(如果您没有看到类似内容,请检查您的 Docker 容器日志)

使用 Localstack

AWS 现在已经装进我们的电脑里了。你可能已经感觉自己有点像世界上最富有的人了。(如果没有,别担心,继续往下看😛)

在开始上传文件之前,我们需要创建并配置一个存储桶。我们将使用之前安装的 AWS CLI 来完成此操作,并使用--endpoint-url相应的标志来与 LocalStack 通信。

  1. 创建存储桶:aws --endpoint-url=http://localhost:4572 s3 mb s3://demo-bucket
  2. 为存储桶附加访问控制列表 (ACL),使其可读:aws --endpoint-url=http://localhost:4572 s3api put-bucket-acl --bucket demo-bucket --acl public-read

现在,当我们访问 Web 用户界面时,我们将看到我们的存储桶:

Localstack UI 与 S3 存储桶

如果你volumes在 Docker 设置中使用了它,让我们暂停一下,看看里面发生了什么./.localstack/data

Localstack S3 JSON

在这里,我们可以看到 Localstack 将所有 API 调用记录在这个 JSON 文件中。容器重启后,它会重新应用这些调用——这就是我们如何在重启之间保留数据的原因。一旦开始上传,我们不会在这个目录中看到新文件出现。相反,我们的上传操作会以原始数据的形式记录在这个文件中。(如果您想与他人共享容器状态,可以将此文件包含在您的代码仓库中——但根据您上传的数据量,它会变得非常大。)

如果您希望稍后能够“恢复”您的存储桶,可以备份此文件。准备恢复时,只需删除已更新的s3_api_calls.json文件,将其替换为备份文件,然后重启容器即可。

通过我们的应用程序上传

网上有很多关于S3上传的教程,所以本节不会深入讲解。我们只会编写一个简单的upload函数,并尝试上传几次图片。

将以下内容复制到他们的文件中:

.env,我们的环境变量



AWS_ACCESS_KEY_ID='123'
AWS_SECRET_KEY='xyz'
AWS_BUCKET_NAME='demo-bucket'


Enter fullscreen mode Exit fullscreen mode

注意:只要您的 AWS 密钥和密钥不为空,它们是什么并不重要。

aws.js,是我们上传功能的模块



const AWS = require('aws-sdk')
require('dotenv').config()

const credentials = {
   accessKeyId: process.env.AWS_ACCESS_KEY_ID,
   secretAccessKey: process.env.AWS_SECRET_KEY,
}

const useLocal = process.env.NODE_ENV !== 'production'

const bucketName = process.env.AWS_BUCKET_NAME

const s3client = new AWS.S3({
   credentials,
   /**
    * When working locally, we'll use the Localstack endpoints. This is the one for S3.
    * A full list of endpoints for each service can be found in the Localstack docs.
    */
   endpoint: useLocal ? 'http://localhost:4572' : undefined,
   /**
     * Including this option gets localstack to more closely match the defaults for
     * live S3. If you omit this, you will need to add the bucketName to the `Key`
     * property in the upload function below.
     *
     * see: https://github.com/localstack/localstack/issues/1180
     */
   s3ForcePathStyle: true,
})


const uploadFile = async (data, fileName) =>
   new Promise((resolve) => {
      s3client.upload(
         {
            Bucket: bucketName,
            Key: fileName,
            Body: data,
         },
         (err, response) => {
            if (err) throw err
            resolve(response)
         },
      )
   })

module.exports = uploadFile


Enter fullscreen mode Exit fullscreen mode

感谢@mcmule提供的关于上述选项的提示s3ForcePathStyle。如果您遇到ECONNREFUSED错误,请查看他的评论。

test-upload.js实现了上传功能



const fs = require('fs')
const path = require('path')
const uploadFile = require('./aws')

const testUpload = () => {
   const filePath = path.resolve(__dirname, 'test-image.jpg')
   const fileStream = fs.createReadStream(filePath)
   const now = new Date()
   const fileName = `test-image-${now.toISOString()}.jpg`
   uploadFile(fileStream, fileName).then((response) => {
      console.log(":)")
      console.log(response)
   }).catch((err) => {
      console.log(":|")
      console.log(err)
   })
}

testUpload()


Enter fullscreen mode Exit fullscreen mode

testUpload()函数获取文件内容,根据当前时间为其分配一个唯一名称,然后上传文件。我们来试一试:

node test-upload.js

测试上传

复制响应属性中的 URLLocation并粘贴到浏览器中。浏览器会立即下载图片。如果想在浏览器中查看图片,可以使用类似 JS Bin 的工具:

我爱我的狗

然后,如果你再看一遍.localstack/data/s3_api_calls.json,你会发现它里面充满了图像的二进制数据:

图像二进制数据

最后,我们重启容器以确保上传功能正常。为此,请运行命令docker restart localstack_demo。重启完成后,运行命令docker logs -f localstack_demo。这将显示容器的日志(使用-f标志可以“跟踪”日志)。

初始化 Localstack 后,它将重新应用在以下位置找到的 API 调用s3_api_calls.json

Localstack 日志

重新加载浏览器后,您应该会看到图片像之前一样显示出来。

🎉 就是这样!感谢观看。这是我的第一个教程,我很想知道你们的想法。如果有什么问题或建议,请在评论区留言!

文章来源:https://dev.to/goodidea/how-to-fake-aws-locally-with-localstack-27me