问题描述
在 Create an AWS S3 Website in Under 5 Minutes YT video 和 Host a Static Website on Amazon S3 Pulumi tutorial 中有很好的解释如何使用 Pulumi 在 S3 上创建网站托管。
在示例代码中使用了 Pulumi 的 Bucket 和 BucketObject。第一个创建一个 S3 存储桶,后者创建对象,这些对象主要是用于公共访问的 index.html
,如下所示:
const aws = require("@pulumi/aws");
const pulumi = require("@pulumi/pulumi");
const mime = require("mime");
// Create an S3 bucket
let siteBucket = new aws.s3.Bucket("s3-website-bucket");
let siteDir = "www"; // directory for content files
// For each file in the directory,create an S3 object stored in `siteBucket`
for (let item of require("fs").readdirsync(siteDir)) {
let filePath = require("path").join(siteDir,item);
let object = new aws.s3.Bucketobject(item,{
bucket: siteBucket,source: new pulumi.asset.FileAsset(filePath),// use FileAsset to point to a file
contentType: mime.getType(filePath) || undefined,// set the MIME type of the file
});
}
exports.bucketName = siteBucket.bucket; // create a stack export for bucket name
现在使用基于 Vue.js / Nuxt.js 的应用程序,我需要上传多个生成的文件,这些文件位于我的项目根目录的 dist
目录中。它们由 npm run build
生成并生成以下文件:
$ find dist
dist
dist/favicon.ico
dist/index.html
dist/.nojekyll
dist/200.html
dist/_nuxt
dist/_nuxt/LICENSES
dist/_nuxt/static
dist/_nuxt/static/1619685747
dist/_nuxt/static/1619685747/manifest.js
dist/_nuxt/static/1619685747/payload.js
dist/_nuxt/f3a11f3.js
dist/_nuxt/f179782.js
dist/_nuxt/fonts
dist/_nuxt/fonts/element-icons.4520188.ttf
dist/_nuxt/fonts/element-icons.313f7da.woff
dist/_nuxt/c25b1a7.js
dist/_nuxt/84fe6d0.js
dist/_nuxt/a93ae32.js
dist/_nuxt/7b77d06.js
我的问题是这些文件还包含嵌套在子目录中的文件,子目录本身也可以是子目录 - 例如dist/_nuxt/fonts/element-icons.4520188.ttf
。教程中提供的方法不评估子目录,我不知道如何使用 Pulumi/TypeScript。
解决方法
我继续采用该方法并尝试构建递归 TypeScript 函数,该函数根据教程推荐的 Pulumi 的 BucketObject 创建文件或目录。
这让我陷入了复杂的困境!我需要使用 BucketObject
创建目录,使用 "/"
参数 (see this answer) 中附加的 key
可以实现。只是为了记录,它的功能看起来像这样:
function createS3BucketFolder(dirName: string) {
new aws.s3.BucketObject(dirName,{
bucket: nuxtBucket,acl: "public-read",key: dirName + "/",// an appended '/' will create a S3 Bucket prefix (see https://stackoverflow.com/a/57479653/4964553)
contentType: "application/x-directory" // this content type is also needed for the S3 Bucket prefix
// no source needed here!
})
}
但这只是使用 TypeScript 递归遍历目录所需的大量代码中的一小部分(另请参阅 this huge amount of so answers on the topic,从同步版本到疯狂的 Node.js 11+ 异步解决方案)。我最终得到了大约 40-50 行代码,仅用于将静态站点生成的文件递归添加到 S3 - 感觉不太好,没有对此进行测试(我真的不明白,为什么Pulumi 不会support that use case somehow like Terraform)。
最后,我偶然发现了关于 Secure Static Website Using Amazon S3,CloudFront,Route53,and Certificate Manager 的 Pulumi 教程,其中有 a special paragraph about deployment speed 并附有一段有趣的引用:
此示例为从提供的每个文件创建一个 aws.S3.BucketObject 网站。在部署大型网站时,这可能会导致很长时间 检查每个单独的文件是否有任何更改时更新。 可能 更有效地不使用 Pulumi 和和 而只是使用 AWS CLI 将本地文件与 S3 存储桶同步 直接。
TLDR:对于非 hello world 用例,Pulumi 文档告诉我们不要使用 Pulumi 将文件上传到 S3,而是使用 AWS CLI!所以我重新编写了我的代码,只使用 Pulumi 创建 S3 Bucket,如下所示:
import * as aws from "@pulumi/aws";
// Create an AWS resource (S3 Bucket)
const nuxtBucket = new aws.s3.Bucket("microservice-ui-nuxt-js-hosting-bucket",{
acl: "public-read",website: {
indexDocument: "index.html",}
});
// Export the name of the bucket
export const bucketName = nuxtBucket.id;
这将创建一个启用静态站点托管的 S3 存储桶,并通过 Pulumi 访问 public-read
。现在使用 AWS CLI,我们可以使用以下命令优雅地将文件复制/同步到存储桶:
aws s3 sync ../dist/ s3://$(pulumi stack output bucketName) --acl public-read
使用 $(pulumi stack output bucketName)
我们只需获取由 Pulumi 创建的 S3 存储桶名称。请注意最后的 --acl public-read
参数,因为您必须对 S3 中的每个静态 Web 文件启用公共读取访问权限,尽管 Bucket 本身已经具有公共读取访问权限!