1. Ringkasan
Lab ini mendemonstrasikan fitur dan kemampuan yang didesain untuk menyederhanakan alur kerja pengembangan bagi software engineer yang bertugas mengembangkan aplikasi Java di lingkungan dalam container. Pengembangan container standar mengharuskan pengguna memahami detail container dan proses build container. Selain itu, developer biasanya harus menghentikan alurnya, keluar dari IDE mereka untuk menguji dan men-debug aplikasi di lingkungan jarak jauh. Dengan alat dan teknologi yang disebutkan dalam tutorial ini, developer dapat bekerja secara efektif dengan aplikasi dalam container tanpa perlu meninggalkan IDE mereka.
Yang akan Anda pelajari
Di lab ini, Anda akan mempelajari metode pengembangan dengan container di GCP, termasuk:
- Penyiapan dan Persyaratan
- Membuat aplikasi awal Java baru
- Menjalani proses pengembangan
- Mengembangkan Layanan Istirahat CRUD yang sederhana
- Pembersihan
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.
- Nama project adalah nama tampilan untuk peserta project ini. String ini adalah string karakter yang tidak digunakan oleh Google API, dan Anda dapat memperbaruinya kapan saja.
- Project ID harus unik di semua project Google Cloud dan tidak dapat diubah (tidak dapat diubah setelah ditetapkan). Cloud Console otomatis menghasilkan string unik; biasanya Anda tidak peduli dengan kata-katanya. Pada sebagian besar codelab, Anda harus mereferensikan Project ID (dan biasanya diidentifikasi sebagai
PROJECT_ID
). Jadi, jika Anda tidak menyukainya, buat ID acak lain, atau, Anda dapat mencoba sendiri dan melihat apakah tersedia. Kemudian file akan "dibekukan" setelah project dibuat. - Ada nilai ketiga, Nomor Project yang digunakan oleh beberapa API. Pelajari lebih lanjut ketiga nilai ini di dokumentasi.
- Selanjutnya, Anda harus mengaktifkan penagihan di Cloud Console untuk menggunakan API/resource Cloud. Menjalankan operasi dalam codelab ini seharusnya tidak memerlukan banyak biaya, bahkan mungkin tidak sama sekali. Untuk menonaktifkan resource agar tidak menimbulkan penagihan di luar tutorial ini, ikuti petunjuk "pembersihan" yang ada di akhir codelab. Pengguna baru Google Cloud memenuhi syarat untuk mengikuti program Uji Coba Gratis senilai $300 USD.
Mulai Cloudshell Editor
Lab ini dirancang dan diuji agar dapat digunakan dengan Google Cloud Shell Editor. Untuk mengakses editor,
- akses project Google Anda di https://console.cloud.google.com.
- Di sudut kanan atas, klik ikon Cloud Shell Editor
- 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 PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
Mendapatkan kode sumber
Kode sumber untuk lab ini terdapat di container-developer-workshop di GoogleCloudPlatform pada GitHub. Clone dengan perintah di bawah ini, lalu pindah 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 tersimpan di database CloudSql. Skrip penyiapan di bawah menyiapkan infrastruktur ini untuk Anda. Proses penyediaan akan memerlukan waktu lebih dari 10 menit. Anda dapat melanjutkan ke beberapa langkah berikutnya saat penyiapan sedang diproses.
./setup.sh
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
Meng-clone Aplikasi Contoh
- Membuat aplikasi awal
curl https://start.spring.io/starter.zip -d dependencies=web -d type=maven-project -d javaVersion=11 -d packageName=com.example.springboot -o sample-app.zip
- Ekstrak aplikasi
unzip sample-app.zip -d sample-app
- Beralihlah ke direktori sample-app dan buka folder di ruang kerja Cloud Shell IDE
cd sample-app && cloudshell workspace .
Tambahkan Spring-boot-devtools & Jib
Untuk mengaktifkan Spring Boot DevTools temukan dan buka pom.xml dari explorer di editor Anda. Selanjutnya, tempel kode berikut setelah baris deskripsi yang bertuliskan <description>Demo project for Spring Boot</description>
- Menambahkan 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>
- Mengaktifkan jib-maven-plugin di pom.xml
Jib adalah alat containerization Java open source dari Google yang memungkinkan developer Java membangun container menggunakan alat Java yang mereka ketahui. Jib adalah builder image container yang cepat dan sederhana yang menangani semua langkah pengemasan aplikasi ke dalam image container. Anda tidak perlu menulis Dockerfile atau sudah menginstalnya, dan Anda sudah terintegrasi langsung ke Maven dan Gradle.
Scroll ke bawah di file pom.xml dan perbarui bagian Build
untuk menyertakan plugin Jib. Bagian build akan terlihat seperti berikut jika sudah 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>
Pilih Always
jika diminta tentang perubahan file build.
Membuat Manifes
Skaffold menyediakan alat terintegrasi untuk menyederhanakan pengembangan container. Pada langkah ini, Anda akan melakukan inisialisasi skaffold yang akan otomatis membuat file YAML Kubernetes dasar. Proses ini mencoba mengidentifikasi direktori dengan definisi image container, seperti Dockerfile, lalu membuat deployment dan manifes layanan untuk setiap direktori tersebut.
Jalankan perintah di bawah ini untuk memulai prosesnya.
- Jalankan perintah berikut di terminal
skaffold init --generate-manifests
- Saat diminta:
- Gunakan tanda panah untuk memindahkan kursor ke
Jib Maven Plugin
- Tekan spasi untuk memilih opsi.
- Tekan enter untuk melanjutkan
- Masukkan 8080 untuk port
- Masukkan y untuk menyimpan konfigurasi
Dua file ditambahkan ke {i>workspace viz<i}, skaffold.yaml
dan deployment.yaml
Perbarui nama aplikasi
Nilai default yang disertakan dalam konfigurasi saat ini tidak cocok dengan nama aplikasi Anda. Update 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 dan pilih Change All Occurrences
- 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 dan pilih Change All Occurrences
- Ketik nama baru sebagai
demo-app
Mengaktifkan hot sync
Untuk memfasilitasi pengalaman hot reload yang dioptimalkan, Anda akan menggunakan fitur Sinkronisasi yang disediakan oleh Jib. Pada langkah ini, Anda akan mengonfigurasi Skaffold untuk memanfaatkan fitur tersebut dalam proses build.
Perhatikan bahwa "sinkronisasi" yang Anda konfigurasi dalam konfigurasi skaffold memanfaatkan "sync" Spring Profil yang telah Anda konfigurasi di langkah sebelumnya, tempat Anda mengaktifkan dukungan untuk Spring-dev-tools.
- Memperbarui konfigurasi skaffold
Di file skaffold.yaml, ganti seluruh bagian build file dengan spesifikasi berikut. Jangan mengubah 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/java:debug
sync:
auto: true
Menambahkan rute default
Membuat file bernama HelloController.java di /src/main/java/com/example/springboot/
Tempel konten berikut pada 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. Menjalani proses pengembangan
Di bagian ini, Anda akan memandu beberapa langkah menggunakan plugin Cloud Code untuk mempelajari proses dasar serta memvalidasi konfigurasi dan penyiapan aplikasi awal.
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 yang mengabstraksi detail dari alur developer. Cloud Code juga meningkatkan proses pengembangan Anda dengan menyediakan kemampuan hotsync dan debug tradisional untuk pengembangan berbasis container.
Men-deploy ke Kubernetes
- Pada panel di bagian bawah Cloud Shell Editor, pilih Cloud Code ✔
- Di panel yang muncul di bagian atas, pilih Debug di Kubernetes. Jika diminta, pilih Ya untuk menggunakan konteks Kubernetes saat ini.
- Saat pertama kali Anda menjalankan perintah, sebuah prompt akan muncul di bagian atas layar dan menanyakan apakah Anda menginginkan konteks Kubernetes saat ini, pilih "Yes" untuk menerima dan menggunakan konteks saat ini.
- Selanjutnya, akan muncul perintah yang menanyakan container registry yang akan digunakan. Tekan enter untuk menerima nilai default yang diberikan
- Pilih tab Output di panel bawah untuk melihat progres dan notifikasi
- Pilih "Kubernetes: Run/Debug - Terperinci" di menu drop-down saluran di sebelah kanan untuk melihat detail tambahan dan log yang melakukan streaming langsung dari penampung
- Kembali ke tampilan yang disederhanakan dengan memilih "Kubernetes: Run/Debug" dari menu dropdown
- Saat build dan pengujian selesai, tab Output akan menampilkan:
Resource deployment/demo-app status completed successfully
, dan URL akan tercantum: "Forwarded URL from service demo-app: http://localhost:8080" - Di terminal Cloud Code, arahkan kursor ke URL di output (http://localhost:8080), lalu di ujung alat yang muncul, pilih Open Web Preview.
Responsnya adalah:
Hello from your local environment!
Memanfaatkan Breakpoint
- Buka aplikasi HelloController.java yang berada di /src/main/java/com/example/springboot/HelloController.java
- Temukan pernyataan return untuk jalur root yang bertuliskan
return String.format("Hello from your %s environment!", target);
- Tambahkan titik henti sementara ke baris tersebut dengan mengklik ruang kosong di sebelah kiri nomor baris. Indikator merah akan muncul untuk mencatat titik henti sementara yang telah disetel
- Muat ulang browser Anda dan perhatikan bahwa debugger menghentikan proses pada titik henti sementara dan memungkinkan Anda menyelidiki status pasir variabel aplikasi yang berjalan dari jarak jauh di GKE
- Klik bagian variabel hingga Anda menemukan "Target" variabel.
- Amati nilai saat ini sebagai "local"
- Klik dua kali nama variabel "target" dan di pop-up, ubah nilai ke nilai lain seperti "Cloud"
- Klik tombol Lanjutkan pada panel kontrol debug
- Tinjau respons di browser Anda yang kini menampilkan nilai terbaru yang baru saja Anda masukkan.
Hot Reload
- Ubah pernyataan untuk menampilkan nilai yang berbeda seperti "Hello from %s Code"
- File secara otomatis disimpan dan disinkronkan ke dalam container jarak jauh di GKE
- Refresh browser Anda untuk melihat hasil yang diperbarui.
- Hentikan sesi proses debug dengan mengklik kotak merah di toolbar debug
5. Mengembangkan Layanan Istirahat CRUD yang sederhana
Pada tahap ini, aplikasi Anda telah dikonfigurasi sepenuhnya untuk pengembangan dalam container dan Anda telah mempelajari alur kerja pengembangan dasar dengan Cloud Code. Di bagian berikut, Anda akan mempraktikkan hal-hal yang telah Anda pelajari dengan menambahkan endpoint layanan lainnya yang terhubung ke database terkelola di Google Cloud.
Mengonfigurasi Dependensi
Kode aplikasi menggunakan database untuk mempertahankan data layanan lainnya. Pastikan dependensi tersedia dengan menambahkan kode berikut di pom.xl
- Buka file
pom.xml
dan 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>
Membuat kode untuk layanan lainnya
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 Kutipan yang digunakan dalam aplikasi.
package com.example.springboot;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.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 KutipanRepository.java di src/main/java/com/example/springboot dan salin kode berikut
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, Anda telah menambahkan metode kustom findRandomQuote
.
QuoteController.java
Untuk mengekspos endpoint untuk layanan, class QuoteController
akan menyediakan fungsi ini.
Buat file bernama KutipanController.java di src/main/java/com/example/springboot dan salin konten berikut
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) {
try {
quoteRepository.deleteById(id);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} catch (RuntimeException e) {
System.out.println(e.getMessage());
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
Tambahkan Konfigurasi Database
application.yaml
Menambahkan konfigurasi untuk database backend yang diakses oleh layanan. Edit (atau buat jika tidak ada) file bernama file application.yaml
di bagian 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
Menambahkan Migrasi Database
Buat folder di src/main/resources/db/migration/
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');
Konfigurasi Kubernetes
Penambahan berikut ke file deployment.yaml
memungkinkan aplikasi terhubung ke instance CloudSQL.
- TARGET - mengonfigurasi variabel untuk menunjukkan lingkungan tempat aplikasi dijalankan
- 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
SQL
di 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
Update deployment.yaml Anda dengan konten di bawah ini.
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
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
Men-deploy dan Validasi Aplikasi
- Pada panel di bagian bawah Cloud Shell Editor, pilih Cloud Code lalu pilih Debug on Kubernetes di bagian atas layar.
- Saat build dan pengujian selesai, tab Output akan menampilkan:
Resource deployment/demo-app status completed successfully
, dan URL akan tercantum: "Forwarded URL from service demo-app: http://localhost:8080" - Lihat Kutipan Acak
Dari Terminal cloudshell, jalankan perintah di bawah beberapa kali terhadap endpoint acak kutipan. Mengamati panggilan berulang yang menampilkan kutipan yang berbeda
curl -v 127.0.0.1:8080/random-quote
- Tambahkan Penawaran Harga
Buat kutipan baru, dengan id=6 menggunakan perintah yang tercantum di bawah ini dan amati permintaan yang dipantulkan kembali
curl -v -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 127.0.0.1:8080/quotes
- Menghapus penawaran harga
Sekarang hapus kutipan yang baru saja Anda tambahkan dengan metode hapus dan amati kode respons HTTP/1.1 204
.
curl -v -X DELETE 127.0.0.1:8080/quotes/6
- Error Server
Rasakan status error dengan menjalankan kembali permintaan terakhir setelah entri telah dihapus
curl -v -X DELETE 127.0.0.1:8080/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 menggunakan class QuoteController.
- Buka src.main.java.com.example.springboot.QuoteController.java
- Menemukan metode
deleteQuote()
- Temukan baris tempat menghapus item dari database:
quoteRepository.deleteById(id);
- Tetapkan titik henti sementara pada baris tersebut dengan mengklik spasi kosong di sebelah kiri nomor baris.
- Indikator merah akan muncul yang menunjukkan titik henti sementara telah disetel
- Jalankan perintah
delete
lagi
curl -v -X DELETE 127.0.0.1:8080/quotes/6
- Beralih kembali ke tampilan debug dengan mengklik ikon di kolom sebelah kiri
- Amati baris debug yang dihentikan di class KutipanController.
- Di debugger, klik ikon
step over
dan amati bahwa pengecualian ditampilkan - Perhatikan bahwa
RuntimeException was caught.
yang sangat umum Tindakan ini menampilkan Error Server Internal HTTP 500 ke klien, hal ini 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
Kode ini salah dan blok pengecualian harus difaktorkan ulang untuk menangkap pengecualian EmptyResultDataAccessException
dan mengirim kembali kode status HTTP 404 tidak ditemukan.
Perbaiki error tersebut.
- Saat sesi Debug masih berjalan, selesaikan permintaan dengan menekan tombol "continue" di panel kontrol debug.
- Selanjutnya, tambahkan blok berikut ke kode:
} catch (EmptyResultDataAccessException e){
return new ResponseEntity<HttpStatus>(HttpStatus.NOT_FOUND);
}
Metode akan terlihat seperti berikut
public ResponseEntity<HttpStatus> deleteQuote(@PathVariable("id") Integer id) { try { quoteRepository.deleteById(id); return new ResponseEntity<>(HttpStatus.NO_CONTENT); } catch(EmptyResultDataAccessException e){ return new ResponseEntity<HttpStatus>(HttpStatus.NOT_FOUND); } catch (RuntimeException e) { System.out.println(e.getMessage()); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } }
- Menjalankan kembali perintah hapus
curl -v -X DELETE 127.0.0.1:8080/quotes/6
- Telusuri debugger dan amati
EmptyResultDataAccessException
tertangkap dan HTTP 404 Not Found ditampilkan kembali 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 debug
6. Pembersihan
Selamat! Di lab ini, Anda telah membuat aplikasi Java baru dari awal dan mengonfigurasinya agar berfungsi secara efektif dengan container. Kemudian, Anda telah men-deploy dan men-debug aplikasi ke cluster GKE jarak jauh dengan mengikuti alur developer yang sama dengan yang ada di stack aplikasi tradisional.
Untuk melakukan pembersihan setelah menyelesaikan lab:
- Menghapus file yang digunakan dalam lab
cd ~ && rm -rf container-developer-workshop
- Menghapus project untuk menghapus semua infrastruktur dan resource terkait