Lewati ke konten

Flushing Akun Master

Pemegang akun masterBelum diujiArti badge ini

Panduan ini dipakai pemegang satu akun master untuk membersihkan ketiga project kelompoknya setelah satu batch selesai, lalu membuktikan bahwa tidak ada lagi biaya yang tertagih.

Bacaan ini untuk instruktur dan asisten instruktur. Empat pemegang akun master menjalankan prosedur yang sama pada akunnya masing-masing; tidak ada prosedur terpisah per akun, supaya satu perbaikan perintah tidak berhenti di satu berkas.

Hasil akhir yang dituju bukan “tidak ada resource”, melainkan tidak ada biaya. Dua hal berbeda, dan selisihnya justru yang paling sering menagih: alamat IP statis yang tidak dipakai dan disk yang tertinggal setelah VM-nya hilang.

Satu akun master mengelola tiga project. Flushing dijalankan per batch, bukan setelah semua batch selesai.

Dibersihkan setelah batch Dipertahankan antar batch
Mesin virtual (VM) Project dan tautan Billing Account
Disk, snapshot, dan custom image API yang sudah diaktifkan
Alamat IP statis Firewall allow-webgis-http dan allow-webgis-iap-ssh
Image di Artifact Registry dan registry lama gcr.io Artifact Registry katalog-images
Bucket Cloud Storage Service Account default Compute Engine
Trigger dan GitHub connection Cloud Build Budget alert
Service Account deployment peserta Label batch dan billing-code
Uptime check, alert policy, notification channel
IAM binding sembilan role peserta

Yang di kolom kanan tidak boleh dihapus. Peserta batch berikutnya mengandalkan keempatnya sudah ada; menghapus Artifact Registry berarti peserta berikutnya harus membuatnya ulang, dan itu bertentangan dengan panduan yang mereka pegang.

Bila seluruh batch sudah selesai dan akun master tidak akan dipakai lagi, jalur kedua ada pada bagian 10.

2. Kenapa per batch, bukan setelah semua batch

Section titled “2. Kenapa per batch, bukan setelah semua batch”

Alasan utamanya bukan kerapian.

Kuota alamat IPv4 publik berbatas empat per project per region, jadi project yang masih menahan VM batch pertama tidak punya slot untuk batch kedua. Batas itu dijelaskan pada panduan batch peserta bagian 6.2.

Alamat IP statis ditagih saat menganggur. Alamat yang sudah di-reserve tetapi tidak terpasang ke instance apa pun tetap masuk tagihan. Ini biaya yang paling sering bertahan setelah seseorang mengira pekerjaannya selesai.

Disk tetap ditagih walaupun VM di-stop. Yang berhenti hanya biaya compute. Stop bukan delete.

Peran Tugas
Pemegang akun master Menjalankan seluruh prosedur pada akunnya sendiri
Koordinator Mengumpulkan bukti biaya nol dari keempat akun
Peserta Tidak mengerjakan apa pun di sini

Peserta tidak menjalankan langkah apa pun pada dokumen ini. Semua resource peserta dihapus oleh pemegang akun master.

Duabelas langkah, dengan empat tanda aman untuk lanjut. Jangan melompati tanda.

Cloud Shell akun master
REGION="asia-southeast2"
ZONE="asia-southeast2-b"
BATCH="batch-1"
PROJECT_IDS=(
"geoportal-kelompok-a-xxxxx"
"geoportal-kelompok-b-xxxxx"
"geoportal-kelompok-c-xxxxx"
)
gcloud auth list
echo "Akun di atas harus akun master untuk akun ini. Kalau bukan, hentikan sekarang."

Jangan menghapus sebelum daftarnya dilihat. Perintah ini tidak mengubah apa pun.

Cloud Shell akun master
for PROJECT_ID in "${PROJECT_IDS[@]}"; do
echo "================ $PROJECT_ID"
echo "-- VM"
gcloud compute instances list --project="$PROJECT_ID"
echo "-- disk"
gcloud compute disks list --project="$PROJECT_ID"
echo "-- snapshot"
gcloud compute snapshots list --project="$PROJECT_ID"
echo "-- custom image"
gcloud compute images list --project="$PROJECT_ID" --no-standard-images
echo "-- alamat IP"
gcloud compute addresses list --project="$PROJECT_ID"
echo "-- Artifact Registry"
gcloud artifacts repositories list --project="$PROJECT_ID" --location="$REGION"
echo "-- bucket"
gcloud storage buckets list --project="$PROJECT_ID"
echo "-- trigger dan connection"
gcloud builds triggers list --project="$PROJECT_ID" --region="$REGION"
gcloud builds connections list --project="$PROJECT_ID" --region="$REGION"
echo "-- Service Account"
gcloud iam service-accounts list --project="$PROJECT_ID"
echo "-- Secret Manager"
gcloud secrets list --project="$PROJECT_ID"
echo "-- uptime check dan alert"
gcloud monitoring uptime list-configs --project="$PROJECT_ID"
gcloud alpha monitoring policies list --project="$PROJECT_ID" --format="value(displayName)"
gcloud alpha monitoring channels list --project="$PROJECT_ID" --format="value(displayName)"
done

Catat setiap nama yang muncul. Dua hal yang harus diperhatikan pada keluaran ini:

  • VM yang masih menyala tetap menagih biaya selama proses pembongkaran berjalan.
  • Alamat IP berstatus RESERVED dengan kolom users kosong adalah biaya menganggur. Ini yang paling sering tertinggal.

Aman untuk lanjut bila daftar sudah tercatat dan kamu sudah tahu resource mana milik batch yang sedang dibongkar.

Langkah ini menghentikan biaya terbesar lebih dahulu, sehingga sisa proses bisa dikerjakan tanpa terburu-buru.

Cloud Shell akun master
for PROJECT_ID in "${PROJECT_IDS[@]}"; do
gcloud compute instances list \
--project="$PROJECT_ID" \
--format="value(name,zone)" |
while IFS=$'\t' read -r NAME VM_ZONE; do
echo "Stop $NAME di $VM_ZONE ($PROJECT_ID)"
gcloud compute instances stop "$NAME" \
--zone="$VM_ZONE" \
--project="$PROJECT_ID" \
--quiet
done
done

Perintah ini mengambil zone dari keluaran instances list, bukan dari variabel $ZONE. Alasannya praktis: satu project boleh berisi VM di region berbeda, dan zone yang salah akan menghasilkan not found yang mudah disalahartikan sebagai “VM-nya sudah tidak ada”.

Aman untuk lanjut bila gcloud compute instances list untuk ketiga project hanya menampilkan status TERMINATED, atau tidak menampilkan apa pun.

Urutannya mengikat: VM harus hilang sebelum disknya, karena disk tidak dapat dihapus saat masih terpasang.

Cloud Shell akun master
for PROJECT_ID in "${PROJECT_IDS[@]}"; do
gcloud compute instances list \
--project="$PROJECT_ID" \
--format="value(name,zone)" |
while IFS=$'\t' read -r NAME VM_ZONE; do
echo "Hapus $NAME di $VM_ZONE ($PROJECT_ID)"
gcloud compute instances delete "$NAME" \
--zone="$VM_ZONE" \
--delete-disks=all \
--project="$PROJECT_ID" \
--quiet
done
done

--delete-disks=all menghapus boot disk sekaligus. Tanpa flag itu, disknya tertinggal dan tetap ditagih.

Cloud Shell akun master
for PROJECT_ID in "${PROJECT_IDS[@]}"; do
gcloud compute addresses list \
--project="$PROJECT_ID" \
--format="value(name,region)" |
while IFS=$'\t' read -r NAME ADDRESS_REGION; do
echo "Hapus alamat $NAME di $ADDRESS_REGION ($PROJECT_ID)"
gcloud compute addresses delete "$NAME" \
--region="$ADDRESS_REGION" \
--project="$PROJECT_ID" \
--quiet
done
done

Langkah 6: Hapus disk, snapshot, dan image yang tertinggal

Section titled “Langkah 6: Hapus disk, snapshot, dan image yang tertinggal”
Cloud Shell akun master
for PROJECT_ID in "${PROJECT_IDS[@]}"; do
gcloud compute disks list \
--project="$PROJECT_ID" \
--format="value(name,zone)" |
while IFS=$'\t' read -r NAME DISK_ZONE; do
echo "Hapus disk $NAME di $DISK_ZONE ($PROJECT_ID)"
gcloud compute disks delete "$NAME" \
--zone="$DISK_ZONE" --project="$PROJECT_ID" --quiet
done
gcloud compute snapshots list \
--project="$PROJECT_ID" \
--format="value(name)" |
while read -r SNAPSHOT; do
echo "Hapus snapshot $SNAPSHOT ($PROJECT_ID)"
gcloud compute snapshots delete "$SNAPSHOT" \
--project="$PROJECT_ID" --quiet
done
gcloud compute images list \
--project="$PROJECT_ID" --no-standard-images \
--format="value(name)" |
while read -r IMAGE; do
echo "Hapus image $IMAGE ($PROJECT_ID)"
gcloud compute images delete "$IMAGE" \
--project="$PROJECT_ID" --quiet
done
done

Aman untuk lanjut bila tidak ada satu pun disk, snapshot, atau custom image yang masih terpasang pada VM yang hidup. Langkah 7 sampai 11 belum menyentuh compute, jadi daftar instances dan addresses sudah menjadi bukti bahwa resource berbayar terbesar sudah lepas. Pemeriksaan kosong yang menyeluruh dilakukan sekali di langkah 12, setelah kesebelas langkah sebelumnya selesai.

Artifact Registry ditagih per GB-bulan, dan image Next.js beserta seluruh tag lamanya bisa menumpuk jauh melebihi 0,5 GB jatah gratis.

Yang dibersihkan hanya isinya, bukan repository-nya.

Cloud Shell akun master
for PROJECT_ID in "${PROJECT_IDS[@]}"; do
REPO="${REGION}-docker.pkg.dev/${PROJECT_ID}/katalog-images"
echo "== $PROJECT_ID"
# Daftar lebih dahulu, supaya jumlahnya terlihat sebelum dihapus.
gcloud artifacts docker images list "$REPO" \
--include-tags \
--format="table(image,digest,tags)"
# Satu paket mewakili satu image beserta seluruh tag dan digest-nya.
gcloud artifacts packages list \
--repository=katalog-images \
--location="$REGION" \
--project="$PROJECT_ID" \
--format="value(name)" |
while read -r PAKET; do
echo "Hapus paket $PAKET"
gcloud artifacts packages delete "$PAKET" \
--repository=katalog-images \
--location="$REGION" \
--project="$PROJECT_ID" \
--quiet
done
done

Menghapus paket lebih ringkas daripada menghapus image satu per satu. Satu paket memuat seluruh tag dan digest di dalamnya, sehingga tidak ada tag lama yang tertinggal untuk ditagih.

Registry lama gcr.io menyimpan image di bucket Cloud Storage, bukan di Artifact Registry. Kalau project ini pernah memakainya, isinya tidak akan terlihat pada perintah di atas:

Cloud Shell akun master
for PROJECT_ID in "${PROJECT_IDS[@]}"; do
gcloud storage ls --project="$PROJECT_ID" "gs://artifacts.${PROJECT_ID}.appspot.com/**" 2>/dev/null \
&& echo "Bucket gcr.io masih berisi objek di $PROJECT_ID" \
|| echo "Tidak ada bucket gcr.io di $PROJECT_ID"
done

Cloud Build dapat menulis log atau artifact ke bucket. Periksa, lalu hapus isinya, bukan bucketnya, karena beberapa bucket dibuat otomatis oleh layanan GCP dan akan dibuat ulang.

Cloud Shell akun master
for PROJECT_ID in "${PROJECT_IDS[@]}"; do
echo "== $PROJECT_ID"
gcloud storage buckets list --project="$PROJECT_ID" \
--format="table(name,location,storageClass)"
done

Hapus hanya bucket yang isinya berkas batch ini:

Cloud Shell akun master
PROJECT_ID="geoportal-kelompok-a-xxxxx"
BUCKET="gs://nama-bucket-yang-dikonfirmasi"
gcloud storage ls "$BUCKET/**"
gcloud storage rm --recursive "$BUCKET/**"

Trigger dihapus lebih dahulu daripada connection. Connection yang masih dipakai trigger akan menolak dihapus.

Cloud Shell akun master
for PROJECT_ID in "${PROJECT_IDS[@]}"; do
echo "== $PROJECT_ID"
gcloud builds triggers list \
--project="$PROJECT_ID" --region="$REGION" --format="value(name)" |
while read -r TRIGGER; do
gcloud builds triggers delete "$TRIGGER" \
--project="$PROJECT_ID" --region="$REGION" --quiet
done
gcloud builds connections list \
--project="$PROJECT_ID" --region="$REGION" --format="value(name)" |
while read -r CONNECTION; do
gcloud builds connections delete "$CONNECTION" \
--project="$PROJECT_ID" --region="$REGION" --quiet
done
done

Langkah 10: Hapus Service Account deployment

Section titled “Langkah 10: Hapus Service Account deployment”

Service Account default Compute Engine jangan dihapus. Ia dibuat otomatis dan dipakai ulang oleh batch berikutnya.

Cloud Shell akun master
for PROJECT_ID in "${PROJECT_IDS[@]}"; do
echo "== $PROJECT_ID"
gcloud iam service-accounts list \
--project="$PROJECT_ID" \
--format="value(email)"
done

Hapus setiap Service Account yang berawalan cb-deployer- milik batch ini:

Cloud Shell akun master
PROJECT_ID="geoportal-kelompok-a-xxxxx"
gcloud iam service-accounts list \
--project="$PROJECT_ID" \
--filter="email:cb-deployer-" \
--format="value(email)" |
while read -r SA; do
gcloud iam service-accounts delete "$SA" \
--project="$PROJECT_ID" --quiet
done

Aman untuk lanjut bila Service Account yang tersisa hanya milik bawaan layanan GCP: *-asisten01@example.com, service-*@gcp-sa-*.iam.gserviceaccount.com, dan service-*@cloudbuild.gserviceaccount.com.

Langkah 11: Bersihkan pemantauan dan cabut IAM peserta

Section titled “Langkah 11: Bersihkan pemantauan dan cabut IAM peserta”

Resource pemantauan hidup di dalam project, bukan di dalam VM. Menghapus VM tidak menghapusnya.

Cloud Shell akun master
for PROJECT_ID in "${PROJECT_IDS[@]}"; do
echo "== $PROJECT_ID"
gcloud monitoring uptime list-configs \
--project="$PROJECT_ID" --format="value(name)" |
while read -r CHECK; do
gcloud monitoring uptime delete "$CHECK" --project="$PROJECT_ID" --quiet
done
gcloud alpha monitoring policies list \
--project="$PROJECT_ID" --format="value(name)" |
while read -r POLICY; do
gcloud alpha monitoring policies delete "$POLICY" --project="$PROJECT_ID" --quiet
done
gcloud alpha monitoring channels list \
--project="$PROJECT_ID" --format="value(name)" |
while read -r CHANNEL; do
gcloud alpha monitoring channels delete "$CHANNEL" --project="$PROJECT_ID" --quiet
done
done

Cabut sembilan role dari setiap email peserta. Isi ROLES dengan blok pada panduan batch peserta bagian 5.1, karena blok itu sumber tunggal daftar role. Daftar itu tidak disalin ulang di sini supaya keduanya tidak bisa berbeda.

Cloud Shell akun master
# ROLES diisi dari panduan batch peserta bagian 5.1.
for PROJECT_ID in "${PROJECT_IDS[@]}"; do
echo "== $PROJECT_ID"
gcloud projects get-iam-policy "$PROJECT_ID" \
--flatten="bindings[].members" \
--filter="bindings.members~user:@" \
--format="value(bindings.members)" |
while read -r MEMBER; do
for ROLE in "${ROLES[@]}"; do
gcloud projects remove-iam-policy-binding "$PROJECT_ID" \
--member="$MEMBER" \
--role="$ROLE" \
--condition=None \
--quiet || true
done
done
done

|| true dipakai di sini, berbeda dari waktu pemasangan. Alasannya: pada pencabutan, “binding tidak ditemukan” adalah hasil yang diinginkan, bukan kegagalan. Pada pemasangan, error apa pun harus menghentikan proses.

Verifikasi bahwa tidak ada lagi user selain akun master:

Cloud Shell akun master
for PROJECT_ID in "${PROJECT_IDS[@]}"; do
echo "== $PROJECT_ID"
gcloud projects get-iam-policy "$PROJECT_ID" \
--flatten="bindings[].members" \
--filter="bindings.members~user:@" \
--format="table(bindings.role, bindings.members)"
done

Langkah ini yang menutup pekerjaan, dan ia tidak dapat dikerjakan pada hari yang sama dengan langkah 1 sampai 11.

Bagian A, bukti hari itu, dari terminal. Tidak ada resource tertagih yang tersisa:

Cloud Shell akun master
for PROJECT_ID in "${PROJECT_IDS[@]}"; do
echo "================ $PROJECT_ID"
gcloud compute instances list --project="$PROJECT_ID" --format="value(name)"
gcloud compute disks list --project="$PROJECT_ID" --format="value(name)"
gcloud compute addresses list --project="$PROJECT_ID" --format="value(name,status,users)"
gcloud compute snapshots list --project="$PROJECT_ID" --format="value(name)"
gcloud artifacts docker images list \
"${REGION}-docker.pkg.dev/${PROJECT_ID}/katalog-images" \
--include-tags --format="value(image)"
gcloud storage buckets list --project="$PROJECT_ID" --format="value(name)"
done

Seluruh perintah itu harus menghasilkan keluaran kosong. Dua pengecualian: bucket bawaan layanan dengan isi kosong boleh tetap ada, dan resource yang sengaja ditahan untuk peserta yang masih bekerja (bagian 7) tentu masih muncul. Selain kedua itu, satu nama pun yang tercetak berarti masih ada yang ditagih.

Bagian B, bukti di Console, dari Billing. Untuk setiap Billing Account:

  1. Billing → Reports. Pilih rentang waktu sejak batch dimulai, kelompokkan per project. Periksa bahwa biaya berhenti bertambah sejak tanggal pembongkaran.
  2. Billing → Cost table. Periksa bahwa tidak ada SKU yang masih bergerak, terutama External IP Charge dan Storage PD Capacity. Kedua SKU inilah yang bertahan setelah VM dihapus bila langkah 5 dan 6 terlewat.
  3. Billing → Credits. Periksa sisa kredit. Kredit trial berkurang oleh pemakaian yang sudah terjadi dan tidak kembali setelah resource dihapus.
  4. Billing → Budgets & alerts. Periksa budget masih menunjuk project yang benar.

Bagian C, bukti tunggu. Billing Reports punya jeda beberapa jam sampai beberapa hari sebelum pemakaian terakhir muncul. Karena itu:

Tanggal pembongkaran: ____
Periksa ulang pada: ____ (24 sampai 48 jam setelahnya)
Hasil periksa ulang: ____

Isi tabel ini untuk keempat akun master, lalu serahkan ke koordinator. Tanpa bagian C, kamu menutup pekerjaan dengan keyakinan yang belum terbukti. Kalimat yang berlaku sejak panduan lama tetap benar: mematikan billing menghentikan tagihan baru, tetapi tidak membatalkan tagihan yang sudah berjalan.

Setelah langkah Yang harus benar
3 Tidak ada VM berstatus RUNNING di ketiga project
6 instances list, disks list, dan addresses list kosong
10 Service Account yang tersisa hanya milik bawaan layanan GCP
12 Billing Reports menunjukkan biaya berhenti bertambah, dan periksa ulang 24–48 jam kemudian sudah terisi

Empat hal ini berulang di setiap pembongkaran, dan keempatnya bukan compute:

Yang tertinggal Kenapa ditagih Langkah pencegahnya
Alamat IP statis tanpa instance Ditagih saat menganggur 5
Disk setelah VM dihapus tanpa --delete-disks=all Ditagih per GB-bulan 4 dan 6
Snapshot dan custom image Ditagih per GB-bulan 6
Tag image lama di Artifact Registry Ditagih per GB-bulan, dan tag lama menumpuk 7

7. Kalau ada peserta yang masih butuh VM-nya

Section titled “7. Kalau ada peserta yang masih butuh VM-nya”

Jangan tunda seluruh pembongkaran karena satu orang. Pisahkan:

  1. Bersihkan resource batch ini saja, dengan daftar nama yang sudah dicatat pada langkah 2. Jangan memakai perintah yang menghapus “semua yang ada” di project.
  2. Sisakan VM dan alamat IP orang itu, dan catat di manifest dengan status DITAHAN.
  3. Ulangi langkah 3 sampai 11 untuk sisanya setelah orang itu selesai.

Yang tidak boleh dilakukan: membiarkan seluruh project utuh karena satu peserta. Empat alamat IP publik yang tertahan berarti project itu tidak dapat menampung peserta batch berikutnya.

8. Pencabutan akses setelah seluruh batch selesai

Section titled “8. Pencabutan akses setelah seluruh batch selesai”

Kalau akun master tidak akan dipakai lagi, dua hal berikut masih tersisa setelah langkah 12:

  1. Budget alert. Hapus budget project dan budget Billing Account.
  2. Akses Billing Account. Cabut roles/billing.admin dari pemegang akun master bila ia bukan pemilik Billing Account.

Kalau yang kamu butuhkan hanya membebaskan slot billing untuk batch berikutnya, bukan menutup akun, jangan jalankan bagian ini. Yang dibutuhkan cuma melepas tautan satu project, dan caranya ada di panduan batch peserta bagian 2.1. Ingat bahwa unlink mematikan seluruh isi project itu.

Dua hal ini sering ditanyakan saat melihat daftar bongkar, dan keduanya bukan milik GCP:

Yang tetap hidup Ditagih?
Database Supabase milik setiap peserta Tidak. Akun peserta sendiri, di luar GCP.
Fork repository GitHub milik setiap peserta Tidak. Source code, tanpa biaya.

Sertifikat Let’s Encrypt pada VM yang dihapus mati bersama VM-nya dan tidak perlu dicabut.

10. Bila seluruh batch selesai dan akun master tidak dipakai lagi

Section titled “10. Bila seluruh batch selesai dan akun master tidak dipakai lagi”

Jalur ini hanya untuk akun master yang benar-benar selesai, bukan untuk jeda antar batch.

Cloud Shell akun master
PROJECT_ID="geoportal-kelompok-a-xxxxx"
gcloud billing projects unlink "$PROJECT_ID"
gcloud projects delete "$PROJECT_ID"

Ulangi untuk ketiga project. Penghapusan project bersifat sementara selama 30 hari; selama masa itu project dapat dipulihkan, tetapi seluruh resource di dalamnya sudah tidak berjalan dan tidak ditagih.

Kalau pekerjaan satu project saja perlu dibongkar tanpa menyentuh dua lainnya, urutan per langkahnya ada di panduan setup project bagian 13.

  • Tidak ada VM berstatus RUNNING.
  • Tidak ada disk, snapshot, atau custom image yang tersisa.
  • Tidak ada alamat IP statis yang tersisa.
  • Artifact Registry kosong, dan bucket gcr.io kosong.
  • Trigger dan connection Cloud Build sudah hilang.
  • Hanya Service Account bawaan layanan yang tersisa.
  • Uptime check, alert policy, dan notification channel sudah hilang.
  • IAM binding peserta sudah dicabut, hanya akun master yang tersisa.
  • Billing Reports menunjukkan biaya berhenti bertambah.
  • Periksa ulang 24–48 jam kemudian sudah diisi dan hasilnya bersih untuk keempat akun.