Mengembangkan dengan Cloud Workstations dan Cloud Code

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:

  • Pengembangan InnerLoop dengan Cloud Workstations
  • Membuat aplikasi awal Java baru
  • Menjalani proses pengembangan
  • Mengembangkan Layanan Istirahat CRUD yang sederhana
  • Melakukan proses debug aplikasi di cluster GKE
  • Menghubungkan aplikasi ke database CloudSQL

58a4cdd3ed7a123a.pngS

2. Penyiapan dan Persyaratan

Penyiapan lingkungan mandiri

  1. 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.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • 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 peduli tentang apa itu. Di sebagian besar codelab, Anda harus mereferensikan Project ID (biasanya diidentifikasi sebagai PROJECT_ID). Jika Anda tidak menyukai ID yang dihasilkan, Anda dapat membuat ID acak lainnya. Atau, Anda dapat mencobanya sendiri dan lihat 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.
  1. 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. Untuk 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 Cloudshell Editor

Lab ini dirancang dan diuji agar dapat digunakan dengan Google Cloud Shell Editor. Untuk mengakses editor,

  1. akses project Google Anda di https://console.cloud.google.com.
  2. Di sudut kanan atas, klik ikon Cloud Shell Editor

8560cc8d45e8c112.pngS

  1. Panel baru akan terbuka di bagian bawah jendela
  2. Klik tombol Open Editor

9e504cb98a6a8005.pngS

  1. Editor akan terbuka dengan penjelajah di sebelah kanan dan editor di area tengah
  2. Panel terminal juga harus tersedia di bagian bawah layar
  3. 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 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 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 berada dalam status READY.

305e1a3d63ac7ff6.pngS

Membuat Konfigurasi Workstations

Jika sesi Cloud Shell Anda terputus, klik "Hubungkan kembali" lalu jalankan perintah "gcloud cli" untuk menetapkan project ID. Ganti contoh project id 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 hasilnya di bagian Konfigurasi. Perlu waktu 2 menit untuk bertransisi ke status SIAP.

7a6af5aa2807a5f2.pngS

Buka Cloud Workstations di Konsol dan buat instance baru.

a53adeeac81a78c8.png

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

f21c216997746097.png

Verifikasi hasilnya di bagian Workstations.

66a9fc8b20543e32.pngS

Luncurkan Workstation

Memulai dan meluncurkan workstation.

c91bb69b61ec8635.png

Izinkan cookie pihak ketiga dengan mengklik ikon di kolom URL. 1b8923e2943f9bc4.pngS

fcf9405b6957b7d7.png

Klik "Situs tidak berfungsi?".

36a84c0e2e3b85b.pngS

Klik "Izinkan cookie".

2259694328628fba.png

Setelah workstation diluncurkan, Anda akan melihat Code OSS IDE muncul. Klik "Tandai Selesai" di halaman Memulai di salah satu workstation IDE

94874fba9b74cc22.pngS

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.

c31d48f2e4938c38.png

Meng-clone Aplikasi Contoh

  1. 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 komputer.

58149777e5cc350a.png

  1. Ekstrak aplikasi
unzip sample-app.zip -d sample-app
  1. Buka "sample-app" folder
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 explorer di editor Anda. Selanjutnya, tempel kode berikut setelah baris deskripsi yang bertuliskan <description>Demo project for Spring Boot</description>

  1. 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>
  1. 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 kenal. 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>

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 di Terminal untuk memulai prosesnya.

d869e0cd38e983d7.png

  1. Jalankan perintah berikut di terminal
skaffold init --generate-manifests
  1. Saat diminta:
  • Gunakan tanda panah untuk memindahkan kursor ke Jib Maven Plugin
  • Tekan spasi untuk memilih opsi.
  • Tekan enter untuk melanjutkan
  1. Masukkan 8080 untuk port
  2. Masukkan y untuk menyimpan konfigurasi

Dua file ditambahkan ke ruang kerja skaffold.yaml dan deployment.yaml

Output Skaffold:

b33cc1e0c2077ab8.png

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.

  1. 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
  1. 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

Aktifkan 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 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.

  1. Mengupdate 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/java17-debian11:debug
    sync:
      auto: true

Menambahkan rute default

Buat file dengan nama HelloController.java di folder /src/main/java/com/example/springboot/.

a624f5dd0c477c09.png

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.

Login ke Google Cloud

Klik ikon Cloud Code dan pilih "Sign in to Google Cloud":

1769afd39be372ff.pngS

Klik "Lanjutkan login".

923bb1c8f63160f9.pngS

Periksa output di Terminal dan buka link:

517fdd579c34aa21.pngS

Login dengan kredensial siswa Qwiklabs Anda.

db99b345f7a8e72c.png

Pilih "Izinkan":

a5376553c430ac84.png

Salin kode verifikasi dan kembali ke tab Workstation.

6719421277b92eac.pngS

Tempelkan kode verifikasi dan tekan Enter.

e9847cfe3fa8a2ce.png

Tambahkan Cluster Kubernetes

  1. Menambahkan Cluster

62a3b97bdbb427e5.pngS

  1. Pilih Google Kubernetes Engine:

9577de423568bbaa.pngS

  1. Pilih project.

c5202fcbeebcd41c.png

  1. Pilih "kutipan-cluster" yang dibuat di penyiapan awal.

366cfd8bc27cd3ed.png

9d68532c9bc4a89b.png

Tetapkan ID project saat ini menggunakan gcloud cli

Salin project ID untuk lab ini dari halaman qwiklabs.

fcff2d10007ec5bc.png

Jalankan perintah gcloud cli untuk menetapkan project ID. Ganti contoh project id sebelum menjalankan perintah.

gcloud config set project qwiklabs-gcp-project-id

Contoh output:

f1c03d01b7ac112c.png

Men-debug di Kubernetes

  1. Pada panel kiri di bagian bawah, pilih Cloud Code.

60b8e4e95868b561.pngS

  1. Di panel yang muncul di bagian DEVELOPMENT SESSIONS, pilih Debug on Kubernetes.

Scroll ke bawah jika opsi tidak terlihat.

7d30833d96632ca0.pngS

  1. Pilih "Ya" untuk menggunakan konteks saat ini.

a024a69b64de7e9e.png

  1. Pilih "kutipan-cluster" yang dibuat selama penyiapan awal.

faebabf372e3caf0.png

  1. Pilih Container Repository.

fabc6dce48bae1b4.png

  1. Pilih tab Output di panel bawah untuk melihat progres dan notifikasi
  2. 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

86b44c59db58f8f3.pngS

Tunggu hingga aplikasi di-deploy.

9f37706a752829fe.pngS

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

6ad220e5d1980756.pngS

  1. Kembali ke tampilan yang disederhanakan dengan memilih "Kubernetes: Run/Debug" dari menu dropdown di tab OUTPUT.
  2. 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"
  3. Di terminal Cloud Code, arahkan kursor ke URL di output (http://localhost:8080), lalu di ujung alat yang muncul, pilih Ikuti link.

28c5539880194a8e.pngS

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

d67253ca16238f49.png

Memanfaatkan Breakpoint

  1. Buka aplikasi HelloController.java yang berada di /src/main/java/com/example/springboot/HelloController.java
  2. Temukan pernyataan return untuk jalur root yang bertuliskan return String.format("Hello from your %s environment!", target);
  3. 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

5027dc6da2618a39.pngS

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

71acfb426623cec2.pngS

  1. Klik bagian variabel hingga Anda menemukan "Target" variabel.
  2. Amati nilai saat ini sebagai "local"

a1160d2ed2bb5c82.png

  1. Klik dua kali nama variabel "target" dan pada pop-up,

ubah nilainya menjadi "Cloud Workstations"

e597a556a5c53f32.png

  1. Klik tombol Lanjutkan pada panel kontrol debug

ec17086191770d0d.png

  1. Tinjau respons di browser Anda yang kini menampilkan nilai terbaru yang baru saja Anda masukkan.

6698a9db9e729925.pngS

  1. Hapus titik henti sementara dengan mengklik indikator merah di sebelah kiri nomor baris. Hal ini akan mencegah kode Anda menghentikan eksekusi di baris ini saat Anda melanjutkan lab ini.

Hot Reload

  1. Ubah pernyataan untuk menampilkan nilai yang berbeda seperti "Hello from %s Code"
  2. File secara otomatis disimpan dan disinkronkan ke dalam container jarak jauh di GKE
  3. Refresh browser Anda untuk melihat hasil yang diperbarui.
  4. Hentikan sesi proses debug dengan mengklik kotak merah di toolbar debug

a541f928ec8f430e.png c2752bb28d82af86.png

Pilih "Yes clean up after each run".

984eb2fa34867d70.pngS

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 REST 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

  1. 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>
    <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 menentukan model Entity untuk objek Kutipan 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, lalu 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 QuoteController.java di src/main/java/com/example/springboot, lalu 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) {
        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);
        }
    }

}

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 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');

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 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 diperbarui dengan IP Instance.

fd63c0aede14beba.png

Men-deploy dan Validasi Aplikasi

  1. Pada panel di bagian bawah Cloud Shell Editor, pilih Cloud Code lalu pilih Debug on Kubernetes di bagian atas layar.

33a5cf41aae91adb.pngS

  1. 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". Perhatikan bahwa terkadang port-nya mungkin berbeda seperti 8081. Jika demikian, tetapkan nilai yang sesuai. Tetapkan nilai URL di terminal
export URL=localhost:8080
  1. Lihat Kutipan Acak

Dari Terminal, jalankan perintah di bawah beberapa kali terhadap endpoint acak kutipan. Amati panggilan berulang yang menampilkan tanda kutip yang berbeda

curl $URL/random-quote | jq
  1. Tambahkan Penawaran Harga

Buat kutipan baru, dengan id=6 menggunakan perintah yang tercantum di bawah ini dan amati permintaan yang dipantulkan kembali

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
  1. 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 $URL/quotes/6
  1. Error Server

Rasakan status error dengan menjalankan kembali permintaan terakhir setelah entri telah 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 menggunakan class QuoteController.

  1. Buka src/main/java/com/example/springboot/QuoteController.java
  2. Menemukan metode deleteQuote()
  3. Temukan garisnya: Optional<Quote> quote = quoteRepository.findById(id);
  4. Tetapkan titik henti sementara pada baris tersebut dengan mengklik spasi kosong di sebelah kiri nomor baris.
  5. Indikator merah akan muncul yang menunjukkan titik henti sementara telah disetel
  6. Jalankan perintah delete lagi
curl -v -X DELETE $URL/quotes/6
  1. Beralih kembali ke tampilan debug dengan mengklik ikon di kolom sebelah kiri
  2. Amati baris debug yang dihentikan di class QuoteController.
  3. Di debugger, klik ikon step over b814d39b2e5f3d9e.png
  4. Perhatikan bahwa sebuah kode mengembalikan HTTP 500 Error Server Internal ke klien. 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 else harus difaktorkan ulang untuk mengirim kembali kode status HTTP 404 tidak ditemukan.

Perbaiki error tersebut.

  1. Saat sesi Debug masih berjalan, selesaikan permintaan dengan menekan tombol "continue" di panel kontrol debug.
  2. Selanjutnya, ubah blok else menjadi kode:
       else {
                return new ResponseEntity<HttpStatus>(HttpStatus.NOT_FOUND);
            }

Metode 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);
        }
    }
  1. Menjalankan kembali perintah hapus
curl -v -X DELETE $URL/quotes/6
  1. Telusuri debugger dan amati HTTP 404 Not Found 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
  1. Hentikan sesi proses debug dengan mengklik kotak merah di toolbar debug

12bc3c82f63dcd8a.pngS

6f19c0f855832407.pngS

6. Selamat

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.

Yang telah Anda pelajari

  • Pengembangan InnerLoop dengan Cloud Workstations
  • Membuat aplikasi awal Java baru
  • Menjalani proses pengembangan
  • Mengembangkan Layanan REST CRUD sederhana
  • Melakukan proses debug aplikasi di cluster GKE
  • Menghubungkan aplikasi ke database CloudSQL