在进行滚动部署时,如何确保 Cloudfront 具有正确的资产版本?

edh*_*ose 5 amazon-ec2 amazon-cloudfront capifony

我们目前正在使用 Capifony 和ec2-capify插件将我们的代码滚动部署到 ELB 后面的一组实例。我们还使用 CloudFront 来管理静态资产,我们使用查询字符串(例如?v1 或?v2)对其进行版本控制。

我们偶然发现了一个有关更新资产版本的罕见问题。如果当前版本是 v1,并且我们每次对一台服务器进行 v2 的滚动部署,那么 v2 盒子上的请求可能会发生以下情况:

  1. CloudFront 被请求使用 v2,但未命中。
  2. CloudFront 前往 ELB 并请求资产。
  3. ELB 选择一台服务器,并且会发生以下两种情况之一:Cloudfront 命中新部署的服务器之一(服务 v2),或者命中旧服务器(v1)。
  4. 无论哪种方式,Cloudfront 都会将内容存储为 v2。如果它到达 v1 服务器,内容将无法正确提供。

我们当前的解决方案是我们必须使用新的资产版本进行另一次部署。

有没有办法强制 Cloudfront 通过 ELB 仅访问我们更新的 (v2) 服务器之一,并忽略 v1 的服务器?

或者我是否缺少可以解决问题的替代解决方案?

edh*_*ose 1

我们选择的方法是广泛放弃现有的资产部署管道。在“旧”方式中,我们选择了一个asset.css?v=<version>模型,其中 CloudFront 指向由多个实例提供服务的源。

我们解决这个问题的方法是转向哈希名称资产模型和基于 S3 的起源。这意味着asset.css?v=<version>我们没有asset-<hash-of-contents>.css同步到 S3 存储桶。该存储桶逐渐添加越来越新的版本,但如果我们决定返回或通过电子邮件等链接到旧版本(图像的常见问题),则旧版本始终可用。

同步到 S3 脚本在我们部署到包含引用资产的 HTML 的 Web 服务器之前运行,因此 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"
Run Code Online (Sandbox Code Playgroud)