This directory contains examples for managing Cloudflare Pages resources using the operator.
- Cloudflare account with Pages enabled
- API Token with
Account:Cloudflare Pages:Editpermission
| CRD | Description / 说明 |
|---|---|
PagesProject |
Pages project with build config and resource bindings / Pages 项目,支持构建配置和资源绑定 |
PagesDomain |
Custom domain for Pages project / Pages 项目自定义域名 |
PagesDeployment |
Deployment operations (create, retry, rollback, direct upload) / 部署操作(创建、重试、回滚、直接上传) |
| Feature / 功能 | Description / 说明 |
|---|---|
| Direct Upload | Deploy static files from HTTP/S3/OCI sources without Git / 无需 Git,从 HTTP/S3/OCI 源部署静态文件 |
| 4-Step API Flow | Correct MD5-based upload flow (v0.27.13) / 正确的基于 MD5 的 4 步上传流程 (v0.27.13) |
| Smart Rollback | Intelligent rollback with multiple strategies / 支持多种策略的智能回滚 |
| Project Adoption | Import existing Cloudflare Pages projects / 导入已存在的 Cloudflare Pages 项目 |
| Web Analytics | Automatic Web Analytics integration / 自动 Web Analytics 集成 |
| Force Redeploy | Trigger redeployment without config changes / 无需配置变更触发重新部署 |
| DNS Auto-Config | Automatic DNS configuration for custom domains / 自定义域名的自动 DNS 配置 |
| FIFO History | FIFO retention policy (max 200 entries) for deployment history / 部署历史的 FIFO 保留策略(最多 200 条) |
The Direct Upload feature uses Cloudflare's 4-step API flow: 直接上传功能使用 Cloudflare 的 4 步 API 流程:
- Get Upload Token / 获取上传令牌 - Obtain JWT for assets API authentication
- Check Missing / 检查缺失 - Query which files (by MD5 hash) need uploading
- Upload Files / 上传文件 - Upload missing files in batches (base64 encoded)
- Create Deployment / 创建部署 - Create deployment with manifest (path → MD5 mapping)
Note: Special config files (_headers, _redirects, _worker.js, _routes.json) are automatically excluded from the manifest.
注意: 特殊配置文件(_headers、_redirects、_worker.js、_routes.json)会自动从清单中排除。
apiVersion: networking.cloudflare-operator.io/v1alpha2
kind: PagesProject
metadata:
name: my-app
namespace: default
spec:
name: my-app
productionBranch: main
buildConfig:
buildCommand: npm run build
destinationDir: dist
rootDir: /
cloudflare:
accountId: "<your-account-id>" # 替换为实际值 / Replace with actual value
credentialsRef:
name: cloudflare-credentialsapiVersion: networking.cloudflare-operator.io/v1alpha2
kind: PagesProject
metadata:
name: my-github-app
namespace: default
spec:
name: my-github-app
productionBranch: main
source:
type: github
github:
owner: my-org
repo: my-repo
productionDeploymentsEnabled: true
previewDeploymentsEnabled: true
prCommentsEnabled: true
buildConfig:
buildCommand: npm run build
destinationDir: dist
cloudflare:
accountId: "<your-account-id>"
credentialsRef:
name: cloudflare-credentialsapiVersion: networking.cloudflare-operator.io/v1alpha2
kind: PagesProject
metadata:
name: my-app-with-env
namespace: default
spec:
name: my-app-with-env
productionBranch: main
buildConfig:
buildCommand: npm run build
destinationDir: dist
deploymentConfigs:
production:
compatibilityDate: "2024-01-01"
environmentVariables:
API_URL:
value: "https://api.example.com"
type: plain_text
API_KEY:
value: "secret-key"
type: secret_text
preview:
compatibilityDate: "2024-01-01"
environmentVariables:
API_URL:
value: "https://staging-api.example.com"
type: plain_text
cloudflare:
accountId: "<your-account-id>"
credentialsRef:
name: cloudflare-credentialsapiVersion: networking.cloudflare-operator.io/v1alpha2
kind: PagesProject
metadata:
name: full-stack-app
namespace: default
spec:
name: full-stack-app
productionBranch: main
buildConfig:
buildCommand: npm run build
destinationDir: dist
deploymentConfigs:
production:
compatibilityDate: "2024-01-01"
compatibilityFlags:
- nodejs_compat
kvBindings:
- name: MY_KV
namespaceId: "<kv-namespace-id>"
r2Bindings:
- name: MY_BUCKET
bucketName: my-bucket
d1Bindings:
- name: MY_DB
databaseId: "<d1-database-id>"
serviceBindings:
- name: MY_WORKER
service: my-worker
cloudflare:
accountId: "<your-account-id>"
credentialsRef:
name: cloudflare-credentialsapiVersion: networking.cloudflare-operator.io/v1alpha2
kind: PagesDomain
metadata:
name: my-app-domain
namespace: default
spec:
domain: app.example.com
projectRef:
name: my-app # Reference to PagesProject / 引用 PagesProject
autoConfigureDNS: true # Default: true - auto DNS config / 默认:true - 自动 DNS 配置
cloudflare:
accountId: "<your-account-id>"
credentialsRef:
name: cloudflare-credentialsapiVersion: networking.cloudflare-operator.io/v1alpha2
kind: PagesDomain
metadata:
name: external-domain
namespace: default
spec:
domain: app.external-dns.com
projectRef:
name: my-app
autoConfigureDNS: false # Manual DNS management / 手动 DNS 管理
cloudflare:
accountId: "<your-account-id>"
credentialsRef:
name: cloudflare-credentials
# Note: Create CNAME record manually: app.external-dns.com → my-app.pages.dev
# 注意:手动创建 CNAME 记录:app.external-dns.com → my-app.pages.devapiVersion: networking.cloudflare-operator.io/v1alpha2
kind: PagesProject
metadata:
name: my-app-with-analytics
namespace: default
spec:
name: my-app-with-analytics
productionBranch: main
enableWebAnalytics: true # Default: true / 默认:true
deploymentHistoryLimit: 100 # Max: 200 (FIFO retention) / 最大:200(FIFO 保留)
buildConfig:
buildCommand: npm run build
destinationDir: dist
cloudflare:
accountId: "<your-account-id>"
credentialsRef:
name: cloudflare-credentialsDirect Upload allows deploying static files without a Git repository. Supports fetching build artifacts from:
- HTTP/HTTPS: Public or presigned URLs
- S3: AWS S3, MinIO, Cloudflare R2
- OCI: Container registries (Docker Hub, GHCR, etc.)
直接上传允许无需 Git 仓库即可部署静态文件。支持从以下源获取构建产物:
- HTTP/HTTPS:公开或预签名 URL
- S3:AWS S3、MinIO、Cloudflare R2
- OCI:容器镜像仓库(Docker Hub、GHCR 等)
apiVersion: networking.cloudflare-operator.io/v1alpha2
kind: PagesDeployment
metadata:
name: my-app-http-deploy
namespace: default
spec:
projectRef:
name: my-app
action: create
directUpload:
source:
http:
url: "https://ci.example.com/builds/my-app/latest/dist.tar.gz"
headers:
Authorization: "Bearer <token>" # Optional / 可选
timeout: "10m"
checksum:
algorithm: sha256
value: "e3b0c44298fc1c149afbf4c8996fb924..." # Verify integrity / 校验完整性
archive:
type: tar.gz
stripComponents: 1 # Remove top-level directory / 移除顶层目录
cloudflare:
accountId: "<your-account-id>"
credentialsRef:
name: cloudflare-credentialsapiVersion: networking.cloudflare-operator.io/v1alpha2
kind: PagesDeployment
metadata:
name: my-app-s3-deploy
namespace: default
spec:
projectRef:
name: my-app
action: create
directUpload:
source:
s3:
bucket: my-ci-artifacts
key: builds/my-app/v1.2.3/dist.tar.gz
region: us-east-1
credentialsSecretRef:
name: aws-credentials # Contains accessKeyId, secretAccessKey
checksum:
algorithm: sha256
value: "abc123..."
archive:
type: tar.gz
stripComponents: 1
cloudflare:
accountId: "<your-account-id>"
credentialsRef:
name: cloudflare-credentials
---
# AWS Credentials Secret / AWS 凭证 Secret
apiVersion: v1
kind: Secret
metadata:
name: aws-credentials
namespace: default
type: Opaque
stringData:
accessKeyId: "<your-access-key-id>"
secretAccessKey: "<your-secret-access-key>"
# sessionToken: "<optional-session-token>"apiVersion: networking.cloudflare-operator.io/v1alpha2
kind: PagesDeployment
metadata:
name: my-app-r2-deploy
namespace: default
spec:
projectRef:
name: my-app
action: create
directUpload:
source:
s3:
bucket: my-build-artifacts
key: dist.zip
endpoint: "https://<account-id>.r2.cloudflarestorage.com"
credentialsSecretRef:
name: r2-credentials
usePathStyle: true # Required for R2 / R2 必需
archive:
type: zip
cloudflare:
accountId: "<your-account-id>"
credentialsRef:
name: cloudflare-credentialsapiVersion: networking.cloudflare-operator.io/v1alpha2
kind: PagesDeployment
metadata:
name: my-app-oci-deploy
namespace: default
spec:
projectRef:
name: my-app
action: create
directUpload:
source:
oci:
image: "ghcr.io/my-org/my-app-dist:v1.2.3"
credentialsSecretRef:
name: ghcr-credentials # Docker config format / Docker 配置格式
archive:
type: tar.gz
cloudflare:
accountId: "<your-account-id>"
credentialsRef:
name: cloudflare-credentials
---
# OCI Credentials Secret (Docker config format)
apiVersion: v1
kind: Secret
metadata:
name: ghcr-credentials
namespace: default
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: <base64-encoded-docker-config>When the source URL/key doesn't change but you want to trigger a new deployment: 当源 URL/key 不变但需要触发新部署时:
apiVersion: networking.cloudflare-operator.io/v1alpha2
kind: PagesDeployment
metadata:
name: my-app-s3-deploy
namespace: default
annotations:
cloudflare-operator.io/force-redeploy: "2025-01-20-v1" # Change this to trigger redeploy / 修改此值触发重新部署
spec:
projectRef:
name: my-app
action: create
directUpload:
source:
s3:
bucket: my-ci-artifacts
key: builds/latest/dist.tar.gz # Always the same key / 始终相同的 key
region: us-east-1
credentialsSecretRef:
name: aws-credentials
archive:
type: tar.gz
cloudflare:
accountId: "<your-account-id>"
credentialsRef:
name: cloudflare-credentialsSmart Rollback provides intelligent deployment rollback with multiple strategies:
- LastSuccessful: Roll back to the last successful deployment
- ByVersion: Roll back to a specific version number from history
- ExactDeploymentID: Roll back to a specific Cloudflare deployment ID
智能回滚提供多种回滚策略:
- LastSuccessful:回滚到最后一次成功的部署
- ByVersion:回滚到历史记录中的特定版本号
- ExactDeploymentID:回滚到指定的 Cloudflare 部署 ID
apiVersion: networking.cloudflare-operator.io/v1alpha2
kind: PagesDeployment
metadata:
name: my-app-rollback-last
namespace: default
spec:
projectRef:
name: my-app
action: rollback
rollback:
strategy: LastSuccessful # Automatically finds last successful deployment
cloudflare:
accountId: "<your-account-id>"
credentialsRef:
name: cloudflare-credentialsapiVersion: networking.cloudflare-operator.io/v1alpha2
kind: PagesDeployment
metadata:
name: my-app-rollback-v5
namespace: default
spec:
projectRef:
name: my-app
action: rollback
rollback:
strategy: ByVersion
version: 5 # Rollback to version 5 from deployment history
cloudflare:
accountId: "<your-account-id>"
credentialsRef:
name: cloudflare-credentialsapiVersion: networking.cloudflare-operator.io/v1alpha2
kind: PagesDeployment
metadata:
name: my-app-rollback-exact
namespace: default
spec:
projectRef:
name: my-app
action: rollback
rollback:
strategy: ExactDeploymentID
deploymentId: "abc123def456" # Cloudflare deployment ID
cloudflare:
accountId: "<your-account-id>"
credentialsRef:
name: cloudflare-credentialsapiVersion: networking.cloudflare-operator.io/v1alpha2
kind: PagesDeployment
metadata:
name: my-app-rollback-legacy
namespace: default
spec:
projectRef:
name: my-app
action: rollback
targetDeploymentId: "<previous-deployment-id>" # Direct ID specification
cloudflare:
accountId: "<your-account-id>"
credentialsRef:
name: cloudflare-credentialsProject Adoption allows importing existing Cloudflare Pages projects into Kubernetes management:
- IfExists: Adopt if exists, create if not
- MustExist: Require project to exist (for importing)
- MustNotExist: Require project to NOT exist (default, creates new)
项目导入允许将已存在的 Cloudflare Pages 项目纳入 Kubernetes 管理:
- IfExists:如果存在则采纳,不存在则创建
- MustExist:必须已存在(用于导入)
- MustNotExist:必须不存在(默认,创建新项目)
apiVersion: networking.cloudflare-operator.io/v1alpha2
kind: PagesProject
metadata:
name: existing-project
namespace: default
spec:
name: existing-project # Must match existing Cloudflare project name
productionBranch: main
adoptionPolicy: MustExist # Require project to exist in Cloudflare
deploymentHistoryLimit: 20 # Keep more history for rollback
cloudflare:
accountId: "<your-account-id>"
credentialsRef:
name: cloudflare-credentialsapiVersion: networking.cloudflare-operator.io/v1alpha2
kind: PagesProject
metadata:
name: maybe-existing-project
namespace: default
spec:
name: maybe-existing-project
productionBranch: main
adoptionPolicy: IfExists # Adopt if exists, create if not
buildConfig:
buildCommand: npm run build
destinationDir: dist
cloudflare:
accountId: "<your-account-id>"
credentialsRef:
name: cloudflare-credentialsapiVersion: networking.cloudflare-operator.io/v1alpha2
kind: PagesProject
metadata:
name: new-project
namespace: default
spec:
name: new-project
productionBranch: main
adoptionPolicy: MustNotExist # Default - fail if project exists
buildConfig:
buildCommand: npm run build
destinationDir: dist
cloudflare:
accountId: "<your-account-id>"
credentialsRef:
name: cloudflare-credentials| Field / 字段 | Description / 说明 |
|---|---|
type |
Archive format: tar.gz, tar, zip, none / 归档格式 |
stripComponents |
Remove N leading path components (like tar --strip-components) / 移除前 N 层目录 |
subPath |
Extract only files under this subdirectory / 仅解压指定子目录 |
If your archive contains:
my-app-v1.0.0/
├── dist/
│ ├── index.html
│ └── assets/
└── README.md
Use stripComponents: 1 and subPath: "dist" to extract only the dist/ contents:
archive:
type: tar.gz
stripComponents: 1 # Removes "my-app-v1.0.0/"
subPath: "dist" # Only extract files under dist/Supported algorithms / 支持的算法:
sha256(default / 默认)sha512md5(legacy / 兼容旧系统)
checksum:
algorithm: sha256
value: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"# Check PagesProject status / 检查 PagesProject 状态
kubectl get pagesproject my-app -o wide
# Check if project was adopted / 检查项目是否被采纳
kubectl get pagesproject existing-project -o jsonpath='{.status.adopted}'
# View deployment history / 查看部署历史
kubectl get pagesproject my-app -o jsonpath='{.status.deploymentHistory}'
# Check PagesDeployment status / 检查 PagesDeployment 状态
kubectl get pagesdeployment my-app-deploy -o wide
# View detailed status / 查看详细状态
kubectl describe pagesdeployment my-app-deploy
# View operator logs / 查看 Operator 日志
kubectl logs -n cloudflare-operator-system deployment/cloudflare-operator-controller-managerkubectl delete pagesdeployment --all
kubectl delete pagesdomain --all
kubectl delete pagesproject --all| Topic / 主题 | Link / 链接 |
|---|---|
| API Reference / API 参考 | docs/en/api-reference/ |
| Configuration / 配置 | docs/en/configuration.md |
| Troubleshooting / 故障排除 | docs/en/troubleshooting.md |