1. 简介
上次更新日期:2024 年 5 月 1 日
内容分发网络 (CDN) 通过以下方式提升用户性能:在更靠近最终用户的位置缓存经常访问的内容、终止更靠近客户端的连接、重复使用与源站的连接,以及采用现代网络协议和自定义。
媒体 CDN 是 GCP 的全球边缘网络,用于流式传输媒体内容,提供许多内置功能或“核心”功能,核心功能旨在满足最常见的用例需求,但您可能还有一些该核心功能集未涵盖的要求。
借助媒体 CDN 的服务扩展(有时也称为边缘可编程性),您可以在边缘运行自己的代码,以自定义媒体 CDN 的行为。这解锁了更多用例,包括对缓存密钥进行标准化、自定义令牌身份验证和令牌撤消、其他自定义日志字段、A/B 测试和自定义错误页面。
构建内容
在此 Codelab 中,我们将逐步介绍如何使用媒体 CDN (CDN) + Service Extensions(边缘可编程性)和 Cloud Storage(CDN 来源)部署支持 Edge Compute 的 CDN 分发环境。
学习内容
- 如何设置媒体 CDN 并将 Cloud Storage 存储分区设为源站
- 如何创建使用自定义 HTTP 身份验证的 Service Extension 插件,并将其与媒体 CDN 相关联
- 如何验证 Service Extension 插件是否按预期运行
- (可选)如何管理 Service Extension 插件,例如更新、引用、回滚和删除特定插件版本
所需条件
- 网络基本知识和 HTTP 知识
- Unix/Linux 命令行基础知识
2. 准备工作
请求媒体 CDN 许可名单和服务扩展程序许可名单
在开始之前,您需要确保您的项目已添加至媒体 CDN 和媒体 CDN 服务扩展的非公开预览版许可名单中。
- 如需请求访问媒体 CDN 和适用于媒体 CDN 的服务扩展程序,请与您的 Google 客户支持团队联系,让其代表您创建媒体 CDN 和服务扩展程序的访问权限请求
3. 设置和要求
启动 Cloud Shell
虽然可以通过笔记本电脑对 Google Cloud 进行远程操作,但在此 Codelab 中,您将使用 Google Cloud Shell,这是一个在云端运行的命令行环境。
在 GCP 控制台中,点击右上角工具栏上的 Cloud Shell 图标:
预配和连接到环境应该只需要片刻时间。完成后,您应该会看到如下内容:
这个虚拟机已加载了您需要的所有开发工具。它提供了一个持久的 5GB 主目录,并且在 Google Cloud 中运行,大大增强了网络性能和身份验证功能。只需一个浏览器,即可完成本实验中的所有工作。
准备工作
IAM 角色和访问权限
创建媒体 CDN 和 Artifact Registry 资源所需的 Identity and Access Management (IAM) 权限如下:
- roles/networkservices.edgeCacheAdmin
- roles/networkservices.edgeCacheUser
- roles/networkservices.edgeCacheViewer
- roles/artifactregistry.repoAdmin
在 Cloud Shell 中,确保已设置 project_id、project_num、location 和 repository 环境变量。
gcloud config list project gcloud config set project [YOUR-PROJECT-NAME] PROJECT_ID=[YOUR-PROJECT-NAME] PROJECT_NUM=[YOUR-PROJECT-NUMBER] LOCATION=us-central1 REPOSITORY=service-extension-$PROJECT_ID
启用 API
启用媒体 CDN 和通过以下命令运行 Service Extensions API
gcloud services enable networkservices.googleapis.com gcloud services enable networkactions.googleapis.com gcloud services enable edgecache.googleapis.com gcloud services enable artifactregistry.googleapis.com
4. 创建 Cloud Storage 存储分区
媒体 CDN 内容可以来自 Cloud Storage 存储分区、第三方存储位置或任何可公开访问的 HTTP(HTTPS) 端点等位置。
在此 Codelab 中,我们将内容存储在 Cloud Storage 存储分区中。
我们将使用 gsutil mb 命令创建存储分区
gsutil mb gs://mediacdn-bucket-$PROJECT_ID
(可选)您可以使用 GUI 创建 Cloud Storage 存储分区,如下所示:
- 在 Google Cloud 控制台中,转到 Cloud Storage 页面。
- 点击创建按钮。
- 输入存储分区的名称。即“mediacdn-bucket-$PROJECT_ID”。
- 将其他设置保留为默认值。
- 点击创建按钮。
5. 将测试对象上传到 Cloud Storage 存储分区
现在,我们将一个对象上传到 Cloud Storage 存储分区。
- 在 Cloud Shell 中创建一个文件,然后使用 gsutil 将其上传到存储分区
echo media-cdn-service-extensions-test > file.txt gsutil cp file.txt gs://mediacdn-bucket-$PROJECT_ID
- 向媒体 CDN 授予对存储分区的访问权限
gsutil iam ch \ serviceAccount:service-$PROJECT_NUM@gcp-sa-mediaedgefill.iam.gserviceaccount.com:objectViewer gs://mediacdn-bucket-$PROJECT_ID
6. 配置媒体 CDN
接下来,我们将创建媒体 CDN 配置。
每项媒体 CDN 配置都包含两个主要资源:
- EdgeCacheService,负责面向客户端的配置(TLS、IP 地址)、路由、CDN 配置(缓存模式、TTL、签名)和安全政策。
- EdgeCacheOrigin,负责针对任何基于 HTTP 的来源进行每个来源的配置,以及在内容不可用或无法访问时的重试条件。
配置边缘缓存来源
现在,我们来创建一个指向您刚刚创建的 Cloud Storage 存储分区的来源。
- 在 Google Cloud 控制台中,前往媒体 CDN 页面。
- 点击来源标签页。
- 点击创建来源。
- 输入“cloud-storage-origin”作为边缘缓存来源的名称
- 在源地址下:
- 选择“选择 Google Cloud Storage 存储分区”
- 浏览名为“mediacdn-bucket-$PROJECT_ID”的 Cloud Storage 存储分区。
- 点击“选择”。
- 将其他设置保留为默认值。
- 点击创建来源。
新创建的 EdgeCacheOrigin 资源会显示在“来源”页面上项目的来源列表中。
配置边缘缓存服务
- 在 Google Cloud 控制台中,前往媒体 CDN 页面。
- 点击服务标签页。
- 点击创建服务。
- 为您的服务输入一个唯一名称,例如“media-cdn”- 然后点击“下一步”。
- 在“转送”部分,点击添加主机规则。
- 输入通配符“*”输入主机名称。
- 点击添加路由规则。
- 对于“优先级”,请指定“1”。
- 点击添加匹配条件。对于“路径匹配”,请选择“前缀匹配”作为匹配类型,指定“/”,然后点击“完成”。
- 选择“主要操作”下的从来源提取,然后从下拉列表中选择您配置的来源。
- 点击高级配置,扩展更多配置选项。
- 在“路由操作”中,点击添加项目。之后,执行以下操作:
- 对于“类型”,选择“CDN 政策”。
- 对于缓存模式,请选择“强制缓存所有内容”。
- 将其余设置保留为默认值
- 点击“完成”。
- 点击保存。
- 点击创建服务。
新创建的 EdgeCacheService 资源会显示在项目的服务列表中的“服务”页面上。
检索 MediaCDN IP 地址并进行测试
- 在 Google Cloud 控制台中,前往媒体 CDN 页面。
- 前往媒体 CDN
- 点击服务标签页。
- 具体请参阅地址列,了解您使用的服务。
要测试您的服务是否已正确配置为缓存内容,请使用 curl 命令行工具发出请求并检查响应。
curl -svo /dev/null "http://MEDIA_CDN_IP_ADDRESS/file.txt"
该命令应生成类似于以下内容的输出:
< HTTP/2 200 OK ... media-cdn-service-extensions-test ...
现在,您已成功创建以 Cloud Storage 为源的 MediaCDN 部署。
7. 为 Service Extensions 配置 Artifact Registry
在创建 Service Extensions 扩展之前,我们需要配置 Artifact Registry。Artifact Registry 是 Google Cloud 的通用软件包管理器,用于管理构建工件。Service Extension (Proxy-Wasm) 插件已发布到 Artifact Registry。发布到 Artifact Registry 后,可将 Proxy-Wasm 插件部署到媒体 CDN 部署。
我们将使用 gcloud artifacts repositories create 命令创建代码库。
gcloud artifacts repositories create service-extension-$PROJECT_ID \ --repository-format=docker \ --location=$LOCATION \ --description="Repo for Service Extension" \ --async
(可选)您可以使用 GUI 创建代码库,如下所示:
- 在 Google Cloud 控制台中,转到 Artifact Registry 页面。
- 点击 + CREATE REPOSITORY 按钮。
- 输入代码库的名称。即“service-extension-$PROJECT_ID”。
- 格式 -“Docker”模式 -“Standard”,位置类型 -“Region”,然后选择“us-central1(爱荷华)”
- 点击创建按钮。
新创建的 Artifact Registry 仓库资源应显示在“仓库”页面上。
创建代码库资源后,在 Cloud Shell 中运行以下命令,以配置 Cloud Shell Docker 客户端以使用此代码库推送和拉取软件包。
gcloud auth configure-docker $LOCATION-docker.pkg.dev
输出:
... Adding credentials for: us-central1-docker.pkg.dev Docker configuration file updated.
8. 在媒体 CDN 上配置服务扩展程序
现在,我们将演示如何使用 Rust 编程语言编写和构建可部署到媒体 CDN 的服务扩展 (Proxy-Wasm) 插件。
在此示例中,我们将创建一个 Proxy-Wasm 插件,用于验证每个 HTTP 请求是否包含值为“secret”的授权标头。如果请求不包含此标头,插件将生成“HTTP 403 Forbidden”响应。
快速回顾一下 Service Extensions 扩展 - 有三个关键资源:WasmAction、WasmPlugin 和 WasmPluginVersion。
- WasmAction 资源是附加到媒体 CDN EdgeCacheService 的内容。WasmAction 引用 WasmPlugin 资源。
- WasmPlugin 资源有一个 main-version,与当前有效的 WasmPluginVersion 相对应。
- WasmPluginVersions 会引用 Artifact Registry 中的容器映像。在对 Proxy-wasm 插件进行更改时,您需创建不同的 WasmPluginVersion。
请参考下图,更好地了解这些资源之间的关系。
编写和构建 Service Extension 插件
- 按照 https://www.rust-lang.org/tools/install 上的说明安装 Rust 工具链。
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
- 接下来,通过运行以下命令,为 Rust 工具链添加 Wasm 支持:
rustup target add wasm32-wasi
- 创建一个名为 my-wasm-plugin 的 Rust 软件包:
cargo new --lib my-wasm-plugin
输出:
Created library `my-wasm-plugin` package
- 输入 my-wasm-plugin 目录,您应该会看到
Cargo.toml
文件和src
目录。
cd my-wasm-plugin ls
输出:
Cargo.toml src
- 接下来,通过修改
Cargo.toml
文件来配置 Rust 软件包。在 Cargo.toml 文件中的[dependencies]
行之后,添加以下代码:
proxy-wasm = "0.2"
log = "0.4"
[lib]
crate-type = ["cdylib"]
[profile.release]
lto = true
opt-level = 3
codegen-units = 1
panic = "abort"
strip = "debuginfo"
- 完成修改后,
Cargo.toml
文件应大致如下所示:
[package]
name = "my-wasm-plugin"
version = "0.1.0"
edition = "2021"
[dependencies]
proxy-wasm = "0.2"
log = "0.4"
[lib]
crate-type = ["cdylib"]
[profile.release]
lto = true
opt-level = 3
codegen-units = 1
panic = "abort"
strip = "debuginfo"
- 完成修改后,
lib.rs
文件应大致如下所示:
use log::info;
use proxy_wasm::traits::*;
use proxy_wasm::types::*;
...
struct DemoPlugin;
impl HttpContext for DemoPlugin {
fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action {
if self.get_http_request_header("Authorization") == Some(String::from("secret")) {
info!("Access granted.");
Action::Continue
} else {
self.send_http_response(403, vec![], Some(b"Access forbidden.\n"));
Action::Pause
}
}
}
impl Context for DemoPlugin {}
- 现在,我们已经配置了
Cargo.toml
清单文件,并在lib.rs
文件中编写了 Proxy-Wasm 代码,接下来就可以构建 Proxy-Wasm 插件了。
cargo build --release --target wasm32-wasi
构建成功完成后,您将看到如下所示的消息:
Finished release [optimized] target(s) in 1.01s
我们再验证一下 target
目录,并检查已创建的文件:
ls ./target
您将看到如下所示的输出:
CACHEDIR.TAG release wasm32-wasi
将 Proxy-Wasm 插件发布到 Artifact Registry
现在,我们会将 Proxy-Wasm 插件发布到您之前创建的 Artifact Registry 代码库,以便将其部署到媒体 CDN。
我们首先将 Proxy-Wasm 插件打包到容器映像中。
- 在同一目录 my-wasm-plugin 中创建一个名为
Dockerfile
的文件,其中包含以下内容:
FROM scratch
COPY target/wasm32-wasi/release/my_wasm_plugin.wasm plugin.wasm
- 接下来,构建容器映像:
docker build --no-cache --platform wasm -t my-wasm-plugin .
(仅限非 x86 处理器)接下来,构建容器映像:
docker build --no-cache --platform wasm --provenance=false -t my-wasm-plugin .
输出
[+] Building 0.2s (5/5) FINISHED docker:default ...
- 下一步,发布或“推送”将 Proxy-Wasm 插件迁移到 Artifact Registry。我们将使用“prod”标记标记前面。
docker tag my-wasm-plugin $LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/my-wasm-plugin:prod
现在,我们要将标记为“prod”的复制到代码库
docker push $LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/my-wasm-plugin:prod
输出:
The push refers to repository ... 8564ddd9910a: Pushed prod: digest: sha256:f3ae4e392eb45393bfd9c200cf8c0c261762f7f39dde5c7cd4b9a8951c6f2812 size: 525
现在,我们将验证 Proxy-Wasm 插件的容器映像已成功推送到 Artifact Registry,您应该会看到类似输出:
gcloud artifacts docker images list $LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/my-wasm-plugin --include-tags
输出:
Listing items under project ... IMAGE DIGEST TAGS CREATE_TIME UPDATE_TIME <LOCATION>-docker.pkg.dev/.../my-wasm-plugin sha256:08c12... prod 2021-11-10T23:31:27 2021-11-10T23:31:27
将 Proxy-Wasm 插件与媒体 CDN 部署相关联
现在,我们已准备好将 Proxy-Wasm 插件与您的媒体 CDN 部署相关联。
Proxy-Wasm 插件与 EdgeCacheService 资源中的媒体 CDN 路由相关联。
- 首先,我们为 Proxy-Wasm 插件创建 Wasm-plugin 资源。
gcloud alpha service-extensions wasm-plugins create my-wasm-plugin-resource
- 接下来,我们创建一个 WasmPluginVersion。
gcloud alpha service-extensions wasm-plugin-versions create my-version-1 \ --wasm-plugin=my-wasm-plugin-resource \ --image="$LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/my-wasm-plugin:prod"
- 接下来,我们指定 Proxy-Wasm 插件的主版本。
gcloud alpha service-extensions wasm-plugins update my-wasm-plugin-resource \ --main-version=my-version-1
现在,我们来验证 Proxy-Wasm 插件已成功关联到位于 Artifact Registry Repository 中的容器映像,您应该会看到类似输出:
gcloud alpha service-extensions wasm-plugin-versions list --wasm-plugin=my-wasm-plugin-resource
输出:
NAME WASM_IMAGE WASM_IMAGE_DIGEST CONFIG_SIZE CONFIG_IMAGE CONFIG_IMAGE_DIGEST UPDATE_TIME c7cfa2 <LOCATION>-docker.pkg.dev/.../my-wasm-plugin@sha256:6d663... ... ... ...
- 接下来,我们创建一个引用 Wasm 插件资源的 WasmAction 资源。
gcloud alpha service-extensions wasm-actions create my-wasm-action-resource \ --wasm-plugin=my-wasm-plugin-resource
我们再验证一下 WasmAction 资源是否已成功关联到 Proxy-Wasm 插件,您应该会看到类似输出:
gcloud alpha service-extensions wasm-actions list
输出:
NAME WASMPLUGIN my-wasm-action-resource projects/805782461588/locations/global/wasmPlugins/myenvoyfilter-resource ...
- 现在,我们需要导出媒体 CDN EdgeCacheService 的配置:
gcloud edge-cache services export media-cdn --destination=my-service.yaml
- 然后,打开 my-service.yaml 文件,并将 wasmAction 添加到给定路由的 routeAction 中,引用先前创建的 WasmPlugin 资源。
wasmAction: "my-wasm-action-resource"
- 修改后,my-service.yaml 文件应大致如下所示:
...
pathMatchers:
- name: routes
routeRules:
- headerAction: {}
matchRules:
- prefixMatch: /
origin: projects/<PROJECT_NUM>/locations/global/edgeCacheOrigins/cloud-storage-origin
priority: '1'
routeAction:
cdnPolicy:
cacheKeyPolicy: {}
cacheMode: FORCE_CACHE_ALL
defaultTtl: 3600s
signedRequestMode: DISABLED
wasmAction: "my-wasm-action-resource"
...
- 然后,使用 Proxy-Wasm 配置将更新后的配置保存到
my-service-with-wasm.yaml
文件中。
- 最后,为正式版媒体 CDN 环境导入更新后的配置:
$ gcloud alpha edge-cache services import media-cdn --source=my-service-with-wasm.yaml
9. 在媒体 CDN 上验证 Service Extensions Proxy-Wasm 插件
要测试您的服务是否已正确配置为缓存内容,请使用 curl 命令行工具发出请求并检查响应。
curl -svo /dev/null "http://IP_ADDRESS/file.txt"
该命令应生成类似于以下内容的输出:
< HTTP/2 403 Forbidden ... Access forbidden. ...
现在,使用 Authorization 标头及其 Secret 值再次发出请求
curl -svo /dev/null "http://IP_ADDRESS/file.txt" -H "Authorization: secret"
该命令应生成类似于以下内容的输出:
< HTTP/2 200 OK ... media-cdn-service-extensions-test ...
10. 可选:管理 Proxy-Wasm 插件
更新 Proxy-Wasm 插件
当您对 Proxy-Wasm 插件进行改进或添加新功能时,您需要将更新的插件部署到媒体 CDN。下面,我们将逐步介绍部署插件更新版本的步骤。
例如,您可以通过修改如下代码来更新示例插件代码,以根据其他身份验证值评估 Authorization 标头。
首先,使用如下所示的代码更新 src/lib.rs 源文件:
use log::{info, warn};
use proxy_wasm::traits::*;
use proxy_wasm::types::*;
...
struct DemoPlugin;
impl HttpContext for DemoPlugin {
fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action {
if self.get_http_request_header("Authorization") == Some(String::from("another_secret")) {
info!("Access granted.");
Action::Continue
} else {
warn!("Access forbidden.");
self.send_http_response(403, vec![], Some(b"Access forbidden.\n"));
Action::Pause
}
}
}
impl Context for DemoPlugin {}
接下来,构建、打包并发布更新后的插件:
cargo build --release --target wasm32-wasi docker build --no-cache --platform wasm -t my-wasm-plugin . docker tag my-wasm-plugin $LOCATION-docker.pkg.dev/$PROJECT_NUM/$REPOSITORY/my-wasm-plugin:prod docker push $LOCATION-docker.pkg.dev/$PROJECT_NUM/$REPOSITORY>/my-wasm-plugin:prod
在 Artifact Registry 中更新容器映像后,我们需要创建一个新的 WasmPluginVersion,然后更新 WasmPlugin 的 –main-version 以引用新版本。
gcloud alpha service-extensions wasm-plugin-versions create my-version-2 \ --wasm-plugin=my-wasm-plugin-resource \ --image="$LOCATION-docker.pkg.dev/$PROJECT_NUM/$REPOSITORY>/my-wasm-plugin:prod"
gcloud alpha service-extensions wasm-plugins update my-wasm-plugin-resource \ --main-version=my-version-2
现在,您已成功更新要从 Artifact Registry 导入的容器映像版本,并将其实时推送到媒体 CDN 部署。
回滚到先前的版本
如需回滚到以前版本的插件,您可以更新 Wasm 插件资源以引用先前版本。
首先,我们列出可用的版本:
gcloud alpha service-extensions wasm-plugin-versions list --wasm-plugin=my-wasm-plugin-resource
您应该会看到以下输出:
NAME WASM_IMAGE WASM_IMAGE_DIGEST CONFIG_SIZE CONFIG_IMAGE CONFIG_IMAGE_DIGEST UPDATE_TIME c7cfa2 <LOCATION>-docker.pkg.dev/.../my-wasm-plugin@sha256:6d663... ... ... a2a8ce <LOCATION>-docker.pkg.dev/.../my-wasm-plugin@sha256:08c12... ... ...
接下来,我们更新 Wasm 插件资源以引用先前版本“a2a8ce”:
$ gcloud alpha service-extensions wasm-plugins update my-wasm-plugin-resource \ --main-version="a2a8ce"
操作成功后,您应该会看到以下输出:
✓ WASM Plugin [my-wasm-plugin-resource] is now serving version "a2a8ce"
每次创建新的 Wasm 插件资源时,媒体 CDN 都会保存 Docker 映像的映像摘要,因此回滚会使用上次发布之前运行的代码版本。
gcloud alpha service-extensions wasm-plugins describe my-wasm-plugin-resource \ --expand-config
对于版本“a2a8ce”,即为摘要 sha256:08c12... 的版本:
name: "my-wasm-plugin-resource" mainVersion: "a2a8ce" mainVersionDetails: image: "<LOCATION>-docker.pkg.dev/<PROJECT>/<REPOSITORY>/my-wasm-plugin" imageDigest: "<LOCATION>-docker.pkg.dev/<PROJECT>/<REPOSITORY>/my-wasm-plugin@sha256:08c121dd7fd1e4d3a116a28300e9fc1fa41b2e9775620ebf3d96cb7119bd9976"
删除 WasmAction 和WasmPlugin
要删除 WasmAction、WasmPlugin 和关联的 WasmPluginVersion,请按以下步骤操作。
首先,在媒体 CDN EdgeCacheService 配置中移除对 WasmAction 的引用。
要移除的参考行:
wasmAction: "my-wasm-action-resource"
然后,更新修改后的 EdgeCacheService 配置。
gcloud alpha edge-cache services import prod-media-service --source=my-service.yaml
接下来,将 WasmPlugin 的主版本更新为空字符串 ""。
gcloud alpha service-extensions wasm-plugins update my-wasm-plugin-resource --main-version=
""
最后,按顺序执行以下删除步骤。
gcloud alpha service-extensions wasm-actions delete my-wasm-action-resource gcloud alpha service-extensions wasm-plugin-versions delete my-version \ --wasm-plugin=my-wasm-plugin-resource gcloud alpha service-extensions wasm-plugins delete my-wasm-plugin-resource
11. 清理实验环境
完成 Codelab 后,请记得清理实验资源,否则这些资源将继续运行并产生费用。
以下命令将删除媒体 CDN EdgeCache 服务、EdgeCache 配置和 Service Extensions 插件。按顺序执行以下删除步骤。
gcloud edge-cache services delete media-cdn gcloud edge-cache origins delete cloud-storage-origin gcloud alpha service-extensions wasm-actions delete my-wasm-action-resource gcloud alpha service-extensions wasm-plugins update my-wasm-plugin-resource --main-version="" gcloud alpha service-extensions wasm-plugin-versions delete my-version-1 --wasm-plugin=my-wasm-plugin-resource gcloud alpha service-extensions wasm-plugins delete my-wasm-plugin-resource gcloud artifacts repositories delete service-extension-$PROJECT_ID --location=$LOCATION
上述每个命令都应要求您确认删除资源。
12. 恭喜!
恭喜,您已完成“媒体 CDN 上的 Service Extensions”Codelab!
所学内容
- 如何设置媒体 CDN 并将 Cloud Storage 存储分区设为源站
- 如何创建使用自定义 HTTP 身份验证的 Service Extension 插件,并将其与媒体 CDN 相关联
- 如何验证 Service Extension 插件是否按预期运行
- (可选)如何管理 Service Extension 插件,例如更新、引用、回滚和删除特定插件版本
后续操作
查看下列 Codelab…