Deployment Asisten
Panduan ini dipakai oleh asisten trainer setelah koordinator memberikan akses IAM ke project kelompok GCP. Satu project dipakai oleh lima asisten. Karena itu, setiap asisten harus memakai slug unik pada Service Account, VM, GitHub connection, linked repository, trigger, image, alamat IP, dan DNS zone.
Panduan ini disusun berurutan dalam tiga tahap:
- Bagian 1 sampai 2, dari laptop. Fork repository, lengkapi berkas konfigurasi, commit, lalu push.
- Bagian 3 sampai 12, dari Cloud Shell dan VM. Buka project, buat Service Account, dan buat VM.
- Bagian 13 sampai 26, dari VM dan Cloud Shell. Clone fork, isi
.env, jalankan Cloud Build, dan uji GeoServer.
Panduan ini adalah bahan uji, bukan laporan hasil uji. Alur fork, VM, GitHub, Cloud Build, dan akses Geoportal melalui alamat IP sudah diuji satu kali pada 10 September 2026 dengan satu email. Bagian GeoServer di VM dan pengujian unggah data spasial belum pernah diuji sampai tuntas, jadi dua bagian itulah yang perlu dibuktikan lewat workbook asisten trainer.
VM memakai spesifikasi default dari modul, yaitu e2-medium dengan heap GeoServer
-Xmx2048m. Spesifikasi ini sengaja dipertahankan supaya kendala memori yang sebenarnya
muncul dan bisa dicatat, bukan disembunyikan dengan menaikkan spesifikasi lebih dulu.
Hasil akhir yang diharapkan
Section titled “Hasil akhir yang diharapkan”Setelah panduan ini selesai:
- Fork berisi
docker-compose.yml,nginx.conf,.env.example, dan.gitignoreyang lengkap. - Push ke branch
mainmemicu Cloud Build yang membangun image dan menjalankannya di VM. - API bersama dan Artifact Registry sudah tersedia di project kelompok.
- Service Account deployment dan VM dengan nama unik asisten sudah tersedia.
- Tiga container berjalan:
nextjs_portal,geoserver_app, dannginx_proxy. - Geoportal dapat dibuka melalui path
/portal/. - GeoServer dapat dibuka melalui path
/geoserver/web/. - Data spasial dapat diunggah dan dibaca kembali melalui endpoint WFS.
- Jika diminta, domain asisten dapat diarahkan ke alamat IP VM.
1. Fork repository dan siapkan berkas konfigurasi
Section titled “1. Fork repository dan siapkan berkas konfigurasi”Bagian ini dikerjakan dari laptop sebelum menyentuh Google Cloud. Alasannya sederhana:
repository instruktur belum memuat docker-compose.yml, nginx.conf, maupun
.env.example, sedangkan Cloud Build membaca berkas-berkas itu dari fork. Kalau fork belum
lengkap, build pertama akan gagal walaupun project GCP sudah benar.
Urutan yang benar adalah fork, sunting berkas di laptop, verifikasi, commit, push, baru lanjut ke bagian 4. Jangan membuat VM lebih dahulu, karena VM hanya menyalin hasil fork.
Lima berkas berikut disiapkan pada bagian ini, lalu diverifikasi pada bagian 2 dan di-commit pada bagian 3:
| Berkas | Fungsi |
|---|---|
docker-compose.yml |
Tiga service: nextjs, geoserver, dan nginx |
nginx.conf |
Rute /portal dan /geoserver/web/ |
.env.example |
Contoh isi .env tanpa nilai rahasia |
.gitignore |
Menambah /geoserver-data/ supaya data GeoServer tidak masuk Git |
scripts/check-config.mjs |
Pemeriksa dua berkas YAML yang jalan tanpa Docker |
Buat fork
Section titled “Buat fork”- Buka
https://github.com/matiurari/personal-geoportalpada browser. - Pilih Fork, lalu pilih akun GitHub asisten sebagai tujuan.
- Beri nama fork
personal-geoportal-pesertasupaya seluruh contoh perintah pada panduan ini cocok. Jika nama itu sudah dipakai repository lain di akun GitHub asisten, biarkan nama bawaanpersonal-geoportaldan sesuaikan URL clone pada langkah berikutnya. - Pastikan branch default fork adalah
main.
Repository public dapat difork tanpa izin khusus. Pastikan fork benar-benar berada di akun asisten, bukan di organisasi yang tidak dipakai untuk pelatihan.
Siapkan file konfigurasi tiga container
Section titled “Siapkan file konfigurasi tiga container”Repository instruktur belum memuat docker-compose.yml, nginx.conf, maupun .env.example.
Ketiga berkas itu hanya muncul sebagai teks pada modul, jadi asisten perlu membuatnya sendiri
di fork. Empat berkas berikut wajib disiapkan sebelum Cloud Build dijalankan. Tanpa
perubahan ini container geoserver_app tidak pernah dibuat dan GeoServer tidak bisa dibuka.
docker-compose.yml di root repository fork:
services: nextjs: image: ${NEXTJS_IMAGE:?Set NEXTJS_IMAGE in .env} container_name: nextjs_portal env_file: - .env depends_on: - geoserver networks: - app-network restart: unless-stopped
geoserver: image: kartoza/geoserver:2.24.1 container_name: geoserver_app environment: - INITIAL_MEMORY=512m - MAXIMUM_MEMORY=2048m - GEOSERVER_ADMIN_USER=admin - GEOSERVER_ADMIN_PASSWORD=ISI_PASSWORD_GEOSERVER - GEOSERVER_CORS_ENABLED=true - GEOSERVER_CORS_ALLOWED_ORIGINS=* volumes: - ./geoserver-data:/opt/geoserver/data_dir networks: - app-network restart: unless-stopped
nginx: image: nginx:1.27-alpine container_name: nginx_proxy depends_on: - nextjs - geoserver ports: - "80:80" volumes: - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro networks: - app-network restart: unless-stopped
networks: app-network: driver: bridgeCatatan dua variabel memori. Image kartoza/geoserver membaca INITIAL_MEMORY dan
MAXIMUM_MEMORY, bukan JAVA_OPTS seperti yang tertulis di modul. MAXIMUM_MEMORY=2048m
adalah heap default yang sengaja dipertahankan pada e2-medium 4 GB.
Catatan kata sandi. GEOSERVER_ADMIN_PASSWORD membuat kata sandi admin ikut ditentukan saat
container pertama kali dijalankan, sehingga kata sandi bertahan setelah container di-restart.
Ganti ISI_PASSWORD_GEOSERVER dengan kata sandi sendiri sebelum push. Jika variabel ini
dikosongkan, image akan membuat kata sandi acak dan menuliskannya pada log startup, serta
kata sandi hasil penggantian lewat antarmuka web tidak bertahan setelah restart container.
nginx.conf di root repository fork:
server { listen 80; server_name _;
location = / { return 302 /portal; }
# Jalur kanonik antarmuka admin GeoServer location = /geoserver { return 302 /geoserver/web/; }
location /geoserver/ { proxy_pass http://geoserver:8080/geoserver/;
proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $http_host;
proxy_buffers 16 16k; proxy_buffer_size 32k; }
location / { proxy_pass http://nextjs:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }}.env.example di root repository fork. Berkas ini menjadi contoh isi .env di VM,
sehingga nilai asli tidak perlu ikut masuk Git. NEXTAUTH_URL wajib memakai alamat IP
eksternal VM dan diakhiri slash. BASE_URL hanya diperlukan kalau aplikasi memanggil API
lewat URL publik.
# Salin berkas ini menjadi .env di VM, lalu isi nilai aslinya di sana.# Jangan pernah commit berkas .env yang sudah terisi.
# Diisi otomatis oleh Cloud Build pada deploy pertama. Biarkan kosong di awal.NEXTJS_IMAGE=
# Boleh dikosongkan untuk menguji build, Nginx, dan halaman publik.# Login, Prisma, dan fitur katalog memerlukan database yang valid.DATABASE_URL=
# Buat dua nilai acak yang berbeda dengan: openssl rand -hex 32JWT_SECRET=JWT_EXPIRES_IN=1hNEXTAUTH_SECRET=
# Wajib memakai alamat IP eksternal VM dan diakhiri slash, contoh:# NEXTAUTH_URL=http://IP_EKSTERNAL_VM/portal/NEXTAUTH_URL=
AUTH_API_URL=http://localhost:3000/portal/api
# Hanya diperlukan jika aplikasi memanggil API melalui URL publik.BASE_URL=.gitignore di root repository fork. Tambahkan satu baris supaya data GeoServer tidak
ikut masuk Git:
/geoserver-data/Tambahkan skrip pemeriksa konfigurasi
Section titled “Tambahkan skrip pemeriksa konfigurasi”Skrip ini memeriksa docker-compose.yml dan cloudbuild.yaml, dan gagal bila service di
berkas compose bukan tiga. Skrip dipakai pada bagian 2 jalur Node, dan berguna juga saat
berkas konfigurasi diubah lagi nanti.
mkdir -p scriptsSimpan isi berikut sebagai scripts/check-config.mjs:
import { readFileSync } from 'node:fs';import { createRequire } from 'node:module';
// YAML dimuat lewat createRequire karena paket ini berbentuk CommonJS,// sehingga import bernama tidak tersedia di berkas .mjs.const YAML = createRequire(import.meta.url)('yaml');
const names = ['docker-compose.yml', 'cloudbuild.yaml'];let failed = false;
for (const file of names) { try { const data = YAML.parse(readFileSync(file, 'utf8')); console.log('OK ' + file + ' -> ' + Object.keys(data).join(', ')); if (names[0] === file) { const services = Object.keys(data.services ?? {}); console.log(' service: ' + services.join(', ')); if (services.length !== 3) { console.error(' HARUS 3 service, ditemukan ' + services.length); failed = true; } } } catch (error) { console.error('GAGAL ' + file + ': ' + error.message); failed = true; }}
process.exit(failed ? 1 : 0);2. Verifikasi berkas sebelum push
Section titled “2. Verifikasi berkas sebelum push”Kesalahan pada berkas konfigurasi baru ketahuan setelah Cloud Build berjalan, dan satu siklus build memakan beberapa menit. Periksa dulu dari laptop supaya kesalahan tertangkap dalam hitungan detik.
Asisten memakai sistem operasi yang berbeda-beda, jadi bagian ini menyediakan dua jalur.
| Jalur | Butuh apa | Jalan di |
|---|---|---|
| Jalur 1 | Docker atau Podman | macOS, Linux, Windows dengan Docker Desktop |
| Jalur 2 | Node.js saja | Semua sistem operasi, termasuk Windows tanpa Docker |
Jalur 1 memakai pemeriksa aslinya sehingga hasilnya paling meyakinkan. Jalur 2 hanya memeriksa struktur dan sintaks dasar, tetapi bisa dijalankan semua orang. Kalau Docker atau Podman tersedia, kerjakan Jalur 1. Kalau tidak, Jalur 2 sudah cukup untuk menangkap sebagian besar kesalahan penulisan.
Jalur 1: dengan container, lebih menyeluruh tetapi butuh Docker atau Podman
Section titled “Jalur 1: dengan container, lebih menyeluruh tetapi butuh Docker atau Podman”Jalur ini menjalankan pemeriksa aslinya, sehingga hasilnya paling meyakinkan.
# Periksa docker-compose.yml. Tanpa .env, perintah ini berhenti dengan# pesan "Set NEXTJS_IMAGE in .env" karena variabel itu wajib ada.NEXTJS_IMAGE=dummy docker compose config --services
# Periksa sintaks nginx.conf lewat salinan sementaraTMP="$(mktemp -d)"sed -e 's|http://geoserver:8080|http://127.0.0.1:8080|' \ -e 's|http://nextjs:3000|http://127.0.0.1:3000|' \ nginx.conf > "$TMP/nginx.conf"
docker run --rm \ -v "$TMP/nginx.conf:/etc/nginx/conf.d/default.conf:ro" \ nginx:1.27-alpine nginx -t
rm -rf "$TMP"Perintah sed dan mktemp di atas hanya jalan di macOS dan Linux. Di Windows, pakai langkah
pemeriksaan sintaks pada Jalur 2, karena hasil pemeriksaannya setara.
Hasil yang diharapkan dari docker compose config --services adalah tiga baris: nextjs,
geoserver, dan nginx. Kalau hanya muncul nextjs dan nginx, berarti service geoserver
belum masuk dan GeoServer tidak akan pernah jalan.
Hasil yang diharapkan dari nginx -t adalah dua baris terakhir seperti ini:
nginx: the configuration file /etc/nginx/nginx.conf syntax is oknginx: configuration file /etc/nginx/nginx.conf test is successfulJalur 2: dengan Node.js saja, jalan di semua sistem operasi
Section titled “Jalur 2: dengan Node.js saja, jalan di semua sistem operasi”Jalur ini tidak memerlukan container, jadi cocok untuk Windows dan untuk laptop yang belum memasang Docker.
Langkah 2a. Periksa docker-compose.yml dan cloudbuild.yaml.
Skrip scripts/check-config.mjs sudah dibuat pada bagian 1. Jalankan dengan:
node scripts/check-config.mjsHasil yang diharapkan:
OK docker-compose.yml -> services, networks service: nextjs, geoserver, nginxOK cloudbuild.yaml -> substitutions, steps, images, optionsKalau muncul pesan bahwa modul yaml tidak ditemukan, pasang lebih dahulu dengan
npm install --no-save yaml.
Langkah 2b. Periksa sintaks nginx.conf.
Nginx menolak konfigurasi yang memuat proxy_pass ke nama service yang belum ada. Di laptop,
container geoserver dan nextjs tidak berjalan, jadi nama service itu tidak bisa
di-resolve dan nginx -t akan gagal dengan pesan host not found in upstream "geoserver".
Pesan itu bukan berarti konfigurasinya salah.
Karena itu, uji dulu berkasnya dengan mengganti nama service menjadi alamat lokal, memakai Node.js supaya jalan di semua sistem operasi:
node -e "const fs=require('fs');const t=fs.readFileSync('nginx.conf','utf8');const g=t.replace(/http:\/\/(nextjs|geoserver):/g,'http://127.0.0.1:');const q=(t.match(/{/g)||[]).length-(t.match(/}/g)||[]).length;const bad=[...g.matchAll(/^\s*(location[^{]*|server)\s*$/gm)].map(m=>m[1].trim());console.log('proxy_pass:',[...g.matchAll(/proxy_pass\s+(\S+);/g)].map(m=>m[1]).join(', '));console.log('kurung kurawal seimbang:',q===0?'ya':'TIDAK, selisih '+q);console.log('blok tanpa kurung buka:',bad.length?bad.join(' | '):'tidak ada');"Hasil yang diharapkan:
proxy_pass: http://127.0.0.1:8080/geoserver/, http://127.0.0.1:3000kurung kurawal seimbang: yablok tanpa kurung buka: tidak adaDua baris terakhir itu yang menangkap salah ketik paling umum, yaitu kurung kurawal yang
tidak ditutup dan proxy_pass yang lupa diakhiri titik koma.
Pengguna Podman
Section titled “Pengguna Podman”Pastikan mesin Podman sudah jalan lebih dahulu:
podman machine startJika muncul Cannot connect to Podman, mesinnya belum berjalan. Jalankan
podman machine init satu kali bila mesinnya belum pernah dibuat.
Saat memanggil podman-compose langsung, bukan lewat perintah docker, tambahkan tanda
pemisah sebelum opsi:
podman-compose -- config --servicesDaftar periksa manual
Section titled “Daftar periksa manual”Kalau kedua jalur di atas tidak bisa dijalankan, periksa lima hal berikut dengan mata:
docker-compose.ymlmemuat tiga service:nextjs,geoserver, dannginx.nginx.confmemuat bloklocation /geoserver/danlocation = /geoserver.- Setiap
proxy_passmemakai nama service, bukanlocalhost. Nilai yang benar adalahhttp://nextjs:3000danhttp://geoserver:8080. GEOSERVER_ADMIN_PASSWORDsudah diganti, bukan lagiISI_PASSWORD_GEOSERVER..gitignorememuat/geoserver-data/.
3. Commit dan push fork
Section titled “3. Commit dan push fork”Setelah keempat berkas siap, commit dan push dari laptop. Push inilah yang nanti memicu Cloud Build pada bagian 17.
cd personal-geoportal-pesertagit status --shortgit add docker-compose.yml nginx.conf .env.example .gitignore scripts/check-config.mjsgit commit -m "feat: tambah GeoServer dan rute nginx"git push origin mainJangan pernah memakai git add . tanpa memeriksa git status --short lebih dahulu, supaya
berkas .env yang sudah terisi tidak ikut ter-commit.
4. Buka project sebagai asisten
Section titled “4. Buka project sebagai asisten”Login ke Google Cloud Console menggunakan email yang didaftarkan oleh koordinator. Pada kunjungan pertama, Google mungkin meminta persetujuan terhadap persyaratan layanan.

Gambar 1. Asisten menyetujui persyaratan layanan sebelum membuka project.
Pilih project yang diberikan oleh akun master. Pastikan nama project terlihat pada bagian atas Google Cloud Console.

Gambar 2. Pengujian awal membuktikan bahwa email asisten dapat membuka project melalui IAM. Pada skema kelompok, pilih Project ID yang dikirim akun master.
5. Tetapkan variabel Cloud Shell
Section titled “5. Tetapkan variabel Cloud Shell”Buka Cloud Shell menggunakan akun asisten. Ganti PARTICIPANT_ID dengan slug yang sudah
disepakati. Gunakan huruf kecil, angka, atau tanda hubung tanpa spasi. Contoh berikut
memakai slug nama01.
PROJECT_ID="geoportal-kelompok-a-xxxxx"REGION="asia-southeast2"ZONE="asia-southeast2-b"PARTICIPANT_ID="nama01"
REPOSITORY="katalog-images"APP_DIR="/opt/webgis/app"VM_NAME="webgis-${PARTICIPANT_ID}"BUILD_SA_NAME="cb-deployer-${PARTICIPANT_ID}"CONNECTION_NAME="github-${PARTICIPANT_ID}"LINKED_REPO_NAME="repo-${PARTICIPANT_ID}"TRIGGER_NAME="deploy-${PARTICIPANT_ID}"IMAGE_NAME="nextjs-${PARTICIPANT_ID}"STATIC_IP_NAME="webgis-ip-${PARTICIPANT_ID}"DNS_ZONE_NAME="geoportal-${PARTICIPANT_ID}"
BUILD_SA="${BUILD_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
gcloud config set project "$PROJECT_ID"gcloud auth listgcloud config get-value projectPastikan akun aktif adalah email asisten dan hasil perintah terakhir sama dengan
PROJECT_ID. Jangan memakai slug asisten lain. Variabel Cloud Shell tidak tersimpan
secara permanen. Jalankan kembali blok ini jika sesi Cloud Shell terputus atau terminal
baru dibuka.
6. Verifikasi API bersama
Section titled “6. Verifikasi API bersama”API sudah diaktifkan oleh akun master. Asisten cukup memeriksa layanan utama:
gcloud services list --enabled \ --filter="config.name:(compute.googleapis.com OR cloudbuild.googleapis.com OR artifactregistry.googleapis.com OR iap.googleapis.com OR dns.googleapis.com OR domains.googleapis.com OR secretmanager.googleapis.com)" \ --format="value(config.name)"Hubungi akun master jika satu layanan belum terlihat. Asisten memang memiliki izin untuk mengaktifkan layanan yang terlewat, tetapi perubahan API berlaku untuk seluruh project kelompok.
7. Buat Service Account deployment
Section titled “7. Buat Service Account deployment”Asisten dapat membuat Service Account sendiri karena akun master sudah memberikan role IAM yang diperlukan.
gcloud iam service-accounts create "$BUILD_SA_NAME" \ --display-name="Cloud Build Deployer"Jika perintah menampilkan bahwa Service Account sudah ada, lanjutkan ke pemberian role.
for ROLE in \ roles/cloudbuild.builds.builder \ roles/artifactregistry.writer \ roles/compute.instanceAdmin.v1 \ roles/compute.osAdminLogin \ roles/iap.tunnelResourceAccessor \ roles/logging.logWriterdo gcloud projects add-iam-policy-binding "$PROJECT_ID" \ --member="serviceAccount:$BUILD_SA" \ --role="$ROLE" \ --condition=NonedoneJika gcloud meminta kondisi karena policy telah memiliki binding bersyarat, gunakan
--condition=None seperti pada contoh. Jangan memilih kondisi sementara milik koneksi
Cloud Build.
8. Periksa Artifact Registry bersama
Section titled “8. Periksa Artifact Registry bersama”gcloud artifacts repositories describe "$REPOSITORY" \ --location="$REGION"Jangan membuat repository katalog-images kembali. Semua asisten memakai repository
yang sama, tetapi nama image wajib berbeda melalui variabel IMAGE_NAME.
9. Siapkan identitas VM
Section titled “9. Siapkan identitas VM”VM memakai Compute Engine default Service Account. Service Account ini memerlukan akses untuk menarik image dari Artifact Registry. Service Account Cloud Build juga harus boleh bertindak pada identitas VM saat membuka SSH berbasis OS Login.
PROJECT_NUMBER="$(gcloud projects describe "$PROJECT_ID" \ --format='value(projectNumber)')"VM_SA="${PROJECT_NUMBER}-asisten01@example.com"
gcloud projects add-iam-policy-binding "$PROJECT_ID" \ --member="serviceAccount:$VM_SA" \ --role="roles/artifactregistry.reader" \ --condition=None
gcloud iam service-accounts add-iam-policy-binding "$VM_SA" \ --member="serviceAccount:$BUILD_SA" \ --role="roles/iam.serviceAccountUser" \ --condition=NoneBinding kedua sengaja diberikan pada VM_SA, bukan hanya pada project. Google
merekomendasikan pemberian roles/iam.serviceAccountUser pada Service Account tertentu
saat identitas tersebut dipakai oleh Compute Engine. Lihat
dokumentasi IAM Compute Engine.
10. Buat VM
Section titled “10. Buat VM”Konfigurasi yang telah diuji memakai e2-medium, Ubuntu 22.04 LTS, disk balanced 30 GB,
dan OS Login.
gcloud compute instances create "$VM_NAME" \ --zone="$ZONE" \ --machine-type="e2-medium" \ --image-family="ubuntu-2204-lts" \ --image-project="ubuntu-os-cloud" \ --boot-disk-size="30GB" \ --boot-disk-type="pd-balanced" \ --service-account="$VM_SA" \ --scopes="https://www.googleapis.com/auth/cloud-platform" \ --tags="webgis-http,webgis-iap-ssh" \ --metadata="enable-oslogin=TRUE"Jika VM sudah ada, jangan menjalankan perintah pembuatan kembali. Periksa statusnya:
gcloud compute instances describe "$VM_NAME" \ --zone="$ZONE" \ --format="table(name,status,machineType.basename(),networkInterfaces[0].accessConfigs[0].natIP)"11. Periksa firewall bersama
Section titled “11. Periksa firewall bersama”Firewall dibuat satu kali oleh akun master. Asisten hanya perlu memeriksa dua rule:
gcloud compute firewall-rules list \ --filter="name:(allow-webgis-http OR allow-webgis-iap-ssh)"
Gambar 3. VM berjalan dan dua rule firewall tersedia untuk dipakai bersama.
12. Masuk ke VM dan instal Docker
Section titled “12. Masuk ke VM dan instal Docker”Masuk ke VM melalui IAP:
gcloud compute ssh "$VM_NAME" \ --zone="$ZONE" \ --tunnel-through-iapJalankan perintah berikut di dalam VM untuk memasang Docker Engine, Docker Compose, Git, dan Google Cloud CLI.
sudo apt-get updatesudo apt-get install -y ca-certificates curl git gnupg
sudo install -m 0755 -d /etc/apt/keyringssudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ -o /etc/apt/keyrings/docker.ascsudo chmod a+r /etc/apt/keyrings/docker.asc
sudo tee /etc/apt/sources.list.d/docker.sources > /dev/null <<EOFTypes: debURIs: https://download.docker.com/linux/ubuntuSuites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")Components: stableArchitectures: $(dpkg --print-architecture)Signed-By: /etc/apt/keyrings/docker.ascEOF
sudo apt-get updatesudo apt-get install -y docker-ce docker-ce-cli containerd.io \ docker-buildx-plugin docker-compose-plugin
curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | \ sudo gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg
echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | \ sudo tee /etc/apt/sources.list.d/google-cloud-sdk.list > /dev/null
sudo apt-get updatesudo apt-get install -y google-cloud-cliPanduan instalasi Docker mengikuti dokumentasi resmi Docker untuk Ubuntu.
13. Periksa Docker dan gcloud CLI
Section titled “13. Periksa Docker dan gcloud CLI”Pastikan dua perangkat utama sudah terpasang sebelum menarik repository. Perintah
docker compose version harus menampilkan versi plugin Compose, bukan pesan bahwa
subperintah tidak dikenal.
sudo docker compose versionsudo docker run --rm hello-worldgcloud --versionJika docker run menolak dengan pesan izin, kelompok docker belum aktif untuk pengguna
saat ini. Tambahkan pengguna ke kelompok tersebut, keluar dari sesi SSH, lalu masuk kembali.
sudo usermod -aG docker "$USER"exitCloud Build menjalankan Docker sebagai root, jadi izin pengguna biasa tidak menghambat
deployment, tetapi perintah manual pada VM akan gagal tanpa perbaikan ini.
Siapkan juga folder aplikasi sebelum repository di-clone pada bagian berikutnya.
sudo mkdir -p /opt/webgissudo chown "$USER:$USER" /opt/webgisls -ld /opt/webgis14. Clone fork ke VM dan isi .env
Section titled “14. Clone fork ke VM dan isi .env”Container nextjs belum bisa dijalankan sebelum Cloud Build mengisi NEXTJS_IMAGE. Karena
itu urutan yang benar adalah clone, isi .env, hubungkan repository, buat trigger, baru push.
Setelah push, Cloud Build menarik image dan menyalakan container nextjs.
Clone fork
Section titled “Clone fork”Repository instruktur bersifat public, jadi clone cukup memakai HTTPS tanpa token. Ganti
GITHUB_USERNAME dengan username GitHub asisten.
GITHUB_USERNAME="ISI_USERNAME_GITHUB"GITHUB_REPOSITORY="https://github.com/${GITHUB_USERNAME}/personal-geoportal-peserta.git"git clone "$GITHUB_REPOSITORY" /opt/webgis/appcd /opt/webgis/appcp .env.example .envJika nama fork mengikuti nama bawaan personal-geoportal, sesuaikan URL-nya:
GITHUB_REPOSITORY="https://github.com/${GITHUB_USERNAME}/personal-geoportal.git"Periksa remote dan commit yang dipakai:
git remote -vgit log --oneline -1Commit dan push dikerjakan dari laptop yang sudah login GitHub, karena git push selalu
butuh kredensial walaupun repository public. VM hanya perlu membaca repository, jadi tidak
ada token yang perlu disimpan di VM.
Isi .env
Section titled “Isi .env”Ambil alamat IP eksternal VM dari Cloud Shell lain, atau catat nilai EXTERNAL_IP yang
muncul saat VM dibuat.
gcloud compute instances describe "$VM_NAME" \ --zone="$ZONE" \ --format='get(networkInterfaces[0].accessConfigs[0].natIP)'Buka .env pada VM:
nano /opt/webgis/app/.envIsi dengan pola berikut. Ganti IP_EKSTERNAL_VM dan dua nilai secret. Jangan memasukkan
file .env yang sudah terisi ke Git.
NEXTJS_IMAGE=DATABASE_URL=JWT_SECRET=ISI_SECRET_ACAKJWT_EXPIRES_IN=1hNEXTAUTH_SECRET=ISI_SECRET_ACAK_BERBEDANEXTAUTH_URL=http://IP_EKSTERNAL_VM/portal/AUTH_API_URL=http://localhost:3000/portal/apiBuat dua secret yang berbeda:
openssl rand -hex 32openssl rand -hex 32NEXTJS_IMAGE sengaja dibiarkan kosong pada setup awal. Cloud Build akan mengisinya dengan
tag image yang baru selesai dibangun. Untuk menguji build, Nginx, dan halaman publik,
DATABASE_URL boleh kosong. Login, Prisma, dan fitur katalog memerlukan database yang valid.
Nyalakan GeoServer dan Nginx lebih dahulu
Section titled “Nyalakan GeoServer dan Nginx lebih dahulu”Dua container ini tidak menunggu Cloud Build, jadi bisa dinyalakan sekarang untuk memastikan
berkas konfigurasi sudah benar. Langkah ini juga memicu pembuatan data directory GeoServer
pertama kali, jadi container geoserver_app terasa lambat pada percobaan pertama.
cd /opt/webgis/appsudo docker compose up -d geoserver nginxsudo docker compose psdocker compose up untuk nextjs belum bisa dijalankan karena NEXTJS_IMAGE masih kosong.
Biarkan container nextjs dibuat oleh Cloud Build.
Periksa instalasi, lalu keluar dari VM:
sudo docker compose versiongcloud --versionexit15. Hubungkan repository GitHub
Section titled “15. Hubungkan repository GitHub”Lakukan langkah berikut pada Google Cloud Console:
- Buka Cloud Build, lalu pilih Repositories.
- Pilih Connect repository.
- Isi nama connection sesuai
CONNECTION_NAME, misalnyagithub-nama01. - Pilih GitHub dan login memakai akun pemilik fork.
- Izinkan Cloud Build GitHub App hanya untuk repository pelatihan jika memungkinkan.
- Pilih repository fork asisten.
- Isi nama linked repository sesuai
LINKED_REPO_NAME, misalnyarepo-nama01. - Selesaikan koneksi dan pastikan statusnya
COMPLETE.
Jika halaman meminta Secret Manager API, kembali ke bagian 6 dan pastikan
secretmanager.googleapis.com sudah aktif.
Satu project dapat memiliki beberapa GitHub connection. Jangan menghapus atau mengubah connection asisten lain.
16. Buat trigger Cloud Build
Section titled “16. Buat trigger Cloud Build”Buat trigger dengan konfigurasi berikut:
| Pengaturan | Nilai |
|---|---|
| Event | Push to a branch |
| Repository | Fork milik asisten |
| Branch | ^main$ |
| Configuration | Cloud Build configuration file |
| File | cloudbuild.yaml |
| Trigger name | Nilai TRIGGER_NAME, misalnya deploy-nama01 |
| Service Account | Nilai BUILD_SA, misalnya cb-deployer-nama01@PROJECT_ID.iam.gserviceaccount.com |
Tambahkan empat substitution variable berikut. Keempatnya wajib diisi. Berkas
cloudbuild.yaml pada fork tidak lagi menyediakan nilai bawaan untuk variabel ini, jadi
build akan berhenti dengan pesan yang menyebut nama variabel yang kosong. Kegagalan itu
disengaja: tanpa nilai unik, image akan memakai satu nama bersama dan menimpa image milik
asisten lain di Artifact Registry.
_VM_NAME = webgis-nama01_VM_ZONE = asia-southeast2-b_VM_APP_DIR = /opt/webgis/app_IMAGE_NAME = nextjs-nama01Ganti suffix nama01 sesuai PARTICIPANT_ID. Nilai _VM_NAME, _IMAGE_NAME, dan Service
Account harus menunjuk ke resource milik asisten yang sama. Simpan trigger, lalu pilih
Run. Push berikutnya ke branch main akan menjalankan build, push image unik, login ke
VM asisten melalui IAP, mengisi NEXTJS_IMAGE, menarik image, dan menjalankan Docker
Compose.
17. Push dari laptop dan jalankan build
Section titled “17. Push dari laptop dan jalankan build”Commit dilakukan dari laptop, bukan dari VM. Push inilah yang memicu trigger dan menjalankan seluruh step Cloud Build.
cd personal-geoportal-pesertagit status --shortgit add docker-compose.yml nginx.conf cloudbuild.yaml .gitignoregit commit -m "feat: tambah GeoServer dan rute nginx"git push origin mainPastikan berkas .env yang sudah terisi tidak ikut ter-commit. Periksa dengan
git status --short sebelum git add, dan jangan pernah memakai git add . tanpa
memeriksa daftar berkas terlebih dahulu.
18. Verifikasi Cloud Build dan container
Section titled “18. Verifikasi Cloud Build dan container”Build yang berhasil menampilkan seluruh step dengan status hijau.

Gambar 4. Build, push, dan deployment SSH selesai tanpa error.
Periksa container dari Cloud Shell. Ada tiga container yang harus terlihat: nextjs_portal,
geoserver_app, dan nginx_proxy.
gcloud compute ssh "$VM_NAME" \ --zone="$ZONE" \ --tunnel-through-iap \ --command='cd /opt/webgis/app && sudo docker compose ps'
Gambar 5. Tangkapan lama ini baru menampilkan container nextjs dan nginx. Setelah
GeoServer masuk, daftar container bertambah satu.
Cloud Build hanya menarik image nextjs. Container geoserver_app dan nginx_proxy sudah
berjalan sejak bagian 14 dan tidak ikut dibangun ulang. Jika Cloud Build hijau tetapi
geoserver_app hilang, berarti docker-compose.yml di VM masih versi dua container dan
perlu disinkronkan seperti pada bagian 25.
19. Buka GeoServer
Section titled “19. Buka GeoServer”GeoServer berjalan di belakang Nginx pada port 8080 di dalam jaringan container, jadi port tersebut tidak dibuka ke internet. Akses masuk melalui Nginx pada alamat berikut:
EXTERNAL_IP="$(gcloud compute instances describe "$VM_NAME" \ --zone="$ZONE" \ --format='get(networkInterfaces[0].accessConfigs[0].natIP)')"
echo "http://${EXTERNAL_IP}/geoserver/web/"curl -sSIL --max-redirs 3 "http://${EXTERNAL_IP}/geoserver/web/"Login memakai nilai GEOSERVER_ADMIN_USER dan GEOSERVER_ADMIN_PASSWORD pada
docker-compose.yml, bukan admin dan geoserver bawaan image.
Container GeoServer memerlukan waktu boot paling lama di antara tiga container. Periksa log sampai muncul penanda selesai:
gcloud compute ssh "$VM_NAME" \ --zone="$ZONE" \ --tunnel-through-iap \ --command='sudo docker compose -f /opt/webgis/app/docker-compose.yml logs --tail=40 geoserver'Jika halaman tidak terbuka, periksa tiga hal berurutan:
docker compose psmenampilkangeoserver_appdengan statusrunning.curl -sS http://localhost:8080/geoserver/web/dari dalam VM menghasilkan HTML.- Blok
location /geoserver/padanginx.confsudah ikut ter-push ke VM. Berkas Nginx berasal dari clone repository, bukan dari image, jadi perubahannginx.confperlu sinkronisasi seperti pada bagian 25.
20. Unggah data spasial ke GeoServer
Section titled “20. Unggah data spasial ke GeoServer”Bagian ini adalah inti pengujian. Tujuannya membuktikan bahwa GeoServer di VM benar-benar
menerima data spasial baru, bukan hanya bisa dibuka. Gunakan berkas contoh
batas_admin.geojson atau jalan.geojson dari folder public/data/ pada repository fork.
Buat workspace
Section titled “Buat workspace”- Buka Data, lalu Workspaces.
- Pilih Add new workspace.
- Isi Name dengan
geoportaldan Namespace URI denganhttp://IP_EKSTERNAL_VM/geoportal. - Pilih Save.
Unggah berkas GeoJSON
Section titled “Unggah berkas GeoJSON”- Buka Stores, lalu Add new store.
- Pilih GeoJSON pada daftar Vector Data Sources.
- Pilih workspace
geoportal. - Isi Data Source Name dengan
batas_admin. - Pada bagian Connection Parameters, unggah berkas
batas_admin.geojsondengan tombol Browse. - Pilih Save, lalu pada halaman New Layer pilih Publish.
- Pada tab Data, tekan Compute from data dan Compute from native bounds.
- Pilih Save.
Atur izin baca publik
Section titled “Atur izin baca publik”Layer baru hanya bisa dilihat pengguna yang login. Untuk menguji endpoint publik:
- Buka Security, lalu Layers.
- Cari
geoportal:batas_admin. - Pilih ROLE_ANONYMOUS, lalu aktifkan Read.
- Pilih Save.
Jika langkah ini terlewat, permintaan WMS akan menampilkan halaman login, bukan gambar peta.
21. Verifikasi data hasil unggah
Section titled “21. Verifikasi data hasil unggah”Periksa kapabilitas dan geometri melalui endpoint WFS. Ganti NAMA_LAYER dengan nama layer
yang barusan dibuat, misalnya geoportal:batas_admin.
EXTERNAL_IP="$(gcloud compute instances describe "$VM_NAME" \ --zone="$ZONE" \ --format='get(networkInterfaces[0].accessConfigs[0].natIP)')"NAMA_LAYER="geoportal:batas_admin"
curl -sS "http://${EXTERNAL_IP}/geoserver/wfs?service=WFS&version=2.0.0&request=GetFeature&typeNames=${NAMA_LAYER}&outputFormat=application/json&count=1"Data dinyatakan berhasil diunggah jika perintah tersebut mengembalikan JSON dengan isi
features. Jika jawabannya ServiceException tentang layer yang tidak ditemukan, periksa
kembali nama workspace dan nama layer pada antarmuka GeoServer.
Data yang sudah diunggah tersimpan pada volume ./geoserver-data di VM, sehingga bertahan
setelah container di-restart. Restart container satu kali untuk membuktikan hal ini:
gcloud compute ssh "$VM_NAME" \ --zone="$ZONE" \ --tunnel-through-iap \ --command='cd /opt/webgis/app && sudo docker compose restart geoserver'Ulangi perintah WFS setelah GeoServer selesai boot. Jika layer hilang setelah restart, catat sebagai temuan karena volume tidak terpasang dengan benar.
22. Buka Geoportal
Section titled “22. Buka Geoportal”Ambil alamat IP eksternal:
EXTERNAL_IP="$(gcloud compute instances describe "$VM_NAME" \ --zone="$ZONE" \ --format='get(networkInterfaces[0].accessConfigs[0].natIP)')"
echo "http://${EXTERNAL_IP}/portal/"curl -sSIL --max-redirs 3 "http://${EXTERNAL_IP}/portal/"Buka URL yang dicetak oleh perintah tersebut. Gunakan trailing slash pada /portal/.

Gambar 6. Geoportal hasil deployment dapat diakses melalui browser.
23. Catat temuan spesifikasi default
Section titled “23. Catat temuan spesifikasi default”Catat keadaan VM sebelum ada perubahan konfigurasi apa pun. Data inilah yang menentukan
apakah heap -Xmx2048m cukup untuk e2-medium.
gcloud compute ssh "$VM_NAME" \ --zone="$ZONE" \ --tunnel-through-iap \ --command='free -h && sudo docker stats --no-stream && sudo docker inspect --format "{{.Name}} OOMKilled={{.State.OOMKilled}}" geoserver_app'Isi hasilnya ke tabel bukti pada workbook asisten trainer. Jika
OOMKilled=true atau memori tersisa di bawah 300 MB, turunkan heap GeoServer dengan
mengubah MAXIMUM_MEMORY menjadi 1024m, lalu jalankan sudo docker compose up -d geoserver.
Jangan mengubah tipe mesin sebelum temuan ini dicatat lebih dahulu. Pengukuran lima VM
serentak ada pada bagian 12 di workbook asisten trainer.
24. Daftarkan domain dan arahkan DNS ke VM
Section titled “24. Daftarkan domain dan arahkan DNS ke VM”Bagian ini dijalankan jika setiap peserta pelatihan diminta membeli satu domain. Harga bergantung pada akhiran domain yang dipilih. Registrasi memiliki komitmen satu tahun dan perpanjangan otomatis aktif secara default. Cloud DNS ditagih terpisah. Periksa harga yang ditampilkan sebelum menyelesaikan pembelian.
Cloud Domains tidak mengirim hak akses ke Billing Account kepada peserta pelatihan. Biaya domain masuk ke Billing Account yang sudah terhubung dengan project. Registrasi domain tidak dapat dipindahkan ke project GCP lain setelah dibuat.
Reservasi alamat IP
Section titled “Reservasi alamat IP”Promosikan alamat IP eksternal VM menjadi static IP sebelum membuat record DNS:
EXTERNAL_IP="$(gcloud compute instances describe "$VM_NAME" \ --zone="$ZONE" \ --format='get(networkInterfaces[0].accessConfigs[0].natIP)')"
gcloud compute addresses create "$STATIC_IP_NAME" \ --region="$REGION" \ --addresses="$EXTERNAL_IP"
gcloud compute addresses describe "$STATIC_IP_NAME" \ --region="$REGION" \ --format="table(name,address,status)"Nama static IP memakai slug asisten. Jangan memakai nama static IP asisten lain.
Daftarkan domain
Section titled “Daftarkan domain”- Buka Cloud Domains pada Google Cloud Console.
- Pilih Register domain.
- Terima persyaratan Squarespace jika diminta.
- Cari nama domain dan periksa harga tahunannya.
- Pilih Use Cloud DNS dan buat zone baru dengan nama sesuai
DNS_ZONE_NAME. - Isi data kontak registrant dengan data yang benar.
- Periksa kembali biaya, lalu selesaikan registrasi.
- Buka email registrant dan selesaikan verifikasi maksimal 15 hari setelah registrasi.
Dokumentasi resmi tersedia pada panduan registrasi Cloud Domains dan harga Cloud Domains.
Buat record DNS
Section titled “Buat record DNS”Ambil IP eksternal VM:
EXTERNAL_IP="$(gcloud compute instances describe "$VM_NAME" \ --zone="$ZONE" \ --format='get(networkInterfaces[0].accessConfigs[0].natIP)')"
echo "$EXTERNAL_IP"Buka Network services, lalu Cloud DNS, kemudian pilih managed zone domain. Buat record berikut:
| DNS name | Jenis | TTL | Data |
|---|---|---|---|
| Nama domain utama | A |
300 |
IP eksternal VM |
www |
CNAME |
300 |
Nama domain utama dengan titik di akhir |
Contoh nilai CNAME untuk domain contoh.com adalah contoh.com.. Tunggu propagasi,
lalu periksa dari Cloud Shell:
DOMAIN_NAME="contoh.com"
dig +short "$DOMAIN_NAME"dig +short "www.$DOMAIN_NAME"curl -sSIL --max-redirs 3 "http://${DOMAIN_NAME}/portal/"Jika record sudah resolve, buka http://DOMAIN_ANDA/portal/. Konfigurasi VM yang diuji
memakai alamat IP eksternal sementara. IP dapat berubah setelah VM dihentikan dan
dinyalakan. Jika berubah, perbarui record A atau gunakan static external IP.
Catatan HTTPS
Section titled “Catatan HTTPS”Tidak ada role GCP tambahan untuk alur Let’s Encrypt atau Certbot pada modul. Role
roles/compute.osAdminLogin memberi peserta pelatihan akses administratif pada VM. Firewall
bersama allow-webgis-http sudah membuka port 80 dan 443 untuk VM dengan network tag
webgis-http. Jangan membuat firewall HTTPS baru untuk setiap asisten.
Deployment yang telah diuji menjalankan Nginx di dalam container. Perintah
certbot --nginx pada host dari modul tidak dapat langsung dipakai karena plugin tersebut
mencari Nginx host, sedangkan port 80 dipakai container. Jadikan HTTPS sebagai checkpoint
terpisah. Sertifikat harus diterbitkan dengan metode yang sesuai, dipasang ke container,
dan Nginx container harus memiliki konfigurasi port 443 sebelum HTTPS dinyatakan selesai.
Lihat juga catatan Modul 5.
Google Certificate Manager tidak digunakan pada alur modul ini. Karena itu,
roles/certificatemanager.editor dan Certificate Manager API tidak perlu diberikan.
Jika domain hanya dipakai untuk pengujian dan tidak ingin diperpanjang tahun berikutnya, matikan perpanjangan otomatis pada pengaturan registrasi Cloud Domains setelah pengujian. Biaya periode satu tahun yang sudah dibeli tetap berlaku.
25. Sinkronkan file konfigurasi VM bila berubah
Section titled “25. Sinkronkan file konfigurasi VM bila berubah”Cloud Build membangun image aplikasi, tetapi docker-compose.yml, .env, dan
nginx.conf berada pada clone repository di VM. Perubahan file tersebut tidak otomatis
masuk ke VM hanya karena image baru berhasil dibangun.
Jika file konfigurasi repository berubah setelah clone awal, sinkronkan dan muat ulang:
gcloud compute ssh "$VM_NAME" \ --zone="$ZONE" \ --tunnel-through-iap \ --command='cd /opt/webgis/app && git pull --ff-only && sudo docker compose up -d && sudo docker compose exec -T nginx nginx -s reload'Jangan menjalankan git pull jika clone di VM memiliki perubahan lokal yang belum
disimpan. Periksa dahulu dengan git status --short.
26. Troubleshooting berdasarkan hasil pengujian
Section titled “26. Troubleshooting berdasarkan hasil pengujian”IAM meminta kondisi
Section titled “IAM meminta kondisi”Gejala:
The policy contains bindings with conditions, so specifying a condition is requiredPenyebabnya adalah project telah memiliki binding bersyarat, biasanya dari koneksi Cloud
Build. Tambahkan --condition=None pada binding baru. Ini menyatakan bahwa role baru tidak
memakai kondisi.
Trigger menampilkan could not parse resource []
Section titled “Trigger menampilkan could not parse resource []”Penyebabnya adalah _VM_NAME atau _VM_ZONE kosong. Buka konfigurasi trigger dan isi
empat substitution variable pada bagian 16. Error ini bukan masalah firewall atau SSH.
SSH menampilkan Permission denied (publickey)
Section titled “SSH menampilkan Permission denied (publickey)”Cloud Build sudah mencapai IAP, tetapi Service Account deployment belum boleh bertindak pada Service Account VM. Jalankan kembali binding berikut:
PROJECT_NUMBER="$(gcloud projects describe "$PROJECT_ID" \ --format='value(projectNumber)')"VM_SA="${PROJECT_NUMBER}-asisten01@example.com"
gcloud iam service-accounts add-iam-policy-binding "$VM_SA" \ --member="serviceAccount:$BUILD_SA" \ --role="roles/iam.serviceAccountUser" \ --condition=NoneArtifact Registry menampilkan Unauthenticated request
Section titled “Artifact Registry menampilkan Unauthenticated request”Pastikan Service Account VM memiliki roles/artifactregistry.reader:
gcloud projects add-iam-policy-binding "$PROJECT_ID" \ --member="serviceAccount:$VM_SA" \ --role="roles/artifactregistry.reader" \ --condition=NoneDeployment yang diuji memakai access token singkat dari identitas VM. Google merekomendasikan access token atau credential helper dibanding Service Account key JSON. Lihat autentikasi Docker untuk Artifact Registry.
Jika login berhasil tetapi pull masih unauthenticated, periksa pengguna yang menjalankan
Docker. Perintah sudo docker membaca /root/.docker/config.json, bukan konfigurasi
Docker milik user biasa. cloudbuild.yaml final memakai sudo gcloud auth print-access-token, sudo docker login, dan sudo -H docker compose agar kredensial
dibaca oleh user yang sama.
NEXTJS_IMAGE belum memiliki nilai
Section titled “NEXTJS_IMAGE belum memiliki nilai”Gejala:
required variable NEXTJS_IMAGE is missing a valueTrigger belum berhasil menyimpan tag image ke /opt/webgis/app/.env. Jalankan trigger
sampai seluruh step hijau. Setelah itu, periksa nilai tanpa menampilkan isi secret lain:
gcloud compute ssh "$VM_NAME" \ --zone="$ZONE" \ --tunnel-through-iap \ --command="sudo grep '^NEXTJS_IMAGE=' /opt/webgis/app/.env"Browser menampilkan ERR_TOO_MANY_REDIRECTS
Section titled “Browser menampilkan ERR_TOO_MANY_REDIRECTS”Masalah ini berasal dari perbedaan URL kanonik antara Nginx dan Next.js, bukan dari
browser. Konfigurasi final repository memakai basePath: "/portal" dan
trailingSlash: true, sedangkan Nginx memproksi seluruh path melalui location /.
Pastikan VM memakai commit terbaru dan muat ulang Nginx dengan perintah pada bagian 25.
Kemudian akses http://IP_EKSTERNAL_VM/portal/. Menghapus cookie hanya diperlukan jika
browser masih menyimpan redirect lama setelah konfigurasi server dipastikan benar.
Container GeoServer mati sendiri atau keluar dengan kode 137
Section titled “Container GeoServer mati sendiri atau keluar dengan kode 137”Gejala:
geoserver_app Exited (137)Periksa apakah container dihentikan oleh kernel karena kehabisan memori:
gcloud compute ssh "$VM_NAME" \ --zone="$ZONE" \ --tunnel-through-iap \ --command='sudo docker inspect --format "{{.State.OOMKilled}}" geoserver_app && free -h'Nilai true berarti heap GeoServer melebihi memori yang tersedia. VM e2-medium hanya
memiliki 4 GB, sedangkan heap default MAXIMUM_MEMORY=2048m ditambah overhead JVM dan
Tomcat memakai sekitar 2,5 GB. Turunkan heap sebelum mempertimbangkan tipe mesin lain:
environment: - INITIAL_MEMORY=256m - MAXIMUM_MEMORY=1024mMuat ulang container setelah berkas diubah:
gcloud compute ssh "$VM_NAME" \ --zone="$ZONE" \ --tunnel-through-iap \ --command='cd /opt/webgis/app && sudo docker compose up -d geoserver && sudo docker compose ps'Catat nilai free -h sebelum dan sesudah perubahan pada
workbook asisten trainer. Data ini yang menentukan apakah
e2-medium tetap layak dipakai untuk pelatihan atau perlu dinaikkan ke e2-standard-2.
Halaman /geoserver/web/ menampilkan 502 atau 404
Section titled “Halaman /geoserver/web/ menampilkan 502 atau 404”Nginx container belum memuat rute GeoServer. Rute tersebut berasal dari nginx.conf pada
repository fork. Pastikan commit berisi blok location /geoserver/, lalu sinkronkan berkas
konfigurasi ke VM dan muat ulang Nginx seperti pada bagian 25.
Jika Nginx sudah benar tetapi tetap 502, periksa container tujuan:
gcloud compute ssh "$VM_NAME" \ --zone="$ZONE" \ --tunnel-through-iap \ --command='cd /opt/webgis/app && sudo docker compose ps && sudo docker compose logs --tail=30 geoserver'Kata sandi admin GeoServer kembali ke nilai bawaan setelah restart
Section titled “Kata sandi admin GeoServer kembali ke nilai bawaan setelah restart”Kata sandi yang diubah lewat antarmuka web tidak bertahan karena image membaca
GEOSERVER_ADMIN_PASSWORD setiap kali container dijalankan. Isi variabel tersebut pada
docker-compose.yml, lalu jalankan sudo docker compose up -d geoserver.
27. Hentikan VM setelah selesai
Section titled “27. Hentikan VM setelah selesai”Jalankan dari Cloud Shell agar biaya compute berhenti saat VM tidak digunakan:
gcloud compute instances stop "$VM_NAME" \ --zone="$ZONE"Nyalakan kembali saat melanjutkan latihan:
gcloud compute instances start "$VM_NAME" \ --zone="$ZONE"Setelah VM menyala kembali, alamat IP eksternal dapat berubah jika alamat tersebut belum
direservasi. Ambil IP terbaru dan sesuaikan NEXTAUTH_URL bila diperlukan.