apollo-deploy-integration

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Apollo Deploy Integration

Apollo 集成部署

Overview

概述

Deploy Apollo.io integrations to production environments with proper configuration, health checks, and rollback procedures.
将Apollo.io集成部署到生产环境,包含正确的配置、健康检查和回滚流程。

Deployment Platforms

部署平台

Vercel Deployment

Vercel 部署

json
// vercel.json
{
  "env": {
    "APOLLO_API_KEY": "@apollo-api-key"
  },
  "build": {
    "env": {
      "APOLLO_API_KEY": "@apollo-api-key"
    }
  }
}
bash
undefined
json
// vercel.json
{
  "env": {
    "APOLLO_API_KEY": "@apollo-api-key"
  },
  "build": {
    "env": {
      "APOLLO_API_KEY": "@apollo-api-key"
    }
  }
}
bash
undefined

Add secret to Vercel

向Vercel添加密钥

vercel secrets add apollo-api-key "your-api-key"
vercel secrets add apollo-api-key "your-api-key"

Deploy

部署

vercel --prod
undefined
vercel --prod
undefined

Google Cloud Run

Google Cloud Run

yaml
undefined
yaml
undefined

cloudbuild.yaml

cloudbuild.yaml

steps:
  • name: 'gcr.io/cloud-builders/docker' args: ['build', '-t', 'gcr.io/$PROJECT_ID/apollo-service', '.']
  • name: 'gcr.io/cloud-builders/docker' args: ['push', 'gcr.io/$PROJECT_ID/apollo-service']
  • name: 'gcr.io/cloud-builders/gcloud' args:
    • 'run'
    • 'deploy'
    • 'apollo-service'
    • '--image=gcr.io/$PROJECT_ID/apollo-service'
    • '--platform=managed'
    • '--region=us-central1'
    • '--set-secrets=APOLLO_API_KEY=apollo-api-key:latest'
    • '--allow-unauthenticated'

```bash
steps:
  • name: 'gcr.io/cloud-builders/docker' args: ['build', '-t', 'gcr.io/$PROJECT_ID/apollo-service', '.']
  • name: 'gcr.io/cloud-builders/docker' args: ['push', 'gcr.io/$PROJECT_ID/apollo-service']
  • name: 'gcr.io/cloud-builders/gcloud' args:
    • 'run'
    • 'deploy'
    • 'apollo-service'
    • '--image=gcr.io/$PROJECT_ID/apollo-service'
    • '--platform=managed'
    • '--region=us-central1'
    • '--set-secrets=APOLLO_API_KEY=apollo-api-key:latest'
    • '--allow-unauthenticated'

```bash

Create secret in Google Cloud

在Google Cloud中创建密钥

gcloud secrets create apollo-api-key --data-file=- echo -n "your-api-key" | gcloud secrets versions add apollo-api-key --data-file=-
gcloud secrets create apollo-api-key --data-file=- echo -n "your-api-key" | gcloud secrets versions add apollo-api-key --data-file=-

Grant access to Cloud Run

为Cloud Run授予访问权限

gcloud secrets add-iam-policy-binding apollo-api-key
--member="serviceAccount:YOUR-SA@PROJECT.iam.gserviceaccount.com"
--role="roles/secretmanager.secretAccessor"
undefined
gcloud secrets add-iam-policy-binding apollo-api-key
--member="serviceAccount:YOUR-SA@PROJECT.iam.gserviceaccount.com"
--role="roles/secretmanager.secretAccessor"
undefined

AWS Lambda

AWS Lambda

yaml
undefined
yaml
undefined

serverless.yml

serverless.yml

service: apollo-integration
provider: name: aws runtime: nodejs20.x region: us-east-1 environment: APOLLO_API_KEY: ${ssm:/apollo/api-key~true}
functions: search: handler: src/handlers/search.handler events: - http: path: /api/apollo/search method: post timeout: 30
enrich: handler: src/handlers/enrich.handler events: - http: path: /api/apollo/enrich method: get timeout: 30

```bash
service: apollo-integration
provider: name: aws runtime: nodejs20.x region: us-east-1 environment: APOLLO_API_KEY: ${ssm:/apollo/api-key~true}
functions: search: handler: src/handlers/search.handler events: - http: path: /api/apollo/search method: post timeout: 30
enrich: handler: src/handlers/enrich.handler events: - http: path: /api/apollo/enrich method: get timeout: 30

```bash

Store secret in SSM

将密钥存储到SSM

aws ssm put-parameter
--name "/apollo/api-key"
--type "SecureString"
--value "your-api-key"
aws ssm put-parameter
--name "/apollo/api-key"
--type "SecureString"
--value "your-api-key"

Deploy

部署

serverless deploy --stage production
undefined
serverless deploy --stage production
undefined

Kubernetes

Kubernetes

yaml
undefined
yaml
undefined

k8s/deployment.yaml

k8s/deployment.yaml

apiVersion: apps/v1 kind: Deployment metadata: name: apollo-service spec: replicas: 3 selector: matchLabels: app: apollo-service template: metadata: labels: app: apollo-service spec: containers: - name: apollo-service image: your-registry/apollo-service:latest ports: - containerPort: 3000 env: - name: APOLLO_API_KEY valueFrom: secretKeyRef: name: apollo-secrets key: api-key livenessProbe: httpGet: path: /health port: 3000 initialDelaySeconds: 10 periodSeconds: 10 readinessProbe: httpGet: path: /health/apollo port: 3000 initialDelaySeconds: 5 periodSeconds: 5 resources: requests: memory: "256Mi" cpu: "100m" limits: memory: "512Mi" cpu: "500m"

apiVersion: v1 kind: Secret metadata: name: apollo-secrets type: Opaque stringData: api-key: your-api-key # Use sealed-secrets in production
undefined

apiVersion: apps/v1 kind: Deployment metadata: name: apollo-service spec: replicas: 3 selector: matchLabels: app: apollo-service template: metadata: labels: app: apollo-service spec: containers: - name: apollo-service image: your-registry/apollo-service:latest ports: - containerPort: 3000 env: - name: APOLLO_API_KEY valueFrom: secretKeyRef: name: apollo-secrets key: api-key livenessProbe: httpGet: path: /health port: 3000 initialDelaySeconds: 10 periodSeconds: 10 readinessProbe: httpGet: path: /health/apollo port: 3000 initialDelaySeconds: 5 periodSeconds: 5 resources: requests: memory: "256Mi" cpu: "100m" limits: memory: "512Mi" cpu: "500m"

apiVersion: v1 kind: Secret metadata: name: apollo-secrets type: Opaque stringData: api-key: your-api-key # 生产环境中使用sealed-secrets
undefined

Health Check Endpoints

健康检查端点

typescript
// src/routes/health.ts
import { Router } from 'express';
import { apollo } from '../lib/apollo/client';

const router = Router();

// Basic health check
router.get('/health', (req, res) => {
  res.json({ status: 'ok', timestamp: new Date().toISOString() });
});

// Apollo-specific health check
router.get('/health/apollo', async (req, res) => {
  try {
    const start = Date.now();
    await apollo.healthCheck();
    const latency = Date.now() - start;

    res.json({
      status: 'ok',
      apollo: {
        connected: true,
        latencyMs: latency,
      },
    });
  } catch (error: any) {
    res.status(503).json({
      status: 'degraded',
      apollo: {
        connected: false,
        error: error.message,
      },
    });
  }
});

// Readiness check (for Kubernetes)
router.get('/ready', async (req, res) => {
  try {
    await apollo.healthCheck();
    res.json({ ready: true });
  } catch {
    res.status(503).json({ ready: false });
  }
});

export default router;
typescript
// src/routes/health.ts
import { Router } from 'express';
import { apollo } from '../lib/apollo/client';

const router = Router();

// 基础健康检查
router.get('/health', (req, res) => {
  res.json({ status: 'ok', timestamp: new Date().toISOString() });
});

// Apollo专属健康检查
router.get('/health/apollo', async (req, res) => {
  try {
    const start = Date.now();
    await apollo.healthCheck();
    const latency = Date.now() - start;

    res.json({
      status: 'ok',
      apollo: {
        connected: true,
        latencyMs: latency,
      },
    });
  } catch (error: any) {
    res.status(503).json({
      status: 'degraded',
      apollo: {
        connected: false,
        error: error.message,
      },
    });
  }
});

// 就绪检查(适用于Kubernetes)
router.get('/ready', async (req, res) => {
  try {
    await apollo.healthCheck();
    res.json({ ready: true });
  } catch {
    res.status(503).json({ ready: false });
  }
});

export default router;

Blue-Green Deployment

蓝绿部署

yaml
undefined
yaml
undefined

.github/workflows/blue-green.yml

.github/workflows/blue-green.yml

name: Blue-Green Deploy
on: push: branches: [main]
jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
  - name: Deploy to Green
    run: |
      kubectl apply -f k8s/deployment-green.yaml
      kubectl rollout status deployment/apollo-service-green

  - name: Run smoke tests on Green
    run: |
      GREEN_URL=$(kubectl get svc apollo-service-green -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
      curl -sf "http://$GREEN_URL/health/apollo" || exit 1

  - name: Switch traffic to Green
    if: success()
    run: |
      kubectl patch service apollo-service -p '{"spec":{"selector":{"version":"green"}}}'

  - name: Rollback on failure
    if: failure()
    run: |
      kubectl patch service apollo-service -p '{"spec":{"selector":{"version":"blue"}}}'
undefined
name: Blue-Green Deploy
on: push: branches: [main]
jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
  - name: Deploy to Green
    run: |
      kubectl apply -f k8s/deployment-green.yaml
      kubectl rollout status deployment/apollo-service-green

  - name: Run smoke tests on Green
    run: |
      GREEN_URL=$(kubectl get svc apollo-service-green -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
      curl -sf "http://$GREEN_URL/health/apollo" || exit 1

  - name: Switch traffic to Green
    if: success()
    run: |
      kubectl patch service apollo-service -p '{"spec":{"selector":{"version":"green"}}}'

  - name: Rollback on failure
    if: failure()
    run: |
      kubectl patch service apollo-service -p '{"spec":{"selector":{"version":"blue"}}}'
undefined

Deployment Checklist

部署检查清单

typescript
// scripts/pre-deploy-check.ts
import { apollo } from '../src/lib/apollo/client';

interface Check {
  name: string;
  check: () => Promise<boolean>;
  required: boolean;
}

const checks: Check[] = [
  {
    name: 'API Key Valid',
    check: async () => {
      try {
        await apollo.healthCheck();
        return true;
      } catch {
        return false;
      }
    },
    required: true,
  },
  {
    name: 'Rate Limit Available',
    check: async () => {
      // Check we have rate limit headroom
      const response = await apollo.searchPeople({ per_page: 1 });
      return true; // If we got here, we have capacity
    },
    required: false,
  },
  {
    name: 'Search Working',
    check: async () => {
      const result = await apollo.searchPeople({
        q_organization_domains: ['apollo.io'],
        per_page: 1,
      });
      return result.people.length > 0;
    },
    required: true,
  },
];

async function runChecks() {
  console.log('Running pre-deployment checks...\n');

  let allPassed = true;

  for (const { name, check, required } of checks) {
    try {
      const passed = await check();
      const status = passed ? 'PASS' : required ? 'FAIL' : 'WARN';
      console.log(`[${status}] ${name}`);

      if (!passed && required) {
        allPassed = false;
      }
    } catch (error: any) {
      console.log(`[FAIL] ${name}: ${error.message}`);
      if (required) {
        allPassed = false;
      }
    }
  }

  if (!allPassed) {
    console.error('\nPre-deployment checks failed. Aborting.');
    process.exit(1);
  }

  console.log('\nAll checks passed. Ready to deploy.');
}

runChecks();
typescript
// scripts/pre-deploy-check.ts
import { apollo } from '../src/lib/apollo/client';

interface Check {
  name: string;
  check: () => Promise<boolean>;
  required: boolean;
}

const checks: Check[] = [
  {
    name: 'API Key Valid',
    check: async () => {
      try {
        await apollo.healthCheck();
        return true;
      } catch {
        return false;
      }
    },
    required: true,
  },
  {
    name: 'Rate Limit Available',
    check: async () => {
      // 检查是否有剩余的速率限制
      const response = await apollo.searchPeople({ per_page: 1 });
      return true; // 如果执行到这里,说明有可用容量
    },
    required: false,
  },
  {
    name: 'Search Working',
    check: async () => {
      const result = await apollo.searchPeople({
        q_organization_domains: ['apollo.io'],
        per_page: 1,
      });
      return result.people.length > 0;
    },
    required: true,
  },
];

async function runChecks() {
  console.log('Running pre-deployment checks...\n');

  let allPassed = true;

  for (const { name, check, required } of checks) {
    try {
      const passed = await check();
      const status = passed ? 'PASS' : required ? 'FAIL' : 'WARN';
      console.log(`[${status}] ${name}`);

      if (!passed && required) {
        allPassed = false;
      }
    } catch (error: any) {
      console.log(`[FAIL] ${name}: ${error.message}`);
      if (required) {
        allPassed = false;
      }
    }
  }

  if (!allPassed) {
    console.error('\nPre-deployment checks failed. Aborting.');
    process.exit(1);
  }

  console.log('\nAll checks passed. Ready to deploy.');
}

runChecks();

Environment Configuration

环境配置

typescript
// src/config/environments.ts
interface EnvironmentConfig {
  apollo: {
    apiKey: string;
    rateLimit: number;
    timeout: number;
  };
  features: {
    enrichment: boolean;
    sequences: boolean;
  };
}

const configs: Record<string, EnvironmentConfig> = {
  development: {
    apollo: {
      apiKey: process.env.APOLLO_API_KEY_DEV!,
      rateLimit: 10,
      timeout: 30000,
    },
    features: {
      enrichment: true,
      sequences: false,
    },
  },
  staging: {
    apollo: {
      apiKey: process.env.APOLLO_API_KEY_STAGING!,
      rateLimit: 50,
      timeout: 30000,
    },
    features: {
      enrichment: true,
      sequences: true,
    },
  },
  production: {
    apollo: {
      apiKey: process.env.APOLLO_API_KEY!,
      rateLimit: 90,
      timeout: 30000,
    },
    features: {
      enrichment: true,
      sequences: true,
    },
  },
};

export function getConfig(): EnvironmentConfig {
  const env = process.env.NODE_ENV || 'development';
  return configs[env] || configs.development;
}
typescript
// src/config/environments.ts
interface EnvironmentConfig {
  apollo: {
    apiKey: string;
    rateLimit: number;
    timeout: number;
  };
  features: {
    enrichment: boolean;
    sequences: boolean;
  };
}

const configs: Record<string, EnvironmentConfig> = {
  development: {
    apollo: {
      apiKey: process.env.APOLLO_API_KEY_DEV!,
      rateLimit: 10,
      timeout: 30000,
    },
    features: {
      enrichment: true,
      sequences: false,
    },
  },
  staging: {
    apollo: {
      apiKey: process.env.APOLLO_API_KEY_STAGING!,
      rateLimit: 50,
      timeout: 30000,
    },
    features: {
      enrichment: true,
      sequences: true,
    },
  },
  production: {
    apollo: {
      apiKey: process.env.APOLLO_API_KEY!,
      rateLimit: 90,
      timeout: 30000,
    },
    features: {
      enrichment: true,
      sequences: true,
    },
  },
};

export function getConfig(): EnvironmentConfig {
  const env = process.env.NODE_ENV || 'development';
  return configs[env] || configs.development;
}

Output

输出内容

  • Platform-specific deployment configs (Vercel, GCP, AWS, K8s)
  • Health check endpoints
  • Blue-green deployment workflow
  • Pre-deployment validation
  • Environment configuration
  • 各平台专属的部署配置(Vercel、GCP、AWS、K8s)
  • 健康检查端点
  • 蓝绿部署工作流
  • 部署前验证
  • 环境配置

Error Handling

错误处理

IssueResolution
Secret not foundVerify secret configuration
Health check failsCheck Apollo connectivity
Deployment timeoutIncrease timeout, check resources
Traffic not switchingVerify service selector
问题解决方法
密钥未找到验证密钥配置
健康检查失败检查Apollo连接状态
部署超时增加超时时间,检查资源配置
流量未切换验证服务选择器配置

Resources

参考资源

Next Steps

下一步

Proceed to
apollo-webhooks-events
for webhook implementation.
继续查看
apollo-webhooks-events
以实现Webhook功能。