一键导入
aws-beanstalk-expert
Expert knowledge for deploying, managing, and troubleshooting AWS Elastic Beanstalk applications with production best practices
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Expert knowledge for deploying, managing, and troubleshooting AWS Elastic Beanstalk applications with production best practices
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when creating or publishing Claude Code hooks - covers executable format, event types, JSON I/O, exit codes, security requirements, and PRPM package structure
Use when creating Agent Skills packages (SKILL.md format) for Codex CLI, GitHub Copilot, or Amp - provides the agentskills.io specification with frontmatter constraints, directory structure, and validation rules
Semantic code search using natural language queries. Use when users ask "where is X implemented", "how does Y work", "find the logic for Z", or need to locate code by concept rather than exact text. Returns file paths with line numbers and code snippets.
Expert guidance for creating Claude Code slash commands with correct frontmatter, structure, and best practices
Use when creating OpenCode agents - provides markdown format with YAML frontmatter, mode/tools/permission configuration, and best practices for specialized AI assistants
Use when creating or fixing .claude/rules/ files - provides correct paths frontmatter (not globs), glob patterns, and avoids Cursor-specific fields like alwaysApply
| name | aws-beanstalk-expert |
| description | Expert knowledge for deploying, managing, and troubleshooting AWS Elastic Beanstalk applications with production best practices |
You are an AWS Elastic Beanstalk expert with deep knowledge of production deployments, infrastructure as code (Pulumi), CI/CD pipelines, and troubleshooting. You help developers deploy robust, scalable applications on Elastic Beanstalk.
Architecture Understanding:
Key Components:
Infrastructure as Code with Pulumi:
import * as aws from "@pulumi/aws";
import * as pulumi from "@pulumi/pulumi";
// Best Practice: Separate VPC for Beanstalk
const vpc = new aws.ec2.Vpc("app-vpc", {
cidrBlock: "10.0.0.0/16",
enableDnsHostnames: true,
enableDnsSupport: true,
});
// Best Practice: Security groups with minimal permissions
const ebSecurityGroup = new aws.ec2.SecurityGroup("eb-sg", {
vpcId: vpc.id,
ingress: [
{
protocol: "tcp",
fromPort: 8080,
toPort: 8080,
securityGroups: [albSecurityGroup.id], // Only from ALB
},
],
egress: [
{
protocol: "-1",
fromPort: 0,
toPort: 0,
cidrBlocks: ["0.0.0.0/0"],
},
],
});
// Best Practice: Application with versioning
const app = new aws.elasticbeanstalk.Application("app", {
description: "Production application",
appversionLifecycle: {
serviceRole: serviceRole.arn,
maxCount: 10, // Keep last 10 versions
deleteSourceFromS3: true,
},
});
// Best Practice: Environment with all production settings
const environment = new aws.elasticbeanstalk.Environment("app-env", {
application: app.name,
solutionStackName: "64bit Amazon Linux 2023 v6.6.6 running Node.js 20", // Always use latest available
settings: [
// Instance configuration
{
namespace: "aws:autoscaling:launchconfiguration",
name: "InstanceType",
value: "t3.micro",
},
{
namespace: "aws:autoscaling:launchconfiguration",
name: "IamInstanceProfile",
value: instanceProfile.name,
},
// Auto-scaling
{
namespace: "aws:autoscaling:asg",
name: "MinSize",
value: "1",
},
{
namespace: "aws:autoscaling:asg",
name: "MaxSize",
value: "4",
},
// Load balancer
{
namespace: "aws:elasticbeanstalk:environment",
name: "LoadBalancerType",
value: "application",
},
// Health checks
{
namespace: "aws:elasticbeanstalk:application",
name: "Application Healthcheck URL",
value: "/health",
},
// Environment variables (encrypted)
{
namespace: "aws:elasticbeanstalk:application:environment",
name: "NODE_ENV",
value: "production",
},
{
namespace: "aws:elasticbeanstalk:application:environment",
name: "DATABASE_URL",
value: databaseUrl,
},
// VPC settings
{
namespace: "aws:ec2:vpc",
name: "VPCId",
value: vpc.id,
},
{
namespace: "aws:ec2:vpc",
name: "Subnets",
value: pulumi.all(privateSubnets.map(s => s.id)).apply(ids => ids.join(",")),
},
],
});
GitHub Actions Deployment with Edge Case Handling:
name: Deploy to Elastic Beanstalk
on:
push:
branches: [main]
workflow_dispatch:
env:
AWS_REGION: us-west-2
jobs:
deploy:
runs-on: ubuntu-latest
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true # Prevent concurrent deployments
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
# CRITICAL: Check environment health before deploying
- name: Check environment status
run: |
ENV_STATUS=$(aws elasticbeanstalk describe-environments \
--environment-names ${{ env.EB_ENVIRONMENT_NAME }} \
--query "Environments[0].Status" --output text)
if [ "$ENV_STATUS" != "Ready" ]; then
echo "Environment not ready. Status: $ENV_STATUS"
exit 1
fi
- name: Build application
run: |
npm ci
npm run build
npm prune --production # Remove dev dependencies
# Create deployment package
zip -r deploy.zip . \
-x "*.git*" \
-x "node_modules/.*" \
-x "*.md" \
-x ".github/*"
- name: Upload to S3
run: |
VERSION_LABEL="v${{ github.run_number }}-${{ github.sha }}"
aws s3 cp deploy.zip s3://${{ env.S3_BUCKET }}/deployments/${VERSION_LABEL}.zip
- name: Create application version
run: |
VERSION_LABEL="v${{ github.run_number }}-${{ github.sha }}"
aws elasticbeanstalk create-application-version \
--application-name ${{ env.EB_APP_NAME }} \
--version-label ${VERSION_LABEL} \
--source-bundle S3Bucket="${{ env.S3_BUCKET }}",S3Key="deployments/${VERSION_LABEL}.zip" \
--description "Deployed from GitHub Actions run ${{ github.run_number }}"
- name: Deploy to environment
run: |
VERSION_LABEL="v${{ github.run_number }}-${{ github.sha }}"
aws elasticbeanstalk update-environment \
--application-name ${{ env.EB_APP_NAME }} \
--environment-name ${{ env.EB_ENVIRONMENT_NAME }} \
--version-label ${VERSION_LABEL}
# CRITICAL: Wait for deployment to complete
- name: Wait for deployment
run: |
for i in {1..60}; do
STATUS=$(aws elasticbeanstalk describe-environments \
--environment-names ${{ env.EB_ENVIRONMENT_NAME }} \
--query "Environments[0].Status" --output text)
HEALTH=$(aws elasticbeanstalk describe-environments \
--environment-names ${{ env.EB_ENVIRONMENT_NAME }} \
--query "Environments[0].Health" --output text)
echo "Deployment status: $STATUS, Health: $HEALTH (attempt $i/60)"
if [ "$STATUS" = "Ready" ] && [ "$HEALTH" = "Green" ]; then
echo "✅ Deployment successful!"
exit 0
fi
if [ "$HEALTH" = "Red" ]; then
echo "❌ Deployment failed - environment unhealthy"
exit 1
fi
sleep 10
done
echo "❌ Deployment timed out after 10 minutes"
exit 1
# CRITICAL: Verify health endpoint
- name: Verify deployment
run: |
ENDPOINT=$(aws elasticbeanstalk describe-environments \
--environment-names ${{ env.EB_ENVIRONMENT_NAME }} \
--query "Environments[0].CNAME" --output text)
for i in {1..30}; do
if curl -f "http://${ENDPOINT}/health" >/dev/null 2>&1; then
echo "✅ Health check passed"
exit 0
fi
echo "⏳ Waiting for health check... ($i/30)"
sleep 10
done
echo "❌ Health check failed"
exit 1
.ebextensions/ Configuration:
# .ebextensions/01-nginx.config
# Configure nginx settings
files:
"/etc/nginx/conf.d/proxy.conf":
mode: "000644"
owner: root
group: root
content: |
client_max_body_size 50M;
proxy_connect_timeout 600s;
proxy_send_timeout 600s;
proxy_read_timeout 600s;
# .ebextensions/02-environment.config
# Set environment-specific configuration
option_settings:
aws:elasticbeanstalk:application:environment:
NODE_ENV: production
LOG_LEVEL: info
aws:elasticbeanstalk:cloudwatch:logs:
StreamLogs: true
DeleteOnTerminate: false
RetentionInDays: 7
aws:elasticbeanstalk:healthreporting:system:
SystemType: enhanced
# .ebextensions/03-cloudwatch.config
# Enhanced CloudWatch monitoring
Resources:
AWSEBCloudwatchAlarmHigh:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmDescription: "Trigger if CPU > 80%"
MetricName: CPUUtilization
Namespace: AWS/EC2
Statistic: Average
Period: 300
EvaluationPeriods: 2
Threshold: 80
ComparisonOperator: GreaterThanThreshold
.platform/ Configuration (Amazon Linux 2):
# .platform/nginx/conf.d/custom.conf
# Custom nginx configuration
client_max_body_size 50M;
# .platform/hooks/predeploy/01-install-dependencies.sh
#!/bin/bash
# Run before deployment
npm ci --production
# .platform/hooks/postdeploy/01-run-migrations.sh
#!/bin/bash
# Run after deployment
cd /var/app/current
npm run migrate
Common Issues and Solutions:
Issue: Environment stuck in "Updating"
# Solution: Check events
aws elasticbeanstalk describe-events \
--environment-name your-env \
--max-records 50 \
--query 'Events[*].[EventDate,Severity,Message]' \
--output table
# If truly stuck, abort and rollback
aws elasticbeanstalk abort-environment-update \
--environment-name your-env
Issue: Application not receiving traffic
# Check health
aws elasticbeanstalk describe-environment-health \
--environment-name your-env \
--attribute-names All
# Check instance health
aws elasticbeanstalk describe-instances-health \
--environment-name your-env
Issue: High latency or errors
# Get enhanced health data
aws elasticbeanstalk describe-environment-health \
--environment-name your-env \
--attribute-names All
# Check CloudWatch logs
aws logs tail /aws/elasticbeanstalk/your-env/var/log/eb-engine.log --follow
# SSH into instance (if configured)
eb ssh your-env
# Check application logs
tail -f /var/app/current/logs/*.log
Issue: Deployment failed
# Get last 100 events
aws elasticbeanstalk describe-events \
--environment-name your-env \
--max-records 100 \
--severity ERROR
# Check deployment logs
aws logs tail /aws/elasticbeanstalk/your-env/var/log/eb-activity.log --follow
Strategies:
Example Auto-scaling Configuration:
// Scale based on CPU
{
namespace: "aws:autoscaling:trigger",
name: "MeasureName",
value: "CPUUtilization",
},
{
namespace: "aws:autoscaling:trigger",
name: "Statistic",
value: "Average",
},
{
namespace: "aws:autoscaling:trigger",
name: "Unit",
value: "Percent",
},
{
namespace: "aws:autoscaling:trigger",
name: "UpperThreshold",
value: "70", // Scale up at 70% CPU
},
{
namespace: "aws:autoscaling:trigger",
name: "LowerThreshold",
value: "20", // Scale down at 20% CPU
},
Checklist:
CloudWatch Metrics to Monitor:
CloudWatch Alarms Example:
const highCpuAlarm = new aws.cloudwatch.MetricAlarm("high-cpu", {
comparisonOperator: "GreaterThanThreshold",
evaluationPeriods: 2,
metricName: "CPUUtilization",
namespace: "AWS/EC2",
period: 300,
statistic: "Average",
threshold: 80,
alarmDescription: "Alert if CPU > 80% for 10 minutes",
alarmActions: [snsTopicArn],
});
Use this expertise when:
Before deploying to production:
# Create new environment (green)
aws elasticbeanstalk create-environment \
--application-name my-app \
--environment-name my-app-green \
--version-label new-version \
--cname-prefix my-app-green
# Wait for green to be healthy
# Test green environment
# Swap CNAMEs (blue <-> green)
aws elasticbeanstalk swap-environment-cnames \
--source-environment-name my-app-blue \
--destination-environment-name my-app-green
# Monitor, then terminate old environment
aws elasticbeanstalk terminate-environment \
--environment-name my-app-blue
// Run migrations in platform hook
// .platform/hooks/postdeploy/01-migrate.sh
#!/bin/bash
cd /var/app/current
# Run migrations with lock to prevent concurrent runs
flock -n /tmp/migrate.lock npm run migrate || {
echo "Migration already running or failed to acquire lock"
exit 0
}
This skill provides battle-tested patterns for production Elastic Beanstalk deployments.
Error: "Invalid option specification - UpdateLevel required"
When enabling managed actions, you MUST also specify UpdateLevel:
// Managed updates - BOTH required
{
namespace: "aws:elasticbeanstalk:managedactions",
name: "ManagedActionsEnabled",
value: "true",
},
{
namespace: "aws:elasticbeanstalk:managedactions",
name: "PreferredStartTime",
value: "Sun:03:00",
},
{
namespace: "aws:elasticbeanstalk:managedactions:platformupdate",
name: "UpdateLevel",
value: "minor", // REQUIRED: "minor" or "patch"
},
Error: "No Solution Stack named 'X' found"
Solution stack names change frequently. Always verify the exact name:
# List available Node.js stacks
aws elasticbeanstalk list-available-solution-stacks \
--region us-west-2 \
--query 'SolutionStacks[?contains(@, `Node.js`) && contains(@, `Amazon Linux 2023`)]' \
--output text
# Current stacks (as of Oct 2025):
# - 64bit Amazon Linux 2023 v6.6.6 running Node.js 20
# - 64bit Amazon Linux 2023 v6.6.6 running Node.js 22
Error: "Unknown or duplicate parameter: NodeVersion" or "NodeCommand"
Amazon Linux 2023 platforms do NOT support the aws:elasticbeanstalk:container:nodejs namespace at all. Neither NodeVersion nor NodeCommand work:
// ❌ WRONG - aws:elasticbeanstalk:container:nodejs namespace not supported in AL2023
{
namespace: "aws:elasticbeanstalk:container:nodejs",
name: "NodeVersion",
value: "20.x",
}
{
namespace: "aws:elasticbeanstalk:container:nodejs",
name: "NodeCommand",
value: "npm start",
}
// ✅ CORRECT - version specified in solution stack, start command in package.json
solutionStackName: "64bit Amazon Linux 2023 v6.6.6 running Node.js 20"
// In your package.json:
{
"scripts": {
"start": "node server.js"
}
}
Why: Amazon Linux 2023 uses a different platform architecture. The app starts automatically using the start script from package.json. You don't need to configure NodeCommand.
Error: "cannot use immediate apply method for static parameter"
Static parameters like shared_preload_libraries cannot be modified after creation.
Solutions:
const parameterGroup = new aws.rds.ParameterGroup(`${name}-db-params`, {
family: "postgres17",
parameters: [
// Only dynamic parameters
{ name: "log_connections", value: "1" },
{ name: "log_disconnections", value: "1" },
{ name: "log_duration", value: "1" },
// DON'T include: shared_preload_libraries (static, requires reboot)
],
});
Error: "DBParameterGroupFamily mismatch"
PostgreSQL engine version MUST match parameter group family:
postgres17 → engineVersion: 17.xpostgres16 → engineVersion: 16.xpostgres15 → engineVersion: 15.xError: "MasterUserPassword is not a valid password"
RDS disallows these characters: /, @, ", space
# Generate valid password
openssl rand -base64 32 | tr -d '/@ "' | cut -c1-32
Error: "The key pair 'X' does not exist"
Key pairs are region-specific:
# List keys
aws ec2 describe-key-pairs --region us-west-2
# Create new
aws ec2 create-key-pair --key-name prpm-prod-bastion --region us-west-2 \
--query 'KeyMaterial' --output text > ~/.ssh/prpm-prod-bastion.pem
chmod 400 ~/.ssh/prpm-prod-bastion.pem
Error: "CNAME is not permitted at apex in zone"
You cannot create CNAME records at the domain apex (root domain). Use A record with ALIAS instead:
// Check if apex domain
const domainParts = domainName.split(".");
const baseDomain = domainParts.slice(-2).join(".");
const isApexDomain = domainName === baseDomain;
if (isApexDomain) {
// ✅ A record with ALIAS for apex (e.g., prpm.dev)
new aws.route53.Record(`dns`, {
name: domainName,
type: "A",
zoneId: hostedZone.zoneId,
aliases: [{
name: beanstalkEnv.cname,
zoneId: "Z1BKCTXD74EZPE", // ELB zone for us-west-2
evaluateTargetHealth: true,
}],
});
} else {
// ✅ CNAME for subdomain (e.g., api.prpm.dev)
new aws.route53.Record(`dns`, {
name: domainName,
type: "CNAME",
zoneId: hostedZone.zoneId,
records: [beanstalkEnv.cname],
ttl: 300,
});
}
Elastic Beanstalk Hosted Zone IDs by Region:
Important: Use Elastic Beanstalk zone IDs (not generic ELB zone IDs) when creating Route53 aliases to Beanstalk environments.
ACM certificate MUST be created and validated BEFORE Beanstalk environment:
// 1. Create cert
const cert = new aws.acm.Certificate(`cert`, {
domainName: "prpm.dev",
validationMethod: "DNS",
});
// 2. Validate via Route53 (automatic)
const validation = new aws.route53.Record(`cert-validation`, {
name: cert.domainValidationOptions[0].resourceRecordName,
type: cert.domainValidationOptions[0].resourceRecordType,
zoneId: hostedZone.zoneId,
records: [cert.domainValidationOptions[0].resourceRecordValue],
});
// 3. Wait for validation
const validated = new aws.acm.CertificateValidation(`cert-complete`, {
certificateArn: cert.arn,
validationRecordFqdns: [validation.fqdn],
});
// 4. Configure HTTPS listener
{
namespace: "aws:elbv2:listener:443",
name: "Protocol",
value: "HTTPS",
},
{
namespace: "aws:elbv2:listener:443",
name: "SSLCertificateArns",
value: validated.certificateArn,
},
/, @, ", or space in database passwords