1. Ringkasan
Lab ini mendemonstrasikan fitur dan kemampuan yang dirancang untuk menyederhanakan alur kerja pengembangan bagi engineer software yang bertugas mengembangkan aplikasi Java di lingkungan dalam container. Pengembangan container yang umum mengharuskan pengguna memahami detail container dan proses build container. Selain itu, developer biasanya harus menghentikan alur kerja mereka, keluar dari IDE untuk menguji dan men-debug aplikasi mereka di lingkungan jarak jauh. Dengan alat dan teknologi yang disebutkan dalam tutorial ini, developer dapat bekerja secara efektif dengan aplikasi yang di-containerisasi tanpa keluar dari IDE mereka.
Yang akan Anda pelajari
Dalam lab ini, Anda akan mempelajari metode untuk mengembangkan dengan container di GCP, termasuk:
- Pengembangan InnerLoop dengan Cloud Workstations
- Membuat aplikasi awal Java baru
- Menjelaskan proses pengembangan
- Mengembangkan Layanan Rest CRUD sederhana
- Proses debug aplikasi di cluster GKE
- Menghubungkan aplikasi ke database CloudSQL

2. Penyiapan dan Persyaratan
Penyiapan lingkungan mandiri
- Login ke Google Cloud Console dan buat project baru atau gunakan kembali project yang sudah ada. Jika belum memiliki akun Gmail atau Google Workspace, Anda harus membuatnya.



- Project name adalah nama tampilan untuk peserta project ini. String ini adalah string karakter yang tidak digunakan oleh Google API. Anda dapat memperbaruinya kapan saja.
- Project ID bersifat unik di semua project Google Cloud dan tidak dapat diubah (tidak dapat diubah setelah ditetapkan). Cloud Console otomatis membuat string unik; biasanya Anda tidak mementingkan kata-katanya. Di sebagian besar codelab, Anda harus merujuk Project ID-nya (biasanya diidentifikasi sebagai
PROJECT_ID). Jika tidak suka dengan ID yang dibuat, Anda dapat membuat ID acak lainnya. Atau, Anda dapat mencobanya sendiri dan melihat apakah ID tersebut tersedia. ID tidak dapat diubah setelah langkah ini dan akan tetap ada selama durasi project. - Sebagai informasi, ada nilai ketiga, Project Number yang digunakan oleh beberapa API. Pelajari lebih lanjut ketiga nilai ini di dokumentasi.
- Selanjutnya, Anda harus mengaktifkan penagihan di Konsol Cloud untuk menggunakan resource/API Cloud. Menjalankan operasi dalam codelab ini seharusnya tidak memerlukan banyak biaya, bahkan mungkin tidak sama sekali. Guna mematikan resource agar tidak menimbulkan penagihan di luar tutorial ini, Anda dapat menghapus resource yang dibuat atau menghapus seluruh project. Pengguna baru Google Cloud memenuhi syarat untuk mengikuti program Uji Coba Gratis senilai $300 USD.
Mulai Cloud Shell Editor
Lab ini dirancang dan diuji untuk digunakan dengan Editor Google Cloud Shell. Untuk mengakses editor:
- mengakses project google Anda di https://console.cloud.google.com.
- Di pojok kanan atas, klik ikon editor cloud shell

- Panel baru akan terbuka di bagian bawah jendela
- Klik tombol Open Editor

- Editor akan terbuka dengan penjelajah di sebelah kanan dan editor di area tengah
- Panel terminal juga harus tersedia di bagian bawah layar
- Jika terminal TIDAK terbuka, gunakan kombinasi tombol `ctrl+`` untuk membuka jendela terminal baru
Menyiapkan gcloud
Di Cloud Shell, tetapkan project ID dan region tempat Anda ingin men-deploy aplikasi. Simpan sebagai variabel PROJECT_ID dan REGION.
export REGION=us-central1
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
Buat clone kode sumber
Kode sumber untuk lab ini terletak di container-developer-workshop di GoogleCloudPlatform di GitHub. Buat clone dengan perintah di bawah, lalu ubah ke direktori.
git clone https://github.com/GoogleCloudPlatform/container-developer-workshop.git
cd container-developer-workshop/labs/spring-boot
Menyediakan infrastruktur yang digunakan dalam lab ini
Di lab ini, Anda akan men-deploy kode ke GKE dan mengakses data yang disimpan dalam database CloudSQL. Skrip penyiapan di bawah akan menyiapkan infrastruktur ini untuk Anda. Proses penyediaan akan memakan waktu lebih dari 25 menit. Tunggu hingga skrip selesai sebelum melanjutkan ke bagian berikutnya.
./setup_with_cw.sh &
Cluster Cloud Workstations
Buka Cloud Workstations di Konsol Cloud. Tunggu hingga cluster berstatus READY.
Membuat Konfigurasi Workstation
Jika sesi Cloud Shell Anda terputus, klik "Reconnect", lalu jalankan perintah gcloud cli untuk menetapkan project ID. Ganti project ID contoh di bawah dengan project ID qwiklabs Anda sebelum menjalankan perintah.
gcloud config set project qwiklabs-gcp-project-id
Jalankan skrip di bawah di terminal untuk membuat konfigurasi Cloud Workstations.
cd ~/container-developer-workshop/labs/spring-boot
./workstation_config_setup.sh
Verifikasi hasil di bagian Konfigurasi. Perlu waktu 2 menit untuk beralih ke status SIAP.

Buka Cloud Workstations di Konsol dan buat instance baru.

Ubah nama menjadi my-workstation dan pilih konfigurasi yang ada: codeoss-java.

Verifikasi hasil di bagian Workstations.

Meluncurkan Workstation
Mulai dan luncurkan workstation.

Izinkan cookie pihak ketiga dengan mengklik ikon di kolom URL. 

Klik "Situs tidak berfungsi?".

Klik "Izinkan cookie".

Setelah workstation diluncurkan, Anda akan melihat IDE Code OSS muncul. Klik "Mark Done" di halaman Getting Started pada IDE workstation

3. Membuat aplikasi awal Java baru
Di bagian ini, Anda akan membuat aplikasi Java Spring Boot baru dari awal menggunakan aplikasi contoh yang disediakan oleh spring.io. Buka Terminal baru.

Meng-clone Aplikasi Contoh
- Membuat aplikasi awal
curl https://start.spring.io/starter.zip -d dependencies=web -d type=maven-project -d javaVersion=17 -d packageName=com.example.springboot -o sample-app.zip
Klik tombol Izinkan jika Anda melihat pesan ini, sehingga Anda dapat menyalin dan menempel ke workstation.

- Buka aplikasi
unzip sample-app.zip -d sample-app
- Buka folder "sample-app"
cd sample-app && code-oss-cloud-workstations -r --folder-uri="$PWD"
Tambahkan spring-boot-devtools & Jib
Untuk mengaktifkan Spring Boot DevTools, temukan dan buka pom.xml dari penjelajah di editor Anda. Selanjutnya, tempel kode berikut setelah baris deskripsi yang berbunyi <description>Demo project for Spring Boot</description>
- Tambahkan spring-boot-devtools di pom.xml
Buka pom.xml di root project. Tambahkan konfigurasi berikut setelah entri Description.
pom.xml
<!-- Spring profiles-->
<profiles>
<profile>
<id>sync</id>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</profile>
</profiles>
- Aktifkan jib-maven-plugin di pom.xml
Jib adalah alat pembuatan container Java open source dari Google yang memungkinkan developer Java membuat container menggunakan alat Java yang mereka kenal. Jib adalah builder image container yang cepat dan sederhana yang menangani semua langkah pengemasan aplikasi Anda ke dalam image container. Plugin ini tidak mengharuskan Anda menulis Dockerfile atau menginstal Docker, dan terintegrasi langsung ke Maven dan Gradle.
Scroll ke bawah dalam file pom.xml dan perbarui bagian Build untuk menyertakan plugin Jib. Bagian build akan cocok dengan berikut ini setelah selesai.
pom.xml
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- Jib Plugin-->
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>3.2.0</version>
</plugin>
<!-- Maven Resources Plugin-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
</plugin>
</plugins>
</build>
Membuat Manifes
Skaffold menyediakan alat terintegrasi untuk menyederhanakan pengembangan container. Pada langkah ini, Anda akan menginisialisasi Skaffold yang akan otomatis membuat file YAML Kubernetes dasar. Proses ini mencoba mengidentifikasi direktori dengan definisi image container, seperti Dockerfile, lalu membuat manifes deployment dan layanan untuk setiap direktori.
Jalankan perintah di bawah ini di Terminal untuk memulai proses.

- Jalankan perintah berikut di terminal
skaffold init --generate-manifests
- Saat diminta:
- Gunakan tombol panah untuk memindahkan kursor ke
Jib Maven Plugin - Tekan tombol spasi untuk memilih opsi.
- Tekan enter untuk melanjutkan
- Masukkan 8080 untuk port
- Masukkan y untuk menyimpan konfigurasi
Dua file ditambahkan ke ruang kerja skaffold.yaml dan deployment.yaml
Output Skaffold:

Perbarui nama aplikasi
Nilai default yang disertakan dalam konfigurasi saat ini tidak cocok dengan nama aplikasi Anda. Perbarui file untuk mereferensikan nama aplikasi Anda, bukan nilai default.
- Mengubah entri dalam konfigurasi Skaffold
- Buka
skaffold.yaml - Pilih nama gambar yang saat ini ditetapkan sebagai
pom-xml-image - Klik kanan, lalu pilih Ubah Semua Kemunculan
- Ketik nama baru sebagai
demo-app
- Mengubah entri dalam konfigurasi Kubernetes
- Buka file
deployment.yaml - Pilih nama gambar yang saat ini ditetapkan sebagai
pom-xml-image - Klik kanan, lalu pilih Ubah Semua Kemunculan
- Ketik nama baru sebagai
demo-app
Mengaktifkan mode Sinkronisasi otomatis
Untuk memfasilitasi pengalaman hot reload yang dioptimalkan, Anda akan menggunakan fitur Sinkronisasi yang disediakan oleh Jib. Pada langkah ini, Anda akan mengonfigurasi Skaffold untuk menggunakan fitur tersebut dalam proses build.
Perhatikan bahwa profil "sync" yang Anda konfigurasi dalam konfigurasi Skaffold memanfaatkan Profil "sync" Spring yang telah Anda konfigurasi pada langkah sebelumnya, tempat Anda mengaktifkan dukungan untuk spring-dev-tools.
- Memperbarui konfigurasi Skaffold
Dalam file skaffold.yaml, ganti seluruh bagian build file dengan spesifikasi berikut. Jangan ubah bagian lain dari file.
skaffold.yaml
build:
artifacts:
- image: demo-app
jib:
project: com.example:demo
type: maven
args:
- --no-transfer-progress
- -Psync
fromImage: gcr.io/distroless/java17-debian11:debug
sync:
auto: true
Menambahkan rute default
Buat file bernama HelloController.java di folder /src/main/java/com/example/springboot/.

Tempel konten berikut dalam file untuk membuat rute http default.
HelloController.java
package com.example.springboot;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.beans.factory.annotation.Value;
@RestController
public class HelloController {
@Value("${target:local}")
String target;
@GetMapping("/")
public String hello()
{
return String.format("Hello from your %s environment!", target);
}
}
4. Menjelaskan proses pengembangan
Di bagian ini, Anda akan mempelajari beberapa langkah menggunakan plugin Cloud Code untuk mempelajari proses dasar dan memvalidasi konfigurasi serta penyiapan aplikasi starter Anda.
Cloud Code terintegrasi dengan Skaffold untuk menyederhanakan proses pengembangan Anda. Saat Anda men-deploy ke GKE dalam langkah-langkah berikut, Cloud Code dan Skaffold akan otomatis membangun image container Anda, mengirimkannya ke Container Registry, lalu men-deploy aplikasi Anda ke GKE. Hal ini terjadi di balik layar dengan mengabstraksi detail dari alur developer. Cloud Code juga meningkatkan proses pengembangan Anda dengan menyediakan kemampuan debug dan sinkronisasi cepat tradisional untuk pengembangan berbasis container.
Login ke Google Cloud
Klik ikon Cloud Code, lalu pilih "Sign in to Google Cloud":

Klik "Lanjutkan untuk login".

Periksa output di Terminal dan buka link:

Login dengan kredensial siswa Qwiklabs Anda.

Pilih "Izinkan":

Salin kode verifikasi dan kembali ke tab Workstation.

Tempelkan kode verifikasi, lalu tekan Enter.

Menambahkan Cluster Kubernetes
- Menambahkan Cluster

- Pilih Google Kubernetes Engine:

- Pilih project.

- Pilih "quote-cluster" yang dibuat pada penyiapan awal.


Menetapkan project id saat ini menggunakan gcloud CLI
Salin project ID untuk lab ini dari halaman qwiklabs.

Jalankan perintah gcloud CLI untuk menetapkan project ID. Ganti project ID contoh sebelum menjalankan perintah.
gcloud config set project qwiklabs-gcp-project-id
Contoh output:

Melakukan debug di Kubernetes
- Di panel kiri di bagian bawah, pilih Cloud Code.

- Di panel yang muncul di bagian SESI PENGEMBANGAN, pilih Debug di Kubernetes.
Scroll ke bawah jika opsi tidak terlihat.

- Pilih "Ya" untuk menggunakan konteks saat ini.

- Pilih "quote-cluster" yang dibuat selama penyiapan awal.

- Pilih Container Repository.

- Pilih tab Output di panel bawah untuk melihat progres dan notifikasi
- Pilih "Kubernetes: Run/Debug - Detailed" di drop-down channel di sebelah kanan untuk melihat detail tambahan dan streaming log secara live dari penampung

Tunggu hingga aplikasi di-deploy.

- Tinjau aplikasi yang di-deploy di GKE di Cloud Console.

- Kembali ke tampilan yang disederhanakan dengan memilih "Kubernetes: Run/Debug" dari dropdown di tab OUTPUT.
- Setelah build dan pengujian selesai, tab Output akan menampilkan:
Resource deployment/demo-app status completed successfully, dan URL akan dicantumkan: "Forwarded URL from service demo-app: http://localhost:8080" - Di terminal Cloud Code, arahkan kursor ke URL dalam output (http://localhost:8080), lalu di ujung alat yang muncul, pilih Follow link.

Tab baru akan terbuka dan Anda akan melihat output di bawah:

Memanfaatkan Titik Henti Sementara
- Buka aplikasi
HelloController.javayang berada di/src/main/java/com/example/springboot/HelloController.java - Cari pernyataan return untuk jalur root yang berbunyi
return String.format("Hello from your %s environment!", target); - Tambahkan titik henti sementara ke baris tersebut dengan mengklik spasi kosong di sebelah kiri nomor baris. Indikator merah akan ditampilkan untuk menunjukkan bahwa titik henti sementara telah ditetapkan

- Muat ulang browser Anda dan perhatikan bahwa debugger menghentikan proses pada titik henti sementara dan memungkinkan Anda menyelidiki variabel dan status aplikasi yang berjalan dari jarak jauh di GKE

- Klik ke bawah di bagian variabel hingga Anda menemukan variabel "Target".
- Perhatikan nilai saat ini sebagai "local"

- Klik dua kali nama variabel "target" dan di jendela pop-up,
ubah nilai menjadi "Cloud Workstations"

- Klik tombol Lanjutkan di panel kontrol debug

- Tinjau respons di browser Anda yang kini menampilkan nilai yang diperbarui yang baru saja Anda masukkan.

- Hapus titik henti sementara dengan mengklik indikator merah di sebelah kiri nomor baris. Hal ini akan mencegah kode Anda berhenti dieksekusi pada baris ini saat Anda melanjutkan lab ini.
Hot Reload
- Ubah pernyataan untuk menampilkan nilai yang berbeda seperti "Hello from %s Code"
- File akan otomatis disimpan dan disinkronkan ke dalam container jarak jauh di GKE
- Muat ulang browser Anda untuk melihat hasil yang diperbarui.
- Hentikan sesi proses debug dengan mengklik kotak merah di toolbar proses debug

Pilih "Ya, bersihkan setelah setiap proses".

5. Mengembangkan Layanan Rest CRUD sederhana
Pada tahap ini, aplikasi Anda telah sepenuhnya dikonfigurasi untuk pengembangan dalam container dan Anda telah mempelajari alur kerja pengembangan dasar dengan Cloud Code. Di bagian berikut, Anda akan mempraktikkan apa yang telah Anda pelajari dengan menambahkan endpoint layanan REST yang terhubung ke database terkelola di Google Cloud.
Mengonfigurasi Dependensi
Kode aplikasi menggunakan database untuk mempertahankan data layanan REST. Pastikan dependensi tersedia dengan menambahkan kode berikut di pom.xml
- Buka file
pom.xmldan tambahkan kode berikut ke bagian dependensi konfigurasi
pom.xml
<!-- Database dependencies-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>2.2</version>
</dependency>
Layanan REST kode
Quote.java
Buat file bernama Quote.java di /src/main/java/com/example/springboot/ dan salin kode di bawah ini. Ini menentukan model Entity untuk objek Quote yang digunakan dalam aplikasi.
package com.example.springboot;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.util.Objects;
@Entity
@Table(name = "quotes")
public class Quote
{
@Id
@Column(name = "id")
private Integer id;
@Column(name="quote")
private String quote;
@Column(name="author")
private String author;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getQuote() {
return quote;
}
public void setQuote(String quote) {
this.quote = quote;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Quote quote1 = (Quote) o;
return Objects.equals(id, quote1.id) &&
Objects.equals(quote, quote1.quote) &&
Objects.equals(author, quote1.author);
}
@Override
public int hashCode() {
return Objects.hash(id, quote, author);
}
}
QuoteRepository.java
Buat file bernama QuoteRepository.java di src/main/java/com/example/springboot dan salin kode berikut ke dalamnya
package com.example.springboot;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
public interface QuoteRepository extends JpaRepository<Quote,Integer> {
@Query( nativeQuery = true, value =
"SELECT id,quote,author FROM quotes ORDER BY RANDOM() LIMIT 1")
Quote findRandomQuote();
}
Kode ini menggunakan JPA untuk mempertahankan data. Class ini memperluas antarmuka Spring JPARepository dan memungkinkan pembuatan kode kustom. Dalam kode yang telah Anda tambahkan, terdapat metode kustom findRandomQuote.
QuoteController.java
Untuk mengekspos endpoint layanan, class QuoteController akan menyediakan fungsi ini.
Buat file bernama QuoteController.java di src/main/java/com/example/springboot dan salin konten berikut ke dalamnya
package com.example.springboot;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class QuoteController {
private final QuoteRepository quoteRepository;
public QuoteController(QuoteRepository quoteRepository) {
this.quoteRepository = quoteRepository;
}
@GetMapping("/random-quote")
public Quote randomQuote()
{
return quoteRepository.findRandomQuote();
}
@GetMapping("/quotes")
public ResponseEntity<List<Quote>> allQuotes()
{
try {
List<Quote> quotes = new ArrayList<Quote>();
quoteRepository.findAll().forEach(quotes::add);
if (quotes.size()==0 || quotes.isEmpty())
return new ResponseEntity<List<Quote>>(HttpStatus.NO_CONTENT);
return new ResponseEntity<List<Quote>>(quotes, HttpStatus.OK);
} catch (Exception e) {
System.out.println(e.getMessage());
return new ResponseEntity<List<Quote>>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@PostMapping("/quotes")
public ResponseEntity<Quote> createQuote(@RequestBody Quote quote) {
try {
Quote saved = quoteRepository.save(quote);
return new ResponseEntity<Quote>(saved, HttpStatus.CREATED);
} catch (Exception e) {
System.out.println(e.getMessage());
return new ResponseEntity<Quote>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@PutMapping("/quotes/{id}")
public ResponseEntity<Quote> updateQuote(@PathVariable("id") Integer id, @RequestBody Quote quote) {
try {
Optional<Quote> existingQuote = quoteRepository.findById(id);
if(existingQuote.isPresent()){
Quote updatedQuote = existingQuote.get();
updatedQuote.setAuthor(quote.getAuthor());
updatedQuote.setQuote(quote.getQuote());
return new ResponseEntity<Quote>(updatedQuote, HttpStatus.OK);
} else {
return new ResponseEntity<Quote>(HttpStatus.NOT_FOUND);
}
} catch (Exception e) {
System.out.println(e.getMessage());
return new ResponseEntity<Quote>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@DeleteMapping("/quotes/{id}")
public ResponseEntity<HttpStatus> deleteQuote(@PathVariable("id") Integer id) {
Optional<Quote> quote = quoteRepository.findById(id);
if (quote.isPresent()) {
quoteRepository.deleteById(id);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} else {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
Menambahkan Konfigurasi Database
application.yaml
Tambahkan konfigurasi untuk database backend yang diakses oleh layanan. Edit (atau buat jika belum ada) file bernama application.yaml di src/main/resources dan tambahkan konfigurasi Spring berparameter untuk backend.
target: local
spring:
config:
activate:
on-profile: cloud-dev
datasource:
url: 'jdbc:postgresql://${DB_HOST:127.0.0.1}/${DB_NAME:quote_db}'
username: '${DB_USER:user}'
password: '${DB_PASS:password}'
jpa:
properties:
hibernate:
jdbc:
lob:
non_contextual_creation: true
dialect: org.hibernate.dialect.PostgreSQLDialect
hibernate:
ddl-auto: update
Tambahkan Migrasi Database
Buat folder db/migration di src/main/resources
Buat file SQL: V1__create_quotes_table.sql
Tempelkan konten berikut ke dalam file
V1__create_quotes_table.sql
CREATE TABLE quotes(
id INTEGER PRIMARY KEY,
quote VARCHAR(1024),
author VARCHAR(256)
);
INSERT INTO quotes (id,quote,author) VALUES (1,'Never, never, never give up','Winston Churchill');
INSERT INTO quotes (id,quote,author) VALUES (2,'While there''s life, there''s hope','Marcus Tullius Cicero');
INSERT INTO quotes (id,quote,author) VALUES (3,'Failure is success in progress','Anonymous');
INSERT INTO quotes (id,quote,author) VALUES (4,'Success demands singleness of purpose','Vincent Lombardi');
INSERT INTO quotes (id,quote,author) VALUES (5,'The shortest answer is doing','Lord Herbert');
Kubernetes Config
Penambahan berikut pada file deployment.yaml memungkinkan aplikasi terhubung ke instance CloudSQL.
- TARGET - mengonfigurasi variabel untuk menunjukkan lingkungan tempat aplikasi dieksekusi
- SPRING_PROFILES_ACTIVE - menampilkan profil Spring aktif, yang akan dikonfigurasi ke
cloud-dev - DB_HOST - IP pribadi untuk database, yang telah dicatat saat instance database dibuat atau dengan mengklik
SQLdi Menu Navigasi Konsol Google Cloud - harap ubah nilainya. - DB_USER dan DB_PASS - seperti yang ditetapkan dalam konfigurasi instance CloudSQL, disimpan sebagai Secret di GCP
Perbarui deployment.yaml dengan konten di bawah.
deployment.yaml
apiVersion: v1
kind: Service
metadata:
name: demo-app
labels:
app: demo-app
spec:
ports:
- port: 8080
protocol: TCP
clusterIP: None
selector:
app: demo-app
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-app
labels:
app: demo-app
spec:
replicas: 1
selector:
matchLabels:
app: demo-app
template:
metadata:
labels:
app: demo-app
spec:
containers:
- name: demo-app
image: demo-app
env:
- name: PORT
value: "8080"
- name: TARGET
value: "Local Dev - CloudSQL Database - K8s Cluster"
- name: SPRING_PROFILES_ACTIVE
value: cloud-dev
- name: DB_HOST
value: ${DB_INSTANCE_IP}
- name: DB_PORT
value: "5432"
- name: DB_USER
valueFrom:
secretKeyRef:
name: gke-cloud-sql-secrets
key: username
- name: DB_PASS
valueFrom:
secretKeyRef:
name: gke-cloud-sql-secrets
key: password
- name: DB_NAME
valueFrom:
secretKeyRef:
name: gke-cloud-sql-secrets
key: database
Ganti nilai DB_HOST dengan alamat Database Anda dengan menjalankan perintah di bawah di terminal:
export DB_INSTANCE_IP=$(gcloud sql instances describe quote-db-instance \
--format=json | jq \
--raw-output ".ipAddresses[].ipAddress")
envsubst < deployment.yaml > deployment.new && mv deployment.new deployment.yaml
Buka deployment.yaml dan pastikan nilai DB_HOST telah diupdate dengan IP Instance.

Men-deploy dan Memvalidasi Aplikasi
- Di panel di bagian bawah Cloud Shell Editor, pilih Cloud Code, lalu pilih Debug di Kubernetes di bagian atas layar.

- Setelah build dan pengujian selesai, tab Output akan menampilkan:
Resource deployment/demo-app status completed successfully, dan URL akan dicantumkan: "Forwarded URL from service demo-app: http://localhost:8080". Perhatikan bahwa terkadang portnya mungkin berbeda seperti 8081. Jika ya, tetapkan nilai yang sesuai. Tetapkan nilai URL di terminal
export URL=localhost:8080
- Melihat Kutipan Acak
Dari Terminal, jalankan perintah di bawah beberapa kali terhadap endpoint random-quote. Mengamati panggilan berulang yang menampilkan kutipan berbeda
curl $URL/random-quote | jq
- Tambahkan Penawaran
Buat penawaran baru, dengan id=6 menggunakan perintah yang tercantum di bawah dan amati permintaan yang dikembalikan
curl -H 'Content-Type: application/json' -d '{"id":"6","author":"Henry David Thoreau","quote":"Go confidently in the direction of your dreams! Live the life you have imagined"}' -X POST $URL/quotes
- Menghapus penawaran harga
Sekarang hapus kutipan yang baru saja Anda tambahkan dengan metode penghapusan dan amati kode respons HTTP/1.1 204.
curl -v -X DELETE $URL/quotes/6
- Error Server
Mengalami status error dengan menjalankan permintaan terakhir lagi setelah entri dihapus
curl -v -X DELETE $URL/quotes/6
Perhatikan bahwa respons menampilkan HTTP:500 Internal Server Error.
Men-debug aplikasi
Di bagian sebelumnya, Anda menemukan status error dalam aplikasi saat mencoba menghapus entri yang tidak ada dalam database. Di bagian ini, Anda akan menetapkan titik henti sementara untuk menemukan masalah. Error terjadi dalam operasi DELETE, jadi Anda akan bekerja dengan class QuoteController.
- Buka
src/main/java/com/example/springboot/QuoteController.java - Temukan metode
deleteQuote() - Temukan baris:
Optional<Quote> quote = quoteRepository.findById(id); - Tetapkan titik henti sementara pada baris tersebut dengan mengklik ruang kosong di sebelah kiri nomor baris.
- Indikator merah akan muncul yang menunjukkan bahwa titik henti sementara telah ditetapkan
- Jalankan kembali perintah
delete
curl -v -X DELETE $URL/quotes/6
- Beralih kembali ke tampilan debug dengan mengklik ikon di kolom kiri
- Amati baris debug yang berhenti di class QuoteController.
- Di debugger, klik ikon
step over
- Perhatikan bahwa kode menampilkan Error Server Internal HTTP 500 ke klien yang tidak ideal.
Trying 127.0.0.1:8080... * Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0) > DELETE /quotes/6 HTTP/1.1 > Host: 127.0.0.1:8080 > User-Agent: curl/7.74.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 500 < Content-Length: 0 < Date: < * Connection #0 to host 127.0.0.1 left intact
Mengupdate kode
Kodenya salah dan blok else harus diubah untuk mengirim kembali kode status HTTP 404 not found.
Perbaiki error tersebut.
- Dengan sesi Debug yang masih berjalan, selesaikan permintaan dengan menekan tombol "continue" di panel kontrol debug.
- Selanjutnya, ubah blok
elseke kode:
else {
return new ResponseEntity<HttpStatus>(HttpStatus.NOT_FOUND);
}
Metodenya akan terlihat seperti berikut
@DeleteMapping("/quotes/{id}")
public ResponseEntity<HttpStatus> deleteQuote(@PathVariable("id") Integer id) {
Optional<Quote> quote = quoteRepository.findById(id);
if (quote.isPresent()) {
quoteRepository.deleteById(id);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} else {
return new ResponseEntity<HttpStatus>(HttpStatus.NOT_FOUND);
}
}
- Jalankan kembali perintah hapus
curl -v -X DELETE $URL/quotes/6
- Lakukan penelusuran langkah demi langkah pada debugger dan amati HTTP 404 Not Found yang ditampilkan ke pemanggil.
Trying 127.0.0.1:8080... * Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0) > DELETE /quotes/6 HTTP/1.1 > Host: 127.0.0.1:8080 > User-Agent: curl/7.74.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 404 < Content-Length: 0 < Date: < * Connection #0 to host 127.0.0.1 left intact
- Hentikan sesi proses debug dengan mengklik kotak merah di toolbar proses debug


6. Selamat
Selamat! Dalam lab ini, Anda telah membuat aplikasi Java baru dari awal dan mengonfigurasinya agar berfungsi secara efektif dengan container. Kemudian, Anda men-deploy dan men-debug aplikasi ke cluster GKE jarak jauh dengan mengikuti alur developer yang sama seperti yang ditemukan dalam stack aplikasi tradisional.
Yang telah Anda pelajari
- Pengembangan InnerLoop dengan Cloud Workstations
- Membuat aplikasi awal Java baru
- Menjelaskan proses pengembangan
- Mengembangkan Layanan REST CRUD sederhana
- Proses debug aplikasi di cluster GKE
- Menghubungkan aplikasi ke database CloudSQL
