Task definition & konfigurasi
Task definition adalah tempat semua keputusan operasional bertemu. Ia versi-berversi dan tidak bisa diubah — setiap perubahan menghasilkan revisi baru, yang membuat rollback jadi mudah.
Intisari
environmentuntuk nilai biasa;secretsuntuk yang rahasia — nilainya tidak pernah tampil di konsol.- Log diarahkan ke CloudWatch lewat driver
awslogs, denganLOG_CHANNEL=stderrdi Laravel. healthCheckdi dalam kontainer berbeda dengan health check ALB — keduanya perlu ada.stopTimeoutharus lebih panjang daripada job antrean terlama.- Setiap perubahan menghasilkan revisi baru; rollback berarti menunjuk revisi sebelumnya.
Bentuk task definition
{
"family": "portal-web",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "1024",
"memory": "2048",
"runtimePlatform": { "cpuArchitecture": "X86_64", "operatingSystemFamily": "LINUX" },
"executionRoleArn": "arn:aws:iam::123456789012:role/portal-execution",
"taskRoleArn": "arn:aws:iam::123456789012:role/portal-task",
"containerDefinitions": [
{
"name": "app",
"image": "123456789012.dkr.ecr.ap-southeast-1.amazonaws.com/portal:a1b2c3d",
"essential": true,
"portMappings": [{ "containerPort": 8000, "protocol": "tcp" }],
"environment": [
{ "name": "APP_ENV", "value": "production" },
{ "name": "APP_DEBUG", "value": "false" },
{ "name": "APP_URL", "value": "https://portal.example.com" },
{ "name": "LOG_CHANNEL", "value": "stderr" },
{ "name": "LOG_LEVEL", "value": "info" },
{ "name": "CACHE_STORE", "value": "redis" },
{ "name": "SESSION_DRIVER", "value": "redis" },
{ "name": "QUEUE_CONNECTION","value": "sqs" },
{ "name": "FILESYSTEM_DISK", "value": "s3" },
{ "name": "OCTANE_SERVER", "value": "frankenphp" }
],
"secrets": [
{ "name": "APP_KEY", "valueFrom": "arn:aws:secretsmanager:...:portal/app:APP_KEY::" },
{ "name": "DB_PASSWORD", "valueFrom": "arn:aws:secretsmanager:...:portal/db:password::" }
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/portal-web",
"awslogs-region": "ap-southeast-1",
"awslogs-stream-prefix": "app",
"mode": "non-blocking",
"max-buffer-size": "4m"
}
},
"healthCheck": {
"command": ["CMD-SHELL", "curl -fsS http://127.0.0.1:8000/up || exit 1"],
"interval": 15, "timeout": 3, "retries": 3, "startPeriod": 30
},
"stopTimeout": 60,
"readonlyRootFilesystem": true,
"linuxParameters": { "initProcessEnabled": true }
}
],
"volumes": [{ "name": "tmp", "host": {} }],
"mountPoints": [{ "sourceVolume": "tmp", "containerPath": "/app/storage/framework" }]
}
environment versus secrets
environment | secrets | |
|---|---|---|
| Nilai tersimpan di | Task definition itu sendiri | Secrets Manager / Parameter Store |
| Terlihat di konsol | Ya | Tidak |
| Terlihat di CloudTrail | Ya | Hanya ARN-nya |
| Bisa dirotasi tanpa deploy | Tidak | Ya (perlu task baru untuk membacanya) |
| Untuk | APP_ENV, URL, nama bucket | APP_KEY, password, token |
Satu password database di dalam environment berarti password itu tersimpan permanen di
task definition — terlihat oleh siapa pun yang punya akses baca ke ECS, dan ikut tercatat di setiap
revisi selamanya. Menghapusnya nanti tidak menghapus revisi lama. Perlakukan aturan ini sebagai mutlak.
stopTimeout: setelan yang menyelamatkan pekerjaan
"stopTimeout": 120 // maksimum yang diizinkan Fargate
Saat ECS menghentikan task, ia mengirim SIGTERM, menunggu selama stopTimeout, lalu
mengirim SIGKILL. Laravel menangani SIGTERM dengan benar: queue:work
menyelesaikan job yang sedang diproses lalu berhenti; Octane menyelesaikan permintaan yang sedang berjalan.
| Service | stopTimeout | Alasan |
|---|---|---|
| Web | 30–60 detik | Permintaan HTTP selesai dalam hitungan detik |
| Worker antrean | 120 detik (maksimum) | Job harus sempat selesai |
| Penjadwal | 30 detik | Hanya mengantre |
Kalau job antreanmu bisa berjalan lebih dari 120 detik, batas Fargate akan memotongnya. Solusinya bukan menaikkan timeout — melainkan memecah job jadi potongan yang lebih pendek, atau membuatnya bisa dilanjutkan dari titik terakhir. Job berdurasi sepuluh menit di lingkungan yang bisa mengganti task kapan saja adalah rancangan yang rapuh, dengan atau tanpa timeout.
Health check: dua lapis yang berbeda
| Health check kontainer | Health check ALB | |
|---|---|---|
| Dijalankan oleh | Agen ECS, dari dalam kontainer | ALB, dari luar |
| Menjawab | "Prosesnya hidup?" | "Boleh dikirimi lalu lintas?" |
| Kalau gagal | Task diganti | Task dikeluarkan dari rotasi |
// bootstrap/app.php — endpoint /up bawaan Laravel
->withRouting(
web: __DIR__.'/../routes/web.php',
health: '/up',
)
Endpoint health check tidak boleh menyentuh database. Kalau ia melakukannya, satu gangguan database
akan membuat semua task dianggap tidak sehat, lalu ECS mengganti semuanya sekaligus — mengubah
gangguan sebagian jadi kegagalan total. Kalau kamu memang butuh pemeriksaan mendalam, sediakan endpoint
terpisah (/health/deep) yang dipantau alarm, bukan yang dipakai load balancer.
Logging
"mode": "non-blocking",
"max-buffer-size": "4m"
Dengan mode blocking (default lama), aplikasimu ikut melambat ketika CloudWatch sedang lambat —
lonjakan log bisa menjadi lonjakan latensi. Mode non-blocking memakai buffer; kalau penuh, log
dibuang alih-alih menahan aplikasi. Untuk log aplikasi, itu pertukaran yang tepat.
// config/logging.php — log JSON supaya bisa diurai Logs Insights
'stderr' => [
'driver' => 'monolog',
'handler' => StreamHandler::class,
'formatter' => JsonFormatter::class,
'with' => ['stream' => 'php://stderr'],
],
Revisi dan rollback
aws ecs register-task-definition --cli-input-json file://task.json
aws ecs update-service --cluster portal --service portal-web \
--task-definition portal-web:47
# rollback: tunjuk revisi sebelumnya
aws ecs update-service --cluster portal --service portal-web \
--task-definition portal-web:46
Inilah alasan tag image harus berupa SHA commit. Revisi 46 menunjuk image dengan tag
a1b2c3d; revisi 47 menunjuk e4f5g6h. Rollback berarti kembali ke image yang persis
sama dengan yang tadi berjalan. Kalau keduanya menunjuk latest, rollback tidak mengembalikan apa
pun.
Latihan: buat task definition untuk service worker dengan stopTimeout: 120, jalankan job
yang butuh 30 detik, lalu hentikan task-nya di tengah jalan. Periksa di log bahwa job itu selesai sebelum
prosesnya berhenti.
Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.