Excellent — you’re asking the right performance question 👍
Let’s analyze your setup precisely:

💻 Your environment
- EC2 instance:
t3.small- vCPU: 2 (shared, burstable)
- RAM: 2 GB
- Baseline CPU credit: ~20–30% of one core continuous, bursts to 2 cores briefly
- Containers:
- Ghost (Node.js, web server)
- MySQL (database)
- PHP (likely some other service or API)
⚙️ Short answer
👉 Yes — there is CPU contention (“CPU競争”) possible,
because you have three active services sharing only two vCPUs, and one of them (MySQL) tends to be CPU hungry at times.
However, whether this hurts performance depends on actual traffic load and how Docker is configured.
🔍 Details
1. t3.small burstable CPU model
t3.small is part of AWS’s burstable instance family (T3).
- You get CPU credits accumulated during idle periods.
- When you burst (e.g., heavy load from Ghost or MySQL), the CPU can temporarily go to 100% on both cores.
- If the CPU credits run out, AWS throttles CPU to baseline (~20–30% of one core).
You can check credits with:
aws cloudwatch get-metric-statistics \
--namespace AWS/EC2 \
--metric-name CPUCreditBalance \
--dimensions Name=InstanceId,Value=i-xxxxxxx \ --statistics Average --period 300 --start-time $(date -d '-1 hour' --utc +%FT%TZ) --end-time $(date --utc +%FT%TZ)
2. Docker CPU sharing
By default, Docker containers share CPU equally — there’s no isolation unless you set limits.
That means:
- MySQL, PHP, and Ghost all fight for the same 2 cores.
- If one (like MySQL) spikes CPU usage, Ghost and PHP can lag.
You can check with:
docker stats
3. Practical performance impact
| Load | Impact |
|---|---|
| Low (few users) | Fine — t3.small handles it easily |
| Medium (hundreds of views/day) | Slight slowdown under bursts, but still ok |
| High (thousands of requests or background jobs) | Ghost and MySQL will compete → response delays, throttling risk |
✅ Recommendations
Option 1 — Keep t3.small but set Docker CPU limits
To prevent one container from starving the others:
docker run --cpus=".7" ghost:5-alpinedocker run --cpus=".7" mysql:8docker run --cpus=".6" php:8
Or in docker-compose.yml:
services:
ghost:
image: ghost:5-alpine
deploy:
resources:
limits:
cpus: '0.7'
mysql:
image: mysql:8
deploy:
resources:
limits:
cpus: '0.7'
php:
image: php:8
deploy:
resources:
limits:
cpus: '0.6'
This ensures fair CPU sharing.
Option 2 — Use t3.medium or t3a.medium
If your Ghost or MySQL usage is active, consider upgrading:
| Instance | vCPU | RAM | Notes |
|---|---|---|---|
| t3.small | 2 | 2 GB | Burstable, limited credits |
| t3.medium | 2 | 4 GB | More memory, better for MySQL |
| t3a.medium | 2 | 4 GB | Cheaper, same performance |
| t4g.small | 2 | 2 GB | ARM-based, lower cost but same burst model |
With 4 GB RAM and full credits, Ghost + MySQL run very smoothly.
Option 3 — Optimize each container
🟢 Ghost
- Use
ghost:5-alpine(lightweight) - Enable caching on Nginx/CDN
- Reduce image size (no heavy processing)
🟢 MySQL
- Disable binary logs if not needed
- Tune
innodb_buffer_pool_sizeto ~512 MB–1 GB max - Mount
/var/lib/mysqlon SSD storage
🟢 PHP
- Use PHP-FPM with
pm = ondemand - Limit
pm.max_childrento 2–3 - Use
opcache.enable=1
Option 4 — Monitor and adjust
Use:
docker stats
htop
iostat
to observe real CPU usage and throttling.
If CPU stays near 100% or Ghost responses slow under burst → upgrade.
⚡️ Summary Table
| Factor | Status on t3.small | Solution |
|---|---|---|
| 2 vCPU | Shared among 3 containers → CPU競争あり | Set Docker CPU limits |
| Burstable CPU | Yes, throttles after credits exhausted | Monitor credits or upgrade |
| Memory | 2 GB (tight for MySQL + PHP + Ghost) | Upgrade to 4 GB |
| Best container combo | Ghost + MySQL only | Move PHP elsewhere if possible |
💡 Recommendation
If your setup is personal / low traffic, keep t3.small but:
- Add CPU limits per container
- Enable Cloudflare or CDN cache for Ghost
- Use swap file (512–1024 MB) for safety
If you expect medium traffic (hundreds+ users/day):
Move to t3a.medium (2 vCPU / 4 GB RAM, ~$0.038/hr) → much smoother, no throttling issues.