customerio-deploy-pipeline
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCustomer.io Deploy Pipeline
Customer.io 部署流水线
Overview
概述
Deploy Customer.io integrations to production cloud platforms with proper configuration and monitoring.
通过正确的配置和监控,将Customer.io集成部署到生产云平台。
Prerequisites
前提条件
- CI/CD pipeline configured
- Cloud platform access (GCP, AWS, Vercel, etc.)
- Production credentials ready
- 已配置CI/CD流水线
- 拥有云平台访问权限(GCP、AWS、Vercel等)
- 准备好生产环境凭证
Instructions
操作步骤
Step 1: Google Cloud Run Deployment
步骤1:Google Cloud Run部署
yaml
undefinedyaml
undefined.github/workflows/deploy-cloud-run.yml
.github/workflows/deploy-cloud-run.yml
name: Deploy to Cloud Run
on:
push:
branches: [main]
env:
PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
REGION: us-central1
SERVICE_NAME: customerio-service
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- id: auth
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.WIF_PROVIDER }}
service_account: ${{ secrets.WIF_SERVICE_ACCOUNT }}
- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@v2
- name: Configure Docker
run: gcloud auth configure-docker ${{ env.REGION }}-docker.pkg.dev
- name: Build and Push
run: |
docker build -t ${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/services/${{ env.SERVICE_NAME }}:${{ github.sha }} .
docker push ${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/services/${{ env.SERVICE_NAME }}:${{ github.sha }}
- name: Deploy to Cloud Run
run: |
gcloud run deploy ${{ env.SERVICE_NAME }} \
--image ${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/services/${{ env.SERVICE_NAME }}:${{ github.sha }} \
--region ${{ env.REGION }} \
--platform managed \
--set-secrets CUSTOMERIO_SITE_ID=customerio-site-id:latest,CUSTOMERIO_API_KEY=customerio-api-key:latest \
--allow-unauthenticatedundefinedname: Deploy to Cloud Run
on:
push:
branches: [main]
env:
PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
REGION: us-central1
SERVICE_NAME: customerio-service
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- id: auth
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.WIF_PROVIDER }}
service_account: ${{ secrets.WIF_SERVICE_ACCOUNT }}
- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@v2
- name: Configure Docker
run: gcloud auth configure-docker ${{ env.REGION }}-docker.pkg.dev
- name: Build and Push
run: |
docker build -t ${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/services/${{ env.SERVICE_NAME }}:${{ github.sha }} .
docker push ${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/services/${{ env.SERVICE_NAME }}:${{ github.sha }}
- name: Deploy to Cloud Run
run: |
gcloud run deploy ${{ env.SERVICE_NAME }} \
--image ${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/services/${{ env.SERVICE_NAME }}:${{ github.sha }} \
--region ${{ env.REGION }} \
--platform managed \
--set-secrets CUSTOMERIO_SITE_ID=customerio-site-id:latest,CUSTOMERIO_API_KEY=customerio-api-key:latest \
--allow-unauthenticatedundefinedStep 2: Vercel Deployment
步骤2:Vercel部署
json
// vercel.json
{
"buildCommand": "npm run build",
"outputDirectory": "dist",
"env": {
"CUSTOMERIO_SITE_ID": "@customerio-site-id",
"CUSTOMERIO_API_KEY": "@customerio-api-key"
},
"functions": {
"api/**/*.ts": {
"memory": 256,
"maxDuration": 10
}
}
}typescript
// api/customerio/identify.ts
import { TrackClient, RegionUS } from '@customerio/track';
import type { VercelRequest, VercelResponse } from '@vercel/node';
const client = new TrackClient(
process.env.CUSTOMERIO_SITE_ID!,
process.env.CUSTOMERIO_API_KEY!,
{ region: RegionUS }
);
export default async function handler(req: VercelRequest, res: VercelResponse) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
try {
const { userId, attributes } = req.body;
await client.identify(userId, attributes);
res.status(200).json({ success: true });
} catch (error: any) {
res.status(500).json({ error: error.message });
}
}json
// vercel.json
{
"buildCommand": "npm run build",
"outputDirectory": "dist",
"env": {
"CUSTOMERIO_SITE_ID": "@customerio-site-id",
"CUSTOMERIO_API_KEY": "@customerio-api-key"
},
"functions": {
"api/**/*.ts": {
"memory": 256,
"maxDuration": 10
}
}
}typescript
// api/customerio/identify.ts
import { TrackClient, RegionUS } from '@customerio/track';
import type { VercelRequest, VercelResponse } from '@vercel/node';
const client = new TrackClient(
process.env.CUSTOMERIO_SITE_ID!,
process.env.CUSTOMERIO_API_KEY!,
{ region: RegionUS }
);
export default async function handler(req: VercelRequest, res: VercelResponse) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
try {
const { userId, attributes } = req.body;
await client.identify(userId, attributes);
res.status(200).json({ success: true });
} catch (error: any) {
res.status(500).json({ error: error.message });
}
}Step 3: AWS Lambda Deployment
步骤3:AWS Lambda部署
yaml
undefinedyaml
undefinedserverless.yml
serverless.yml
service: customerio-integration
provider:
name: aws
runtime: nodejs20.x
region: us-east-1
environment:
CUSTOMERIO_SITE_ID: ${ssm:/customerio/site-id}
CUSTOMERIO_API_KEY: ${ssm:/customerio/api-key}
functions:
identify:
handler: src/handlers/identify.handler
events:
- http:
path: /identify
method: post
track:
handler: src/handlers/track.handler
events:
- http:
path: /track
method: post
webhook:
handler: src/handlers/webhook.handler
events:
- http:
path: /webhook
method: post
```typescript
// src/handlers/identify.ts
import { APIGatewayProxyHandler } from 'aws-lambda';
import { TrackClient, RegionUS } from '@customerio/track';
const client = new TrackClient(
process.env.CUSTOMERIO_SITE_ID!,
process.env.CUSTOMERIO_API_KEY!,
{ region: RegionUS }
);
export const handler: APIGatewayProxyHandler = async (event) => {
try {
const body = JSON.parse(event.body || '{}');
await client.identify(body.userId, body.attributes);
return {
statusCode: 200,
body: JSON.stringify({ success: true })
};
} catch (error: any) {
return {
statusCode: 500,
body: JSON.stringify({ error: error.message })
};
}
};service: customerio-integration
provider:
name: aws
runtime: nodejs20.x
region: us-east-1
environment:
CUSTOMERIO_SITE_ID: ${ssm:/customerio/site-id}
CUSTOMERIO_API_KEY: ${ssm:/customerio/api-key}
functions:
identify:
handler: src/handlers/identify.handler
events:
- http:
path: /identify
method: post
track:
handler: src/handlers/track.handler
events:
- http:
path: /track
method: post
webhook:
handler: src/handlers/webhook.handler
events:
- http:
path: /webhook
method: post
```typescript
// src/handlers/identify.ts
import { APIGatewayProxyHandler } from 'aws-lambda';
import { TrackClient, RegionUS } from '@customerio/track';
const client = new TrackClient(
process.env.CUSTOMERIO_SITE_ID!,
process.env.CUSTOMERIO_API_KEY!,
{ region: RegionUS }
);
export const handler: APIGatewayProxyHandler = async (event) => {
try {
const body = JSON.parse(event.body || '{}');
await client.identify(body.userId, body.attributes);
return {
statusCode: 200,
body: JSON.stringify({ success: true })
};
} catch (error: any) {
return {
statusCode: 500,
body: JSON.stringify({ error: error.message })
};
}
};Step 4: Kubernetes Deployment
步骤4:Kubernetes部署
yaml
undefinedyaml
undefinedk8s/deployment.yaml
k8s/deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: customerio-service labels: app: customerio-service spec: replicas: 3 selector: matchLabels: app: customerio-service template: metadata: labels: app: customerio-service spec: containers: - name: customerio-service image: gcr.io/PROJECT_ID/customerio-service:latest ports: - containerPort: 8080 env: - name: CUSTOMERIO_SITE_ID valueFrom: secretKeyRef: name: customerio-secrets key: site-id - name: CUSTOMERIO_API_KEY valueFrom: secretKeyRef: name: customerio-secrets key: api-key resources: requests: memory: "128Mi" cpu: "100m" limits: memory: "256Mi" cpu: "200m" readinessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 5 periodSeconds: 10 livenessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 15 periodSeconds: 20
apiVersion: v1
kind: Service
metadata:
name: customerio-service
spec:
selector:
app: customerio-service
ports:
- port: 80
targetPort: 8080
type: ClusterIP
undefinedapiVersion: apps/v1 kind: Deployment metadata: name: customerio-service labels: app: customerio-service spec: replicas: 3 selector: matchLabels: app: customerio-service template: metadata: labels: app: customerio-service spec: containers: - name: customerio-service image: gcr.io/PROJECT_ID/customerio-service:latest ports: - containerPort: 8080 env: - name: CUSTOMERIO_SITE_ID valueFrom: secretKeyRef: name: customerio-secrets key: site-id - name: CUSTOMERIO_API_KEY valueFrom: secretKeyRef: name: customerio-secrets key: api-key resources: requests: memory: "128Mi" cpu: "100m" limits: memory: "256Mi" cpu: "200m" readinessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 5 periodSeconds: 10 livenessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 15 periodSeconds: 20
apiVersion: v1
kind: Service
metadata:
name: customerio-service
spec:
selector:
app: customerio-service
ports:
- port: 80
targetPort: 8080
type: ClusterIP
undefinedStep 5: Health Check Endpoint
步骤5:健康检查端点
typescript
// src/health.ts
import { TrackClient, RegionUS } from '@customerio/track';
interface HealthStatus {
status: 'healthy' | 'degraded' | 'unhealthy';
checks: {
customerio: { status: string; latency?: number };
database?: { status: string; latency?: number };
};
version: string;
uptime: number;
}
const startTime = Date.now();
export async function healthCheck(): Promise<HealthStatus> {
const checks: HealthStatus['checks'] = {
customerio: { status: 'unknown' }
};
// Check Customer.io connectivity
try {
const start = Date.now();
const client = new TrackClient(
process.env.CUSTOMERIO_SITE_ID!,
process.env.CUSTOMERIO_API_KEY!,
{ region: RegionUS }
);
await client.identify('health-check', { _health_check: true });
checks.customerio = {
status: 'healthy',
latency: Date.now() - start
};
} catch (error) {
checks.customerio = { status: 'unhealthy' };
}
const allHealthy = Object.values(checks).every(c => c.status === 'healthy');
return {
status: allHealthy ? 'healthy' : 'degraded',
checks,
version: process.env.APP_VERSION || '1.0.0',
uptime: Date.now() - startTime
};
}typescript
// src/health.ts
import { TrackClient, RegionUS } from '@customerio/track';
interface HealthStatus {
status: 'healthy' | 'degraded' | 'unhealthy';
checks: {
customerio: { status: string; latency?: number };
database?: { status: string; latency?: number };
};
version: string;
uptime: number;
}
const startTime = Date.now();
export async function healthCheck(): Promise<HealthStatus> {
const checks: HealthStatus['checks'] = {
customerio: { status: 'unknown' }
};
// Check Customer.io connectivity
try {
const start = Date.now();
const client = new TrackClient(
process.env.CUSTOMERIO_SITE_ID!,
process.env.CUSTOMERIO_API_KEY!,
{ region: RegionUS }
);
await client.identify('health-check', { _health_check: true });
checks.customerio = {
status: 'healthy',
latency: Date.now() - start
};
} catch (error) {
checks.customerio = { status: 'unhealthy' };
}
const allHealthy = Object.values(checks).every(c => c.status === 'healthy');
return {
status: allHealthy ? 'healthy' : 'degraded',
checks,
version: process.env.APP_VERSION || '1.0.0',
uptime: Date.now() - startTime
};
}Step 6: Blue-Green Deployment
步骤6:蓝绿部署
bash
#!/bin/bashbash
#!/bin/bashscripts/blue-green-deploy.sh
scripts/blue-green-deploy.sh
set -e
CURRENT=$(gcloud run services describe customerio-service --region=us-central1 --format='value(status.traffic[0].revisionName)')
NEW_TAG="v$(date +%Y%m%d%H%M%S)"
echo "Current revision: $CURRENT"
echo "Deploying new revision: $NEW_TAG"
set -e
CURRENT=$(gcloud run services describe customerio-service --region=us-central1 --format='value(status.traffic[0].revisionName)')
NEW_TAG="v$(date +%Y%m%d%H%M%S)"
echo "Current revision: $CURRENT"
echo "Deploying new revision: $NEW_TAG"
Deploy new revision with no traffic
Deploy new revision with no traffic
gcloud run deploy customerio-service
--image gcr.io/$PROJECT_ID/customerio-service:$NEW_TAG
--region us-central1
--no-traffic
--image gcr.io/$PROJECT_ID/customerio-service:$NEW_TAG
--region us-central1
--no-traffic
gcloud run deploy customerio-service
--image gcr.io/$PROJECT_ID/customerio-service:$NEW_TAG
--region us-central1
--no-traffic
--image gcr.io/$PROJECT_ID/customerio-service:$NEW_TAG
--region us-central1
--no-traffic
Run smoke tests against new revision
Run smoke tests against new revision
NEW_URL=$(gcloud run services describe customerio-service --region=us-central1 --format='value(status.url)')
if ! curl -s "$NEW_URL/health" | grep -q '"status":"healthy"'; then
echo "Health check failed, rolling back"
exit 1
fi
NEW_URL=$(gcloud run services describe customerio-service --region=us-central1 --format='value(status.url)')
if ! curl -s "$NEW_URL/health" | grep -q '"status":"healthy"'; then
echo "Health check failed, rolling back"
exit 1
fi
Gradually shift traffic
Gradually shift traffic
echo "Shifting 10% traffic to new revision"
gcloud run services update-traffic customerio-service
--region us-central1
--to-revisions LATEST=10
--region us-central1
--to-revisions LATEST=10
sleep 60
echo "Shifting 50% traffic"
gcloud run services update-traffic customerio-service
--region us-central1
--to-revisions LATEST=50
--region us-central1
--to-revisions LATEST=50
sleep 60
echo "Shifting 100% traffic"
gcloud run services update-traffic customerio-service
--region us-central1
--to-revisions LATEST=100
--region us-central1
--to-revisions LATEST=100
echo "Deployment complete"
undefinedecho "Shifting 10% traffic to new revision"
gcloud run services update-traffic customerio-service
--region us-central1
--to-revisions LATEST=10
--region us-central1
--to-revisions LATEST=10
sleep 60
echo "Shifting 50% traffic"
gcloud run services update-traffic customerio-service
--region us-central1
--to-revisions LATEST=50
--region us-central1
--to-revisions LATEST=50
sleep 60
echo "Shifting 100% traffic"
gcloud run services update-traffic customerio-service
--region us-central1
--to-revisions LATEST=100
--region us-central1
--to-revisions LATEST=100
echo "Deployment complete"
undefinedOutput
输出结果
- Cloud Run deployment workflow
- Vercel serverless deployment
- AWS Lambda configuration
- Kubernetes deployment manifests
- Health check endpoint
- Blue-green deployment script
- Cloud Run部署工作流
- Vercel无服务器部署配置
- AWS Lambda配置
- Kubernetes部署清单
- 健康检查端点代码
- 蓝绿部署脚本
Error Handling
错误处理
| Issue | Solution |
|---|---|
| Secret not found | Verify secret name and permissions |
| Health check failing | Check Customer.io credentials |
| Cold start timeout | Increase memory/timeout limits |
| 问题 | 解决方案 |
|---|---|
| 未找到密钥 | 验证密钥名称和权限 |
| 健康检查失败 | 检查Customer.io凭证 |
| 冷启动超时 | 增加内存/超时限制 |
Resources
参考资源
Next Steps
后续步骤
After deployment, proceed to for webhook handling.
customerio-webhooks-events部署完成后,请继续执行进行Webhook处理。
customerio-webhooks-events