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 akışlarını kesmeleri, IDE'lerinden çıkmaları 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:
- Kurulum ve Gereksinimler
- Yeni bir Java başlangıç uygulaması oluşturma
- Geliştirme sürecinde rehberlik etme
- Basit bir CRUD Dinlenme Hizmeti geliştirme
- Temizleme
2. Kurulum ve Gereksinimler
Kendi hızınızda ortam kurulumu
- 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.
- 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 ve bunu istediğiniz zaman güncelleyebilirsiniz.
- Proje Kimliği, tüm Google Cloud projelerinde benzersiz olmalıdır 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ğine referans vermeniz gerekir (ve bu kimlik genellikle
PROJECT_ID
olarak tanımlanır). Beğenmezseniz başka bir rastgele kod oluşturun ya da kendi proje kimliğinizi deneyip mevcut olup olmadığına bakın. Sıcaklık "soğudu" takip etmeniz gerekir. - Bazı API'lerin kullandığı üçüncü bir değer, yani Proje Numarası daha vardır. Bu değerlerin üçü hakkında daha fazla bilgiyi belgelerde bulabilirsiniz.
- Ardından, 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ırmayla karşılaşmamak için kaynakları kapatmak istiyorsanız tüm "temizleme" işlemlerini uygulayın buradaki talimatları uygulayın. 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
- https://console.cloud.google.com adresinden Google projenize erişin.
- Sağ üst köşedeki Cloud Shell düzenleyici simgesini tıklayın.
- Pencerenizin alt kısmında yeni bir bölme açılır
- Düzenleyiciyi Aç düğmesini tıklayın.
- Düzenleyici, sağ tarafta bir gezgin, orta alanda ise düzenleyici açılır.
- Ekranın alt kısmında da bir terminal bölmesi bulunmalıdır
- 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 PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
Kaynak kodunu alma
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 10 dakikadan uzun sürer. Kurulum işlenirken sonraki birkaç adımla devam edebilirsiniz.
./setup.sh
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
Örnek Uygulamayı Klonlama
- Başlangıç uygulaması oluşturma
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
- Uygulamanın sıkıştırmasını açın
unzip sample-app.zip -d sample-app
- sample-app dizinine geçin ve klasörü Cloud Shell IDE çalışma alanında açın.
cd sample-app && cloudshell workspace .
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>Yazlı Bot için tanıtım projesi</description> yazan açıklama satırının arkasına yapıştırın
- pom.xml dosyasına spring-boot-devtools ekleyin
Projenin kök dizininde bulunan 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>
- pom.xml dosyasında jib-maven-plugin özelliğini etkinleştir
Jib, Java geliştiricilerinin bildikleri Java araçlarını kullanarak container'lar oluşturmalarına olanak tanıyan, Google'ın açık kaynak Java container mimarisine alma araçlarıdı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>
Derleme dosyası değişikliği istenirse Always
öğesini seçin.
Manifest Oluşturma
Skaffold, container geliştirmeyi basitleştirmek için entegre araçlar sunar. Bu adımda temel Kubernetes YAML dosyalarını otomatik olarak oluşturacak şekilde skaffold'u başlatacaksı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 aşağıdaki komutu yürütün.
- Terminalde aşağıdaki komutu yürütün
skaffold init --generate-manifests
- İ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
- Bağlantı noktası için 8080 girin
- Yapılandırmayı kaydetmek için y yazın
Çalışma alanı görünümüne şu iki dosya eklendi: skaffold.yaml
ve deployment.yaml
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.
- 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
- 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
Çalışır durumda senkronizasyonu etkinleştir
Optimize edilmiş bir çalışır durumda yeniden yükleme deneyimini kolaylaştırmak için Jib tarafından sağlanan 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, yapılandırmasında yapılandırdığınız Spring "sync" etiketinden yararlanır. İlkbaharda geliştirme araçları için desteği etkinleştirdiğiniz önceki adımda yapılandırdığınız profil.
- Skaffold yapılandırmasını güncelle
skaffold.yaml dosyasında, dosyanın tüm derleme bölümü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/java:debug
sync:
auto: true
Varsayılan rota ekleme
/src/main/java/com/example/springboot/ konumunda HelloController.java adlı bir dosya oluşturun.
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.
Kubernetes'e dağıtma
- Cloud Shell Düzenleyici'nin alt kısmındaki bölmeden Cloud Code'u seçin.
- Üst kısımda görünen panelde Kubernetes'te hata ayıkla'yı seçin. İstenirse geçerli Kubernetes bağlamını kullanmak için Evet'i seçin.
- Komutu ilk kez çalıştırdığınızda ekranın üst kısmında geçerli Kubernetes bağlamını isteyip istemediğinizi soran bir istem görünür. "Evet"i seçin geçerli bağlamı kabul edip kullanmak.
- Ardından, hangi container kayıt defterinin kullanılacağını soran bir istem gösterilir. Sağlanan varsayılan değeri kabul etmek için Enter tuşuna basın
- İlerleme durumunu ve bildirimleri görüntülemek için alt bölmede Çıkış sekmesini seçin
- "Kubernetes: Çalıştır/Hata Ayıklama - Ayrıntılı" seçeneğini belirleyin "sağdaki kanal açılır menüsünü tıklayıp ek ayrıntıları ve kapsayıcılardan canlı yayınlanan günlükleri görüntüleyin"
- "Kubernetes: Çalıştır/Hata Ayıklama"yı seçerek basitleştirilmiş görünüme dönün açılır menüden
- 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" - Cloud Code terminalinde çıkıştaki URL'nin (http://localhost:8080) üzerine gelin. Ardından, görünen araç ucunda Web Önizlemesini Aç'ı seçin.
Yanıt şöyle olacaktır:
Hello from your local environment!
Kesme noktalarından yararlanma
- /src/main/java/com/example/springboot/HelloController.java adresinde bulunan HelloController.java uygulamasını açın.
return String.format("Hello from your %s environment!", target);
değerini okuyan kök yol için döndürülen ifadeyi bulun- 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.
- 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şken kum durumunu incelemenize olanak tanıdığını unutmayın
- "Hedef"i bulana kadar değişkenler bölümünü tıklayın değişkenine eklenmelidir.
- Mevcut değeri "local" olarak gözlemle
- "target" değişken adını çift tıklayın Pop-up pencerede değeri "Bulut" gibi farklı bir değerle değiştirin
- Hata ayıklama kontrol panelinde Devam düğmesini tıklayın
- Az önce girdiğiniz güncellenmiş değeri gösteren yanıtı tarayıcınızda inceleyin.
Sıcak Yeniden Yükle
- İfadeyi, "%s Kodundan Merhaba" gibi farklı bir değer döndürecek şekilde değiştirin
- Dosya otomatik olarak kaydedilir ve GKE'deki uzak container'lara senkronize edilir.
- Güncellenen sonuçları görmek için tarayıcınızı yenileyin.
- Hata ayıklama araç çubuğundaki kırmızı kare simgesini tıklayarak hata ayıklama oturumunu durdurun
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 dinlenme hizmeti 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.
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>
Geri kalan hizmeti kodlayın
Quote.java
/src/main/java/com/example/springboot/ konumunda quote.java adında 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 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
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) {
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);
}
}
}
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/db/migration/ konumunda bir klasör 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
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
Uygulamayı Dağıtma ve Doğrulama
- 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.
- 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" - Rastgele Alıntıları Görüntüle
Cloudshell Terminal'den aşağıdaki komutu rastgele alıntı uç noktasında birden çok kez çalıştırın. Farklı alıntılar döndüren tekrarlanan aramaları gözlemleme
curl -v 127.0.0.1:8080/random-quote
- 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 -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
- 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 127.0.0.1:8080/quotes/6
- Sunucu Hatası
Giriş silindikten sonra son isteği tekrar çalıştırarak hata durumuyla karşılaşabilirsiniz
curl -v -X DELETE 127.0.0.1:8080/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.
- src.main.java.com.example.springboot.quoteController.java açın
deleteQuote()
yöntemini bulun- Veritabanından bir öğenin silindiği satırı bulun:
quoteRepository.deleteById(id);
- Satır numarasının solundaki boş alanı tıklayarak bu satırda bir ayrılma noktası belirleyin.
- Kesme noktasının ayarlandığını gösteren kırmızı bir gösterge görünür
delete
komutunu tekrar çalıştırın
curl -v -X DELETE 127.0.0.1:8080/quotes/6
- Sol sütundaki simgeyi tıklayarak hata ayıklama görünümüne geri dönebilirsiniz
- quoteController sınıfında duran hata ayıklama satırını inceleyin.
- Hata ayıklayıcıda
step over
simgesini tıklayın ve bir istisnanın atıldığını gözlemleyin. - Çok genel bir
RuntimeException was caught.
değerinin istemciye dahili Sunucu Hatası olan HTTP 500 döndürdüğünü ve bu hatanın ideal olmadığını unutmayın.
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. İstisna bloğunun, EmptyResultDataAccessException
istisnasını yakalamak ve bir HTTP 404 bulunamadı durum kodunu geri göndermek için yeniden düzenlenmesi gerekir.
Hatayı düzeltin.
- Hata Ayıklama oturumu devam ederken "devam" düğmesine basarak isteği tamamlayın düğmesini tıklayın.
- Sonra, aşağıdaki bloku koda ekleyin:
} catch (EmptyResultDataAccessException e){
return new ResponseEntity<HttpStatus>(HttpStatus.NOT_FOUND);
}
Yöntem aşağıdaki gibi görünmelidir:
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); } }
- Sil komutunu yeniden çalıştırma
curl -v -X DELETE 127.0.0.1:8080/quotes/6
- Hata ayıklayıcıyı adım adım inceleyin ve
EmptyResultDataAccessException
öğesinin yakalandığını ve çağrı yapana bir HTTP 404 Bulunamadı hatası döndürüldüğü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
- Hata ayıklama araç çubuğundaki kırmızı kare simgesini tıklayarak hata ayıklama oturumunu durdurun
6. Temizleme
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.
Laboratuvarı tamamladıktan sonra yer açmak için:
- Laboratuvarda kullanılan dosyaları silme
cd ~ && rm -rf container-developer-workshop
- İlgili tüm altyapı ve kaynakları kaldırmak için projeyi silin