在进行滚动部署时,如何确保 Cloudfront 具有正确的资产版本?
Posted
技术标签:
【中文标题】在进行滚动部署时,如何确保 Cloudfront 具有正确的资产版本?【英文标题】:How do I ensure Cloudfront has the correct asset version when doing a rolling deployment? 【发布时间】:2015-07-08 08:55:45 【问题描述】:我们目前正在使用 Capifony 和 ec2-capify 插件将我们的代码滚动部署到 ELB 后面的一组实例。我们还使用 CloudFront 管理静态资产,我们使用查询字符串(例如 ?v1 或 ?v2)对其进行版本控制。
我们偶然发现了一个关于更新资产版本的罕见问题。如果当前版本是 v1,并且我们一次滚动部署 v2 一台服务器,那么 v2 机器上的请求可能会发生以下情况:
-
CloudFront 被要求提供 v2 并且未命中。
CloudFront 转到 ELB 并请求资产。
ELB 选择了一台服务器,然后发生以下两种情况之一:Cloudfront 访问其中一台新部署的服务器(服务于 v2)或访问旧服务器 (v1)。
无论哪种方式,Cloudfront 都将内容存储为 v2。在访问 v1 服务器的情况下,内容服务不正确。
我们目前的解决方案是我们必须使用新的资产版本进行另一次部署。
有没有办法通过 ELB 强制 Cloudfront 只访问我们更新的 (v2) 服务器之一,而忽略 v1?
或者我是否缺少可以解决问题的替代解决方案?
【问题讨论】:
你有没有找到好的方法? 有类似的问题,但由于资产版本在名称中,当使用只有 v1 的旧服务器时,客户端会得到 404。 【参考方案1】:我认为在您的情况下,正确的部署策略是首先部署能够同时服务于 v1 和 v2 资产(但仍服务于 v1)的实例,然后再进行一次滚动部署以切换到 v2。
ELB (http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/US_StickySessions.html) 上还有可用的“粘性会话”,但我不知道如何在此处使用 - 每个查看者的 cookie 将消除 CloudFront 缓存的好处
【讨论】:
【参考方案2】:我们选择的方法是广泛放弃我们现有的资产部署管道。在“旧”方式中,我们选择了 asset.css?v=<version>
模型,其中 CloudFront 指向由多个实例提供服务的源。
我们解决它的方法是迁移到哈希名称资产模型和基于 S3 的来源。这意味着我们有 asset-<hash-of-contents>.css
而不是 asset.css?v=<version>
,它们同步到 S3 存储桶。存储桶会逐步添加更新和更新的版本,但如果我们决定返回或如果有类似电子邮件的链接指向旧版本(图像的常见问题),旧版本始终可用。
同步到 S3 脚本在我们部署到包含引用资产的 HTML 的网络服务器之前运行,因此 CloudFront 始终能够提供最新的资产。
这是一个示例脚本:
#!/usr/bin/env bash
set -e # Fail on any error
set -x
if [ "$#" -ne "1" ]
then
echo "Usage: call with the name of the environment you're deploying to"
exit 1
fi
CDN_ENVIRONMENT=$1
S3_BUCKET="s3://static-bucket-name-of-your-choice/$CDN_ENVIRONMENT/"
echo "Generating assets
... do the asset generation here ...
echo "Copying to S3"
# Now do the actual copying of the web dir. We use size-only because otherwise all files are newer, and all get copied.
aws s3 sync --exclude "some-folder-to-exclude/*" --acl public-read --size-only ./web/ $S3_BUCKET
echo "Copy to S3 complete"
【讨论】:
【参考方案3】:当 Cloudfront 从您的源获得 404 时(可能是因为它尚未收到新版本),它会将该 404 缓存 5 分钟。您可以通过为您的分发创建新的“自定义错误响应”来更改该行为。自定义响应允许您设置一个非常低的 TTL,以便 Cloudfront 将传递到您的 ELB,直到它找到新文件。这样做的缺点是 Cloudfront 将不再有效地缓存 404 - 您的 ELB 将需要处理该负载(希望很小!)
http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/HTTPStatusCodes.html#HTTPStatusCodes-no-custom-error-pages
【讨论】:
以上是关于在进行滚动部署时,如何确保 Cloudfront 具有正确的资产版本?的主要内容,如果未能解决你的问题,请参考以下文章
如何在模板文件中为 CloudFront 函数设置 FunctionCode 属性?
Rails 3 自动资产部署到 Amazon CloudFront?