Cloud Workstations ve Cloud Code ile Geliştirme

1. Genel Bakış

Bu laboratuvar, container mimarisine alınmış bir ortamda Java uygulamaları geliştirmekten görevli yazılım mühendisleri için geliştirme iş akışını kolaylaştırmak amacıyla tasarlanmış özellikleri ve olanakları gösterir. Tipik container geliştirme yöntemleri, kullanıcının container ayrıntılarını ve container derleme sürecini anlamasını gerektirir. Buna ek olarak, geliştiricilerin uzak ortamlarda uygulamalarını test etmek ve hata ayıklamak için genellikle IDE'lerinden ayrılarak akışlarını bozmaları gerekir. Geliştiriciler, bu eğitimde bahsedilen araçlar ve teknolojiler sayesinde, IDE'lerinden ayrılmadan container mimarisine alınmış uygulamalarla verimli bir şekilde çalışabilirler.

Öğrenecekleriniz

Bu laboratuvarda, GCP'de container'larla geliştirme yapmaya yönelik aşağıdaki gibi yöntemleri öğreneceksiniz:

  • Cloud Workstations ile InnerLoop geliştirme
  • Yeni bir Java başlangıç uygulaması oluşturma
  • Geliştirme sürecinde rehberlik etme
  • Basit bir CRUD Dinlenme Hizmeti geliştirme
  • GKE kümesinde uygulama hata ayıklama
  • Uygulamayı CloudSQL veritabanına bağlama

58a4cdd3ed7a123a.png

2. Kurulum ve Gereksinimler

Kendi hızınızda ortam kurulumu

  1. Google Cloud Console'da oturum açıp yeni bir proje oluşturun veya mevcut bir projeyi yeniden kullanın. Gmail veya Google Workspace hesabınız yoksa hesap oluşturmanız gerekir.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • Proje adı, bu projenin katılımcıları için görünen addır. Google API'leri tarafından kullanılmayan bir karakter dizesidir. İstediğiniz zaman güncelleyebilirsiniz.
  • Proje Kimliği, tüm Google Cloud projelerinde benzersizdir ve değiştirilemez (belirlendikten sonra değiştirilemez). Cloud Console, otomatik olarak benzersiz bir dize oluşturur. bunun ne olduğunu umursamıyorsunuz. Çoğu codelab'de proje kimliğini (genellikle PROJECT_ID olarak tanımlanır) referans almanız gerekir. Oluşturulan kimliği beğenmezseniz rastgele bir kimlik daha oluşturabilirsiniz. Alternatif olarak, kendi ölçümünüzü deneyip mevcut olup olmadığına bakabilirsiniz. Bu adımdan sonra değiştirilemez ve proje süresince kalır.
  • Bilginiz için bazı API'lerin kullandığı üçüncü bir değer, yani Proje Numarası daha vardır. Bu değerlerin üçü hakkında daha fazla bilgiyi belgelerde bulabilirsiniz.
  1. Sonraki adımda, Cloud kaynaklarını/API'lerini kullanmak için Cloud Console'da faturalandırmayı etkinleştirmeniz gerekir. Bu codelab'i çalıştırmanın maliyeti, yüksek değildir. Bu eğitim dışında faturalandırma yapılmaması için kaynakları kapatmak isterseniz oluşturduğunuz kaynakları silebilir veya projenin tamamını silebilirsiniz. Yeni Google Cloud kullanıcıları, 300 ABD doları değerindeki ücretsiz denemeden yararlanabilir.

Cloudshell Düzenleyiciyi Başlat

Bu laboratuvar, Google Cloud Shell Düzenleyici ile birlikte kullanılmak üzere tasarlanmış ve test edilmiştir. Düzenleyiciye erişmek için

  1. https://console.cloud.google.com adresinden Google projenize erişin.
  2. Sağ üst köşedeki Cloud Shell düzenleyici simgesini tıklayın.

8560cc8d45e8c112.png

  1. Pencerenizin alt kısmında yeni bir bölme açılır
  2. Düzenleyiciyi Aç düğmesini tıklayın.

9e504cb98a6a8005.png

  1. Düzenleyici, sağda bir gezgin, orta alanda ise düzenleyici açılır.
  2. Ekranın alt kısmında da bir terminal bölmesi bulunmalıdır
  3. Terminal AÇIK DEĞİLSE yeni bir terminal penceresi açmak için "ctrl+"" tuş kombinasyonunu kullanın.

gcloud'u kurun

Cloud Shell'de proje kimliğinizi ve uygulamanızı dağıtmak istediğiniz bölgeyi ayarlayın. Bunları PROJECT_ID ve REGION değişkenleri olarak kaydedin.

export REGION=us-central1
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')

Kaynak kodu klonlama

Bu laboratuvarın kaynak kodu, GitHub'daki GoogleCloudPlatform'da bulunan container-developer-workshop'ta bulunmaktadır. Aşağıdaki komutla klonlayın, ardından dizine değiştirin.

git clone https://github.com/GoogleCloudPlatform/container-developer-workshop.git
cd container-developer-workshop/labs/spring-boot

Bu laboratuvarda kullanılan altyapıyı sağlayın

Bu laboratuvarda GKE'ye kod dağıtacak ve CloudSQL veritabanında depolanan verilere erişeceksiniz. Aşağıdaki kurulum komut dosyası, bu altyapıyı sizin için hazırlar. Temel hazırlık işlemi 25 dakikadan uzun sürer. Sonraki bölüme geçmeden önce komut dosyasının tamamlanmasını bekleyin.

./setup_with_cw.sh &

Cloud Workstations Kümesi

Cloud Console'da Cloud Workstations'ı açın. Kümenin READY durumunda olmasını bekleyin.

305e1a3d63ac7ff6.png

İş İstasyonları Yapılandırması Oluşturma

Cloud Shell oturumunuzun bağlantısı kesildiyse "Yeniden bağlan"ı tıklayın Ardından proje kimliğini ayarlamak için gcloud cli komutunu çalıştırın. Komutu çalıştırmadan önce aşağıdaki örnek proje kimliğini qwiklabs proje kimliğinizle değiştirin.

gcloud config set project qwiklabs-gcp-project-id

Cloud Workstations yapılandırması oluşturmak için aşağıdaki komut dosyasını terminalde çalıştırın.

cd ~/container-developer-workshop/labs/spring-boot
./workstation_config_setup.sh

Yapılandırmalar bölümündeki sonuçları doğrulayın. READY durumuna geçiş 2 dakika sürer.

7a6af5aa2807a5f2.png

Console'da Cloud Workstations'ı açın ve yeni örnek oluşturun.

a53adeeac81a78c8.png

Adı my-workstation olarak değiştirin ve mevcut yapılandırmayı seçin: codeoss-java.

f21c216997746097.png

İş İstasyonları bölümündeki sonuçları doğrulayın.

66a9fc8b20543e32.png

İş İstasyonunu Başlat

İş istasyonunu başlatın ve başlatın.

c91bb69b61ec8635.png

Adres çubuğundaki simgeyi tıklayarak 3. taraf çerezlerine izin verin. 1b8923e2943f9bc4.png

fcf9405b6957b7d7.png

"Site çalışmıyor mu?" seçeneğini tıklayın.

36a84c0e2e3b85b.png

"Çerezlere izin ver"i tıklayın.

2259694328628fba.png

İş istasyonu açıldığında Code OSS IDE görünür. "Tamamlandı Olarak İşaretle"yi tıklayın Başlarken sayfasında iş istasyonu IDE'sini

94874fba9b74cc22.png

3. Yeni bir Java başlangıç uygulaması oluşturma

Bu bölümde, spring.io tarafından sağlanan örnek bir uygulamayı kullanarak sıfırdan yeni bir Java Spring Boot uygulaması oluşturacaksınız. Yeni bir Terminal açın.

c31d48f2e4938c38.png

Örnek Uygulamayı Klonlama

  1. Başlangıç uygulaması oluşturma
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

Bu mesajı görürseniz İzin Ver düğmesini tıklayın. Böylece, kopyalayıp iş istasyonuna yapıştırabilirsiniz.

58149777e5cc350a.png

  1. Uygulamanın sıkıştırmasını açın
unzip sample-app.zip -d sample-app
  1. "sample-app"i açın klasör
cd sample-app && code-oss-cloud-workstations -r --folder-uri="$PWD"

Spring-boot-devtools &ekle Jib

Spring Boot Geliştirici Araçları'nı etkinleştirmek için düzenleyicinizdeki gezginde pom.xml dosyasını bulup açın. Sonra, aşağıdaki kodu, <description>Demo project for Spring Boot</description> yazan açıklama satırının arkasına yapıştırın

  1. pom.xml dosyasına spring-boot-devtools ekleyin

Projenin kök dizininde pom.xml dosyasını açın. Description girişinden sonra aşağıdaki yapılandırmayı ekleyin.

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. pom.xml dosyasında jib-maven-plugin özelliğini etkinleştir

Jib, Google tarafından sunulan açık kaynaklı bir Java container mimarisine alma aracıdır. Java geliştiricilerinin bildikleri Java araçlarını kullanarak container'lar oluşturmalarına olanak tanır. Jib, uygulamanızı bir container görüntüsüne paketlemenin tüm adımlarını kapsayan hızlı ve basit bir container görüntüsü oluşturucudur. Dockerfile yazmanız veya Dockerfile'ı yüklemenizi gerektirmez. Ayrıca, Maven ve Gradle'a doğrudan entegre edilmiştir.

pom.xml dosyasında aşağı doğru kaydırın ve Build bölümünü Jib eklentisini içerecek şekilde güncelleyin. Derleme bölümü tamamlandığında aşağıdakiyle eşleşmelidir.

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>

Manifest Oluşturma

Skaffold, container geliştirmeyi basitleştirmek için entegre araçlar sunar. Bu adımda Skaffold'ı ilk kullanıma hazırlayarak temel Kubernetes YAML dosyalarını otomatik olarak oluşturacaksınız. Bu işlem, Dockerfile gibi container görüntüsü tanımlarına sahip dizinleri tanımlamaya çalışır ve ardından her biri için dağıtım ve hizmet manifesti oluşturur.

İşlemi başlatmak için Terminal'de aşağıdaki komutu yürütün.

d869e0cd38e983d7.png

  1. Terminalde aşağıdaki komutu yürütün
skaffold init --generate-manifests
  1. İstendiğinde:
  • İmlecinizi Jib Maven Plugin adresine taşımak için okları kullanın
  • Seçeneği belirlemek için boşluk tuşuna basın.
  • Devam etmek için Enter tuşuna basın
  1. Bağlantı noktası için 8080 girin
  2. Yapılandırmayı kaydetmek için y yazın

skaffold.yaml ve deployment.yaml çalışma alanına iki dosya eklendi

Skaffold çıktısı:

b33cc1e0c2077ab8.png

Uygulama adını güncelleyin

Yapılandırmada yer alan varsayılan değerler şu anda uygulamanızın adıyla eşleşmemektedir. Dosyaları, varsayılan değerler yerine uygulama adınızı referans alacak şekilde güncelleyin.

  1. Skaffold yapılandırmasındaki girişleri değiştir
  • skaffold.yaml uygulamasını aç
  • Şu anda pom-xml-image olarak ayarlanmış olan resim adını seçin
  • Sağ tıklayın ve Tüm Tekrarları Değiştir'i seçin
  • Yeni adı demo-app olarak yazın
  1. Kubernetes yapılandırmasındaki girişleri değiştir
  • deployment.yaml dosyasını aç
  • Şu anda pom-xml-image olarak ayarlanmış olan resim adını seçin
  • Sağ tıklayın ve Tüm Tekrarları Değiştir'i seçin
  • Yeni adı demo-app olarak yazın

Otomatik senkronizasyon modunu etkinleştir

Optimize edilmiş bir çalışır durumda yeniden yükleme deneyimini kolaylaştırmak için Jib'in sağladığı Senkronizasyon özelliğini kullanırsınız. Bu adımda, Skaffold'ı derleme işleminde bu özelliği kullanacak şekilde yapılandıracaksınız.

"Senkronizasyon" seçeneğinin, profilindeki Spring "senkronizasyon" veya İlkbaharda geliştirme araçları için desteği etkinleştirdiğiniz önceki adımda yapılandırdığınız profil.

  1. Skaffold yapılandırmasını güncelle

skaffold.yaml dosyasında, dosyanın derleme bölümünün tamamını aşağıdaki spesifikasyonla değiştirin. Dosyanın diğer bölümlerini değiştirmeyin.

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

Varsayılan rota ekleme

/src/main/java/com/example/springboot/ klasöründe HelloController.java adlı bir dosya oluşturun.

a624f5dd0c477c09.png

Varsayılan bir http yolu oluşturmak için aşağıdaki içeriği dosyaya yapıştırın.

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. Geliştirme sürecinde rehberlik etme

Bu bölümde, temel işlemleri öğrenmek ve başlangıç uygulamanızın yapılandırmasını ve kurulumunu doğrulamak için Cloud Code eklentisini kullanma konusunda birkaç adım öğreneceksiniz.

Cloud Code, Skaffold ile entegre olarak geliştirme sürecinizi kolaylaştırır. Aşağıdaki adımlarda GKE'ye dağıtım yaptığınızda Cloud Code ve Skaffold, container görüntünüzü otomatik olarak derler, Container Registry'ye aktarır ve ardından uygulamanızı GKE'ye dağıtır. Bu, perde arkasında olup ayrıntıları geliştirici akışından uzaklaştırarak gerçekleşir. Cloud Code, container tabanlı geliştirme için geleneksel hata ayıklama ve hotspot özellikleri sağlayarak geliştirme sürecinizi de iyileştirir.

Google Cloud'da oturum açma

Cloud Code simgesini tıklayın ve "Sign in to Google Cloud" (Google Cloud'da oturum aç) seçeneğini belirleyin:

1769afd39be372ff.png

"Oturum açmak için devam et"i tıklayın.

923bb1c8f63160f9.png

Terminal'de çıkışı kontrol edin ve bağlantıyı açın:

517fdd579c34aa21.png

Qwiklabs öğrenci kimlik bilgilerinizle giriş yapın.

db99b345f7a8e72c.png

"İzin Ver"i seçin:

a5376553c430ac84.png

Doğrulama kodunu kopyalayın ve Workstation sekmesine dönün.

6719421277b92eac.png

Doğrulama kodunu yapıştırın ve Enter tuşuna basın.

e9847cfe3fa8a2ce.png

Kubernetes Kümesi Ekle

  1. Küme Ekle

62a3b97bdbb427e5.png

  1. Google Kubernetes Engine'i seçin:

9577de423568bbaa.png

  1. Proje seçin.

c5202fcbeebcd41c.png

  1. "quote-cluster"ı seçin ilk kurulumda oluşturulan bir feed'dir.

366cfd8bc27cd3ed.png

9d68532c9bc4a89b.png

gcloud cli'yi kullanarak geçerli proje kimliğini ayarlayın

Qwiklabs sayfasından bu laboratuvarın proje kimliğini kopyalayın.

fcff2d10007ec5bc.png

Proje kimliğini ayarlamak için gcloud cli komutunu çalıştırın. Komutu çalıştırmadan önce örnek proje kimliğini değiştirin.

gcloud config set project qwiklabs-gcp-project-id

Örnek çıktı:

f1c03d01b7ac112c.png

Kubernetes'te hata ayıkla

  1. En alttaki sol bölmede Cloud Code'u seçin.

60b8e4e95868b561.png

  1. GELİŞTİRME OTURUMLARI bölümünde gösterilen panelde Kubernetes'te hata ayıkla'yı seçin.

Seçenek görünmüyorsa sayfayı aşağı kaydırın.

7d30833d96632ca0.png

  1. "Evet"i seçin geçerli bağlamı kullanmak.

a024a69b64de7e9e.png

  1. "quote-cluster"ı seçin oluşturulan bir dosyayı otomatik olarak oluşturur.

faebabf372e3caf0.png

  1. Container Repository'i seçin.

fabc6dce48bae1b4.png

  1. İlerleme durumunu ve bildirimleri görüntülemek için alt bölmede Çıkış sekmesini seçin
  2. "Kubernetes: Çalıştır/Hata Ayıklama - Ayrıntılı" seçeneğini belirleyin "Kanaldan canlı yayınlanan" ek ayrıntıları ve günlükleri görüntülemek için sağdaki kanal açılır

86b44c59db58f8f3.png

Uygulamanın dağıtılmasını bekleyin.

9f37706a752829fe.png

  1. Cloud Console'dan, GKE'de dağıtılan uygulamayı inceleyin.

6ad220e5d1980756.png

  1. "Kubernetes: Çalıştır/Hata Ayıklama"yı seçerek basitleştirilmiş görünüme dönün açılır menüden "OUTPUT" (ÇIKIŞ) sekmesine gidin.
  2. Derleme ve testler tamamlandığında Çıkış sekmesinde Resource deployment/demo-app status completed successfully görüntülenir ve bir URL listelenir: "Hizmet demo uygulamasından yönlendirilen URL: http://localhost:8080"
  3. Cloud Code terminalinde çıkıştaki URL'nin (http://localhost:8080) üzerine gelin. Ardından, görünen araç ucunda Bağlantıyı takip et'i seçin.

28c5539880194a8e.png

Yeni bir sekme açılacak ve aşağıdaki çıkışı göreceksiniz:

d67253ca16238f49.png

Kesme noktalarından yararlanma

  1. /src/main/java/com/example/springboot/HelloController.java adresindeki HelloController.java uygulamasını açın
  2. return String.format("Hello from your %s environment!", target); değerini okuyan kök yol için döndürülen ifadeyi bulun
  3. Satır numarasının solundaki boş alanı tıklayarak bu satıra bir ayrılma noktası ekleyin. Kesme noktasının ayarlandığını belirten kırmızı bir gösterge görünür.

5027dc6da2618a39.png

  1. Tarayıcınızı yeniden yükleyin. Hata ayıklayıcının işlemi kesme noktasında durdurduğunu ve GKE'de uzaktan çalışan uygulamanın değişkenlerini ve durumunu incelemenize olanak tanıdığını unutmayın

71acfb426623cec2.png

  1. "Hedef"i bulana kadar değişkenler bölümünü tıklayın değişkenine eklenmelidir.
  2. Mevcut değeri "local" olarak gözlemle

a1160d2ed2bb5c82.png

  1. "target" değişken adını çift tıklayın Pop-up'ta

değeri "Cloud Workstations" olarak değiştirin.

e597a556a5c53f32.png

  1. Hata ayıklama kontrol panelinde Devam düğmesini tıklayın

ec17086191770d0d.png

  1. Az önce girdiğiniz güncellenmiş değeri gösteren yanıtı tarayıcınızda inceleyin.

6698a9db9e729925.png

  1. Satır numarasının solundaki kırmızı göstergeyi tıklayarak ayrılma noktasını kaldırın. Böylece, siz bu laboratuvarda ilerlerken kodunuzun bu satırda yürütülmesini durdurmanız önlenir.

Sıcak Yeniden Yükle

  1. İfadeyi, "%s Kodundan Merhaba" gibi farklı bir değer döndürecek şekilde değiştirin
  2. Dosya otomatik olarak kaydedilir ve GKE'deki uzak container'lara senkronize edilir.
  3. Güncellenen sonuçları görmek için tarayıcınızı yenileyin.
  4. Hata ayıklama araç çubuğundaki kırmızı kare simgesini tıklayarak hata ayıklama oturumunu durdurun.

a541f928ec8f430e.png c2752bb28d82af86.png

"Evet, her çalıştırmadan sonra temizle"yi seçin.

984eb2fa34867d70.png

5. Basit bir CRUD Dinlenme Hizmeti geliştirme

Bu noktada uygulamanız, container mimarisine alınmış geliştirme için tamamen yapılandırıldı ve Cloud Code ile temel geliştirme iş akışını öğrendiniz. Aşağıdaki bölümlerde, Google Cloud'da yönetilen bir veritabanına bağlanan REST hizmet uç noktaları ekleyerek öğrendiklerinizi uygulayacaksınız.

Bağımlılıkları Yapılandırma

Uygulama kodu, geri kalan hizmet verilerini saklamak için bir veritabanı kullanır. Aşağıdakileri pom.xl dosyasına ekleyerek bağımlılıkların mevcut olduğundan emin olun.

  1. pom.xml dosyasını açın ve yapılandırmanın bağımlılıklar bölümüne aşağıdakini ekleyin

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>

Kod REST hizmeti

Quote.java

/src/main/java/com/example/springboot/ ürününde Quote.java adlı bir dosya oluşturun ve aşağıdaki kodu kopyalayın. Bu, uygulamada kullanılan Alıntı nesnesi için Varlık modelini tanımlar.

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

src/main/java/com/example/springboot adresinde QuoteRepository.java adında bir dosya oluşturun ve aşağıdaki kodu kopyalayın

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();
}

Bu kod, verilerin saklanması için JPA'yı kullanır. Sınıf, Spring JPARepository arayüzünü genişletir ve özel kod oluşturulmasına olanak tanır. Bu kodda bir findRandomQuote özel yöntemi eklediniz.

QuoteController.java

Hizmetin uç noktasını kullanıma sunmak için bu işlevi QuoteController sınıfı sağlar.

src/main/java/com/example/springboot adresinde QuoteController.java adında bir dosya oluşturun ve aşağıdaki içeriği kopyalayın

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

}

Veritabanı Yapılandırmaları Ekleyin

application.yaml

Hizmet tarafından erişilen arka uç veritabanı için yapılandırma ekleyin. src/main/resources altındaki application.yaml dosyasını düzenleyin (veya mevcut değilse oluşturun) ve arka uç için parametreleştirilmiş bir Spring yapılandırması ekleyin.

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

Veritabanı Taşıma İşlemi Ekleme

src/main/resources altında db/migration klasörleri oluşturun

SQL dosyası oluşturun: V1__create_quotes_table.sql

Aşağıdaki içeriği dosyaya yapıştırın

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 Yapılandırması

deployment.yaml dosyasına yapılan aşağıdaki eklemeler, uygulamanın CloudSQL örneklerine bağlanmasına olanak tanır.

  • HEDEF - Değişkeni, uygulamanın yürütüldüğü ortamı belirtecek şekilde yapılandırır
  • SPRING_PROFILES_ACTIVE: cloud-dev olarak yapılandırılacak etkin Spring profilini gösterir.
  • DB_HOST; veritabanı örneği oluşturulduğunda veya Google Cloud Console'un Gezinme Menüsünde SQL simgesini tıklayarak not edilen, veritabanına ait özel IP'dir. Lütfen değeri değiştirin .
  • DB_USER ve DB_PASS - CloudSQL örnek yapılandırmasında ayarlandığı şekilde, GCP'de Gizli Anahtar olarak saklanır

delivery.yaml dosyanızı aşağıdaki içeriklerle güncelleyin.

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

Terminalde aşağıdaki komutları çalıştırarak DB_HOST değerini Veritabanınızın adresiyle değiştirin:

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

delivery.yaml dosyasını açın ve DB_HOST değerinin, Örnek IP'si ile güncellendiğini doğrulayın.

fd63c0aede14beba.png

Uygulamayı Dağıtma ve Doğrulama

  1. Cloud Shell Düzenleyici'nin alt kısmındaki bölmede Cloud Code'u ve ardından ekranın üst kısmındaki Kubernetes'te Hata ayıkla'yı seçin.

33a5cf41aae91adb.png

  1. Derleme ve testler tamamlandığında Çıkış sekmesinde Resource deployment/demo-app status completed successfully görüntülenir ve bir URL listelenir: "Hizmet demo uygulamasından yönlendirilen URL: http://localhost:8080". Bağlantı noktasının bazen 8081 gibi farklı olabileceğini unutmayın. Öyleyse uygun değeri ayarlayın. Terminalde URL değerini ayarlayın
export URL=localhost:8080
  1. Rastgele Alıntıları Görüntüle

Terminal'den, aşağıdaki komutu rastgele tırnak uç noktasında birden çok kez çalıştırın. Farklı alıntılar döndüren tekrarlanan aramaları gözlemleme

curl $URL/random-quote | jq
  1. Fiyat Teklifi Ekle

Aşağıda listelenen komutu kullanarak id=6 ile yeni bir fiyat teklifi oluşturun ve isteğin tekrarlandığını gözlemleyin

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. Alıntı silme

Şimdi, delete yöntemiyle eklediğiniz alıntıyı silin ve bir HTTP/1.1 204 yanıt kodunu gözlemleyin.

curl -v -X DELETE $URL/quotes/6
  1. Sunucu Hatası

Giriş silindikten sonra son isteği tekrar çalıştırarak hata durumuyla karşılaşabilirsiniz

curl -v -X DELETE $URL/quotes/6

Yanıtın HTTP:500 Internal Server Error döndürdüğüne dikkat edin.

Uygulamada hata ayıkla

Önceki bölümde, veritabanında olmayan bir girişi silmeye çalıştığınızda uygulamada bir hata durumu buldunuz. Bu bölümde sorunun yerini belirlemek için bir ayrılma noktası belirleyeceksiniz. Hata DELETE işleminde meydana geldiği için quoteController sınıfıyla çalışacaksınız.

  1. src/main/java/com/example/springboot/QuoteController.java uygulamasını aç
  2. deleteQuote() yöntemini bulun
  3. Şu satırı bulun: Optional<Quote> quote = quoteRepository.findById(id);
  4. Satır numarasının solundaki boş alanı tıklayarak bu satırda bir ayrılma noktası belirleyin.
  5. Kesme noktasının ayarlandığını gösteren kırmızı bir gösterge görünür
  6. delete komutunu tekrar çalıştırın
curl -v -X DELETE $URL/quotes/6
  1. Sol sütundaki simgeyi tıklayarak hata ayıklama görünümüne geri dönebilirsiniz
  2. quoteController sınıfında duran hata ayıklama satırını inceleyin.
  3. Hata ayıklayıcıda step over simgesini b814d39b2e5f3d9e.png tıklayın.
  4. Bir kodun istemciye, ideal olmayan bir Dahili Sunucu Hatası HTTP 500 döndürdüğüne dikkat edin.
   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

Kodu güncelleme

Kod yanlıştır ve else bloğunun, HTTP 404 bulunamadı durum kodunu geri göndermesi için yeniden düzenlenmesi gerekir.

Hatayı düzeltin.

  1. Hata Ayıklama oturumu devam ederken "devam" düğmesine basarak isteği tamamlayın düğmesini tıklayın.
  2. Sonra else blokunu kodla değiştirin:
       else {
                return new ResponseEntity<HttpStatus>(HttpStatus.NOT_FOUND);
            }

Yöntem aşağıdaki gibi görünmelidir:

@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. Sil komutunu yeniden çalıştırma
curl -v -X DELETE $URL/quotes/6
  1. Hata ayıklayıcıyı adım adım inceleyin ve arayana döndürülen HTTP 404 Bulunamadı hatasını gözlemleyin.
   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. Hata ayıklama araç çubuğundaki kırmızı kare simgesini tıklayarak hata ayıklama oturumunu durdurun.

12bc3c82f63dcd8a.png

6f19c0f855832407.png

6. Tebrikler

Tebrikler! Bu laboratuvarda, sıfırdan yeni bir Java uygulaması oluşturdunuz ve bu uygulamayı kapsayıcılarla etkili bir şekilde çalışacak şekilde yapılandırdınız. Ardından geleneksel uygulama yığınlarında bulunan geliştirici akışını izleyerek uygulamanızı uzak bir GKE kümesine dağıttınız ve hatalarını ayıkladınız.

Öğrendikleriniz

  • Cloud Workstations ile InnerLoop geliştirme
  • Yeni bir Java başlangıç uygulaması oluşturma
  • Geliştirme sürecinde rehberlik etme
  • Basit bir CRUD REST Hizmeti geliştirme
  • GKE kümesinde uygulama hata ayıklama
  • Uygulamayı CloudSQL veritabanına bağlama