← Semua pembelajaran / Laravel Nol → Enterprise
Fase 9 · Deploy di AWS

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

  • environment untuk nilai biasa; secrets untuk yang rahasia — nilainya tidak pernah tampil di konsol.
  • Log diarahkan ke CloudWatch lewat driver awslogs, dengan LOG_CHANNEL=stderr di Laravel.
  • healthCheck di dalam kontainer berbeda dengan health check ALB — keduanya perlu ada.
  • stopTimeout harus 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

environmentsecrets
Nilai tersimpan diTask definition itu sendiriSecrets Manager / Parameter Store
Terlihat di konsolYaTidak
Terlihat di CloudTrailYaHanya ARN-nya
Bisa dirotasi tanpa deployTidakYa (perlu task baru untuk membacanya)
UntukAPP_ENV, URL, nama bucketAPP_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.

ServicestopTimeoutAlasan
Web30–60 detikPermintaan HTTP selesai dalam hitungan detik
Worker antrean120 detik (maksimum)Job harus sempat selesai
Penjadwal30 detikHanya 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 kontainerHealth check ALB
Dijalankan olehAgen ECS, dari dalam kontainerALB, dari luar
Menjawab"Prosesnya hidup?""Boleh dikirimi lalu lintas?"
Kalau gagalTask digantiTask 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.