1. بررسی اجمالی
این آزمایشگاه ویژگیها و قابلیتهایی را نشان میدهد که برای ساده کردن گردش کار توسعه برای مهندسان نرمافزاری که وظیفه توسعه برنامههای جاوا را در یک محیط کانتینری دارند، طراحی شده است. توسعه کانتینر معمولی به کاربر نیاز دارد که جزئیات کانتینرها و فرآیند ساخت کانتینر را درک کند. علاوه بر این، توسعه دهندگان معمولاً باید جریان خود را قطع کنند و از IDE خود خارج شوند تا برنامه های خود را در محیط های راه دور آزمایش و اشکال زدایی کنند. با ابزارها و فناوری های ذکر شده در این آموزش، توسعه دهندگان می توانند بدون خروج از IDE خود، با برنامه های کانتینری به طور موثر کار کنند.
آنچه خواهید آموخت
در این آزمایشگاه روش هایی برای توسعه با کانتینرها در GCP از جمله:
- توسعه InnerLoop با ایستگاه های کاری ابری
- ایجاد یک برنامه استارت جدید جاوا
- قدم زدن در فرآیند توسعه
- توسعه یک سرویس استراحت ساده CRUD
- برنامه اشکال زدایی در خوشه GKE
- اتصال برنامه به پایگاه داده CloudSQL
2. راه اندازی و الزامات
تنظیم محیط خود به خود
- به Google Cloud Console وارد شوید و یک پروژه جدید ایجاد کنید یا از یک موجود استفاده مجدد کنید. اگر قبلاً یک حساب Gmail یا Google Workspace ندارید، باید یک حساب ایجاد کنید .
- نام پروژه نام نمایشی برای شرکت کنندگان این پروژه است. این یک رشته کاراکتری است که توسط API های Google استفاده نمی شود. شما می توانید آن را در هر زمان به روز کنید.
- شناسه پروژه در تمام پروژههای Google Cloud منحصربهفرد است و تغییرناپذیر است (پس از تنظیم نمیتوان آن را تغییر داد). Cloud Console به طور خودکار یک رشته منحصر به فرد تولید می کند. معمولاً برای شما مهم نیست که چیست. در اکثر کدها، باید به شناسه پروژه ارجاع دهید (معمولاً به عنوان
PROJECT_ID
شناخته می شود). اگر شناسه تولید شده را دوست ندارید، ممکن است یک شناسه تصادفی دیگر ایجاد کنید. از طرف دیگر، میتوانید خودتان را امتحان کنید و ببینید آیا در دسترس است یا خیر. پس از این مرحله نمی توان آن را تغییر داد و در طول مدت پروژه باقی می ماند. - برای اطلاع شما، یک مقدار سوم وجود دارد، یک شماره پروژه که برخی از API ها از آن استفاده می کنند. در مورد هر سه این مقادیر در مستندات بیشتر بیاموزید.
- در مرحله بعد، برای استفاده از منابع Cloud/APIها باید صورتحساب را در کنسول Cloud فعال کنید . اجرا کردن از طریق این کد لبه نباید هزینه زیادی داشته باشد، اگر اصلاً باشد. برای اینکه منابع را خاموش کنید تا بیش از این آموزش متحمل صورتحساب نشوید، می توانید منابعی را که ایجاد کرده اید حذف کنید یا کل پروژه را حذف کنید. کاربران جدید Google Cloud واجد شرایط برنامه آزمایشی رایگان 300 دلاری هستند.
ویرایشگر Cloudshell را شروع کنید
این آزمایشگاه برای استفاده با Google Cloud Shell Editor طراحی و آزمایش شده است. برای دسترسی به ویرایشگر،
- به پروژه Google خود در https://console.cloud.google.com دسترسی پیدا کنید.
- در گوشه بالا سمت راست روی نماد ویرایشگر پوسته ابری کلیک کنید
- یک صفحه جدید در پایین پنجره شما باز می شود
- بر روی دکمه Open Editor کلیک کنید
- ویرایشگر با یک کاوشگر در سمت راست و ویرایشگر در ناحیه مرکزی باز می شود
- یک صفحه ترمینال نیز باید در پایین صفحه موجود باشد
- اگر ترمینال باز نیست، از کلید ترکیبی «ctrl+» برای باز کردن پنجره ترمینال جدید استفاده کنید
gcloud را راه اندازی کنید
در Cloud Shell، شناسه پروژه و منطقه ای را که می خواهید برنامه خود را در آن مستقر کنید، تنظیم کنید. آنها را به عنوان متغیرهای PROJECT_ID
و REGION
ذخیره کنید.
export REGION=us-central1
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
کد منبع را کلون کنید
کد منبع این آزمایشگاه در کارگاه توسعه دهنده کانتینر در GoogleCloudPlatform در GitHub قرار دارد. با دستور زیر آن را کلون کنید سپس به دایرکتوری تغییر دهید.
git clone https://github.com/GoogleCloudPlatform/container-developer-workshop.git
cd container-developer-workshop/labs/spring-boot
زیرساخت های مورد استفاده در این آزمایشگاه را فراهم کنید
در این آزمایشگاه شما کد را در GKE مستقر خواهید کرد و به داده های ذخیره شده در پایگاه داده CloudSQL دسترسی خواهید داشت. اسکریپت راه اندازی زیر این زیرساخت را برای شما آماده می کند. فرآیند تهیه بیش از 25 دقیقه طول خواهد کشید. قبل از رفتن به بخش بعدی منتظر بمانید تا اسکریپت کامل شود.
./setup_with_cw.sh &
Cloud Workstation Cluster
ایستگاه های کاری Cloud را در Cloud Console باز کنید. منتظر بمانید تا خوشه در وضعیت READY
باشد.
ایجاد پیکربندی ایستگاه های کاری
اگر جلسه Cloud Shell شما قطع شد، روی "Reconnect" کلیک کنید و سپس دستور gcloud cli را برای تنظیم ID پروژه اجرا کنید. قبل از اجرای دستور، شناسه پروژه نمونه زیر را با ID پروژه qwiklabs خود جایگزین کنید.
gcloud config set project qwiklabs-gcp-project-id
برای ایجاد تنظیمات Cloud Workstations، اسکریپت زیر را در ترمینال اجرا کنید.
cd ~/container-developer-workshop/labs/spring-boot
./workstation_config_setup.sh
نتایج را در بخش تنظیمات تأیید کنید. انتقال به وضعیت آماده 2 دقیقه طول می کشد.
ایستگاه های کاری Cloud را در کنسول باز کنید و نمونه جدیدی ایجاد کنید.
نام را به my-workstation
تغییر دهید و پیکربندی موجود را انتخاب کنید: codeoss-java
.
نتایج را در بخش ایستگاه های کاری بررسی کنید.
ایستگاه کاری را راه اندازی کنید
ایستگاه کاری را راه اندازی و راه اندازی کنید.
با کلیک بر روی نماد در نوار آدرس، کوکیهای شخص ثالث را مجاز کنید.
روی "سایت کار نمی کند؟" کلیک کنید.
روی "Allow cookies" کلیک کنید.
پس از راه اندازی ایستگاه کاری، کد OSS IDE را مشاهده خواهید کرد. روی "علامت گذاری انجام شده" در صفحه شروع به کار در یکی از IDE ایستگاه کاری کلیک کنید
3. ایجاد یک برنامه جدید Java starter
در این بخش با استفاده از یک برنامه نمونه ارائه شده توسط spring.io، یک برنامه Java Spring Boot جدید از ابتدا ایجاد خواهید کرد. یک ترمینال جدید باز کنید.
نمونه برنامه را کلون کنید
- یک برنامه شروع ایجاد کنید
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
در صورت مشاهده این پیغام روی دکمه Allow کلیک کنید تا بتوانید در ایستگاه کاری کپی کنید.
- برنامه را از حالت فشرده خارج کنید
unzip sample-app.zip -d sample-app
- پوشه "sample-app" را باز کنید
cd sample-app && code-oss-cloud-workstations -r --folder-uri="$PWD"
Spring-boot-devtools & Jib را اضافه کنید
برای فعال کردن Spring Boot DevTools، pom.xml را از کاوشگر در ویرایشگر خود پیدا کرده و باز کنید. سپس کد زیر را بعد از خط توضیحات قرار دهید که <description>Demo project for Spring Boot</description>
میخواند.
- Spring-boot-devtools را در pom.xml اضافه کنید
pom.xml
در ریشه پروژه باز کنید. پیکربندی زیر را بعد از ورودی 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>
- پلاگین jib-maven-plugin را در pom.xml فعال کنید
Jib یک ابزار جاوا منبع باز از Google است که به توسعه دهندگان جاوا اجازه می دهد با استفاده از ابزارهای جاوا که می شناسند، کانتینر بسازند. Jib یک سازنده تصویر ظرف سریع و ساده است که تمام مراحل بسته بندی برنامه شما را در یک تصویر ظرف انجام می دهد. نیازی به نوشتن Dockerfile یا نصب داکر ندارد و مستقیماً با Maven و Gradle ادغام می شود.
در فایل pom.xml
به پایین اسکرول کنید و بخش Build
را به روز کنید تا افزونه Jib را نیز در آن قرار دهد. پس از تکمیل، بخش ساخت باید با موارد زیر مطابقت داشته باشد.
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>
ایجاد مانیفست
Skaffold ابزارهای یکپارچه ای را برای ساده سازی توسعه کانتینر فراهم می کند. در این مرحله شما Skaffold را مقداردهی اولیه می کنید که به طور خودکار فایل های پایه Kubernetes YAML را ایجاد می کند. این فرآیند سعی میکند دایرکتوریهایی را با تعریف تصویر کانتینر، مانند Dockerfile شناسایی کند، و سپس برای هر کدام یک مانیفست استقرار و سرویس ایجاد میکند.
برای شروع فرآیند، دستور زیر را در ترمینال اجرا کنید.
- دستور زیر را در ترمینال اجرا کنید
skaffold init --generate-manifests
- وقتی از شما خواسته شد:
- از فلش ها برای انتقال مکان نما به
Jib Maven Plugin
استفاده کنید - برای انتخاب گزینه، کلید فاصله را فشار دهید.
- برای ادامه اینتر را فشار دهید
- 8080 را برای پورت وارد کنید
- برای ذخیره تنظیمات y را وارد کنید
دو فایل به فضای کاری skaffold.yaml
و deployment.yaml
اضافه می شود
خروجی داربست:
نام برنامه را به روز کنید
مقادیر پیشفرض موجود در پیکربندی در حال حاضر با نام برنامه شما مطابقت ندارد. فایل ها را برای ارجاع به نام برنامه خود به جای مقادیر پیش فرض به روز کنید.
- ورودیها را در پیکربندی Skaffold تغییر دهید
-
skaffold.yaml
باز کنید - نام تصویری که در حال حاضر به عنوان
pom-xml-image
تنظیم شده را انتخاب کنید - کلیک راست کرده و Change All Occurrences را انتخاب کنید
- نام جدید را به عنوان
demo-app
تایپ کنید
- ورودیهای پیکربندی Kubernetes را تغییر دهید
- فایل
deployment.yaml
را باز کنید - نام تصویری که در حال حاضر به عنوان
pom-xml-image
تنظیم شده را انتخاب کنید - کلیک راست کرده و Change All Occurrences را انتخاب کنید
- نام جدید را به عنوان
demo-app
تایپ کنید
حالت همگامسازی خودکار را فعال کنید
برای تسهیل تجربه بارگیری مجدد داغ بهینه شده، از ویژگی Sync ارائه شده توسط Jib استفاده خواهید کرد. در این مرحله شما Skaffold را برای استفاده از آن ویژگی در فرآیند ساخت پیکربندی خواهید کرد.
توجه داشته باشید که نمایه «همگامسازی» که در پیکربندی Skaffold پیکربندی میکنید، از نمایه «همگامسازی» Spring که در مرحله قبل پیکربندی کردهاید، استفاده میکند، جایی که پشتیبانی از Spring-dev-tools را فعال کردهاید.
- پیکربندی Skaffold را به روز کنید
در فایل skaffold.yaml
کل بخش ساخت فایل را با مشخصات زیر جایگزین کنید. بخش های دیگر فایل را تغییر ندهید.
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
یک مسیر پیش فرض اضافه کنید
فایلی به نام HelloController.java
در پوشه /src/main/java/com/example/springboot/
ایجاد کنید.
محتویات زیر را در فایل قرار دهید تا یک مسیر پیش فرض http ایجاد کنید.
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. قدم زدن در فرآیند توسعه
در این بخش با استفاده از افزونه Cloud Code چند مرحله را طی میکنید تا فرآیندهای اساسی را بیاموزید و پیکربندی و راهاندازی برنامه شروع خود را تأیید کنید.
Cloud Code با Skaffold ادغام می شود تا فرآیند توسعه شما را ساده کند. هنگامی که در مراحل زیر در GKE مستقر می شوید، Cloud Code و Skaffold به طور خودکار تصویر کانتینر شما را می سازند، آن را به یک رجیستری کانتینر فشار می دهند و سپس برنامه شما را در GKE مستقر می کنند. این در پشت صحنه اتفاق می افتد و جزئیات را به دور از جریان توسعه دهنده انتزاع می کند. Cloud Code همچنین با ارائه قابلیتهای سنتی Debug و Hotsync برای توسعه مبتنی بر کانتینر، فرآیند توسعه شما را افزایش میدهد.
به Google Cloud وارد شوید
روی نماد Cloud Code کلیک کنید و "Sign in to Google Cloud" را انتخاب کنید:
روی "ادامه برای ورود به سیستم" کلیک کنید.
خروجی را در ترمینال بررسی کنید و پیوند را باز کنید:
با اعتبارنامه دانشجویان Qwiklabs خود وارد شوید.
"مجاز" را انتخاب کنید:
کد تأیید را کپی کنید و به تب Workstation برگردید.
کد تایید را بچسبانید و Enter را بزنید.
خوشه Kubernetes را اضافه کنید
- یک خوشه اضافه کنید
- موتور Google Kubernetes را انتخاب کنید:
- پروژه را انتخاب کنید
- "quote-cluster" را که در تنظیمات اولیه ایجاد شده است انتخاب کنید.
با استفاده از gcloud cli شناسه پروژه فعلی را تنظیم کنید
شناسه پروژه را برای این آزمایشگاه از صفحه qwiklabs کپی کنید.
برای تنظیم ID پروژه، دستور gcloud cli را اجرا کنید. قبل از اجرای دستور، شناسه پروژه نمونه را جایگزین کنید.
gcloud config set project qwiklabs-gcp-project-id
خروجی نمونه:
اشکال زدایی در Kubernetes
- در قسمت سمت چپ در پایین، Cloud Code را انتخاب کنید.
- در پانلی که در زیر DEVELOPMENT SESSIONS ظاهر می شود، Debug on Kubernetes را انتخاب کنید.
اگر گزینه قابل مشاهده نیست، به پایین اسکرول کنید.
- برای استفاده از زمینه فعلی "بله" را انتخاب کنید.
- "Cluster-Cluster" را انتخاب کنید که در طول راه اندازی اولیه ایجاد شده است.
- Container Repository را انتخاب کنید.
- برای مشاهده پیشرفت و اعلان ها، تب Output را در قسمت پایین انتخاب کنید
- "Kubernetes: Run/Debug - Detailed" را در منوی کشویی کانال به سمت راست انتخاب کنید تا جزئیات بیشتر و گزارشها را به صورت زنده از کانتینرها مشاهده کنید.
منتظر بمانید تا برنامه اجرا شود.
- برنامه مستقر شده در GKE را در Cloud Console مرور کنید.
- با انتخاب "Kubernetes: Run/Debug" از منوی کشویی در برگه OUTPUT به نمای ساده شده بازگردید.
- وقتی ساخت و آزمایش انجام شد، برگه خروجی میگوید:
Resource deployment/demo-app status completed successfully
، و یک نشانی اینترنتی فهرست میشود: «URL بازارسال شده از برنامه آزمایشی سرویس: http://localhost:8080» - در ترمینال Cloud Code، نشانی اینترنتی موجود در خروجی (http://localhost:8080) را نگه دارید و سپس در نکته ابزاری که ظاهر میشود، پیوند را دنبال کنید.
تب جدید باز می شود و خروجی را در زیر می بینید:
از نقاط شکست استفاده کنید
- برنامه
HelloController.java
واقع در/src/main/java/com/example/springboot/HelloController.java
را باز کنید - عبارت return را برای مسیر ریشه پیدا کنید که
return String.format("Hello from your %s environment!", target);
- با کلیک بر روی فضای خالی سمت چپ شماره خط، یک نقطه شکست به آن خط اضافه کنید. یک نشانگر قرمز نشان می دهد تا توجه داشته باشید که نقطه شکست تنظیم شده است
- مرورگر خود را دوباره بارگیری کنید و توجه داشته باشید که دیباگر فرآیند را در نقطه شکست متوقف می کند و به شما امکان می دهد متغیرها و وضعیت برنامه ای را که از راه دور در GKE اجرا می شود بررسی کنید.
- در قسمت متغیرها کلیک کنید تا متغیر "هدف" را پیدا کنید.
- مقدار فعلی را به عنوان "محلی" مشاهده کنید
- روی نام متغیر "target" دوبار کلیک کنید و در پنجره بازشو،
مقدار را به "Cloud Workstations" تغییر دهید
- روی دکمه Continue در کنترل پنل اشکال زدایی کلیک کنید
- پاسخ را در مرورگر خود مرور کنید که اکنون مقدار به روز شده ای را که وارد کرده اید نشان می دهد.
- با کلیک بر روی نشانگر قرمز در سمت چپ شماره خط، نقطه شکست را حذف کنید. این کار مانع از توقف اجرای کد شما در این خط در حین حرکت در این آزمایشگاه میشود.
بارگذاری مجدد داغ
- عبارت را تغییر دهید تا مقدار دیگری مانند "Hello from %s Code" را برگردانید
- فایل به طور خودکار در کانتینرهای راه دور در GKE ذخیره و همگام سازی می شود
- مرورگر خود را به روز کنید تا نتایج به روز شده را ببینید.
- با کلیک بر روی مربع قرمز در نوار ابزار اشکال زدایی، جلسه اشکال زدایی را متوقف کنید
"Yes clean up after every run" را انتخاب کنید.
5. ایجاد یک سرویس استراحت ساده CRUD
در این مرحله برنامه شما به طور کامل برای توسعه کانتینری پیکربندی شده است و شما در جریان کار توسعه اولیه با Cloud Code قدم زده اید. در بخشهای بعدی، آنچه را که آموختهاید با افزودن نقاط پایانی سرویس REST که به پایگاه داده مدیریتشده در Google Cloud متصل میشوند، تمرین میکنید.
پیکربندی وابستگی ها
کد برنامه از یک پایگاه داده برای حفظ بقیه داده های سرویس استفاده می کند. با افزودن موارد زیر در pom.xl، اطمینان حاصل کنید که وابستگی ها در دسترس هستند
- فایل
pom.xml
را باز کنید و موارد زیر را به بخش وابستگی های پیکربندی اضافه کنید
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>
سرویس کد REST
نقل قول.java
یک فایل به نام Quote.java
در /src/main/java/com/example/springboot/
ایجاد کنید و در کد زیر کپی کنید. این مدل Entity را برای شی Quote استفاده شده در برنامه تعریف می کند.
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
فایلی به نام QuoteRepository.java
در src/main/java/com/example/springboot
ایجاد کنید و در کد زیر کپی کنید.
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();
}
این کد از JPA برای تداوم داده ها استفاده می کند. کلاس رابط Spring JPARepository
را گسترش می دهد و اجازه ایجاد کد سفارشی را می دهد. در کد شما یک روش سفارشی findRandomQuote
اضافه کرده اید.
QuoteController.java
برای نشان دادن نقطه پایانی سرویس، یک کلاس QuoteController
این قابلیت را ارائه می دهد.
فایلی به نام QuoteController.java
در src/main/java/com/example/springboot
ایجاد کنید و در مطالب زیر کپی کنید.
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);
}
}
}
افزودن تنظیمات پایگاه داده
application.yaml
پیکربندی را برای پایگاه داده باطن مورد دسترسی سرویس اضافه کنید. فایلی به نام فایل application.yaml
را در زیر src/main/resources
ویرایش کنید (یا ایجاد کنید) و یک پیکربندی Spring پارامتری برای 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
مهاجرت پایگاه داده را اضافه کنید
پوشه های db/migration
را در زیر src/main/resources
ایجاد کنید
یک فایل SQL ایجاد کنید: V1__create_quotes_table.sql
مطالب زیر را در فایل قرار دهید
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
اضافات زیر به فایل deployment.yaml
به برنامه اجازه می دهد تا به نمونه های CloudSQL متصل شود.
- TARGET - متغیر را برای نشان دادن محیطی که برنامه در آن اجرا می شود پیکربندی می کند
- SPRING_PROFILES_ACTIVE - نمایه فعال Spring را نشان می دهد که برای
cloud-dev
پیکربندی می شود - DB_HOST - IP خصوصی برای پایگاه داده، که هنگام ایجاد نمونه پایگاه داده یا با کلیک کردن بر روی
SQL
در منوی ناوبری Google Cloud Console ذکر شده است - لطفا مقدار را تغییر دهید! - DB_USER و DB_PASS - همانطور که در پیکربندی نمونه CloudSQL تنظیم شده است، به عنوان یک Secret در GCP ذخیره می شود
deployment.yaml خود را با محتوای زیر به روز کنید.
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 را با آدرس پایگاه داده خود جایگزین کنید:
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
deployment.yaml را باز کنید و بررسی کنید که مقدار DB_HOST با IP نمونه به روز شده باشد.
استقرار و اعتبارسنجی برنامه
- در قسمت پایین Cloud Shell Editor، Cloud Code را انتخاب کنید و سپس Debug on Kubernetes را در بالای صفحه انتخاب کنید.
- وقتی ساخت و آزمایش انجام شد، برگه خروجی میگوید:
Resource deployment/demo-app status completed successfully
، و یک نشانی اینترنتی فهرست میشود: «URL فوروارد شده از برنامه آزمایشی سرویس: http://localhost:8080 ». توجه داشته باشید که گاهی اوقات پورت ممکن است مانند 8081 متفاوت باشد. در این صورت مقدار مناسب را تنظیم کنید. مقدار URL را در ترمینال تنظیم کنید
export URL=localhost:8080
- مشاهده نقل قول های تصادفی
از ترمینال، دستور زیر را چندین بار در مقابل نقطه پایانی نقل قول تصادفی اجرا کنید. تماس های مکرر را مشاهده کنید که نقل قول های مختلف را برمی گرداند
curl $URL/random-quote | jq
- یک نقل قول اضافه کنید
یک نقل قول جدید با id=6 با استفاده از دستور فهرست شده در زیر ایجاد کنید و مشاهده کنید که درخواست برگشت داده می شود.
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
- یک نقل قول را حذف کنید
اکنون نقل قولی را که با روش حذف اضافه کرده اید حذف کنید و کد پاسخ HTTP/1.1 204
را مشاهده کنید.
curl -v -X DELETE $URL/quotes/6
- خطای سرور
با اجرای مجدد آخرین درخواست پس از حذف ورودی، حالت خطا را تجربه کنید
curl -v -X DELETE $URL/quotes/6
توجه داشته باشید که پاسخ یک HTTP:500 Internal Server Error
برمیگرداند.
برنامه را اشکال زدایی کنید
در بخش قبل، هنگام تلاش برای حذف یک ورودی که در پایگاه داده نبود، یک حالت خطا در برنامه پیدا کردید. در این بخش یک نقطه انفصال برای پیدا کردن مشکل تعیین می کنید. این خطا در عملیات DELETE رخ داده است، بنابراین شما با کلاس QuoteController کار خواهید کرد.
-
src/main/java/com/example/springboot/QuoteController.java
را باز کنید - متد
deleteQuote()
پیدا کنید - خط را پیدا کنید:
Optional<Quote> quote = quoteRepository.findById(id);
- با کلیک بر روی فضای خالی سمت چپ شماره خط، یک نقطه شکست در آن خط تعیین کنید.
- یک نشانگر قرمز ظاهر می شود که نشان می دهد نقطه شکست تنظیم شده است
- دوباره دستور
delete
را اجرا کنید
curl -v -X DELETE $URL/quotes/6
- با کلیک بر روی نماد در ستون سمت چپ به نمای اشکال زدایی برگردید
- خط اشکال زدایی متوقف شده در کلاس QuoteController را مشاهده کنید.
- در دیباگر، روی نماد
step over
کلیک کنید - توجه داشته باشید که یک کد یک خطای سرور داخلی HTTP 500 را به مشتری برمی گرداند که ایده آل نیست.
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
کد را به روز کنید
کد نادرست است و بلوک else
باید دوباره ساخته شود تا کد وضعیت HTTP 404 یافت نشد.
خطا را تصحیح کنید.
- در حالی که جلسه Debug هنوز در حال اجرا است، با فشار دادن دکمه "ادامه" در کنترل پنل اشکال زدایی، درخواست را تکمیل کنید.
- بعد بلوک
else
را به کد تغییر دهید:
else {
return new ResponseEntity<HttpStatus>(HttpStatus.NOT_FOUND);
}
روش باید به شکل زیر باشد
@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); } }
- دستور delete را دوباره اجرا کنید
curl -v -X DELETE $URL/quotes/6
- از اشکالزدا عبور کنید و مشاهده کنید که HTTP 404 Not Found به تماسگیرنده بازگردانده میشود.
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
- با کلیک بر روی مربع قرمز در نوار ابزار اشکال زدایی، جلسه اشکال زدایی را متوقف کنید
6. تبریک می گویم
تبریک می گویم! در این آزمایشگاه شما یک برنامه جدید جاوا را از ابتدا ایجاد کرده اید و آن را برای کارکرد موثر با کانتینرها پیکربندی کرده اید. سپس برنامه خود را به دنبال همان جریان توسعهدهنده موجود در پشتههای برنامههای سنتی، در یک خوشه راهدور GKE مستقر کرده و اشکال زدایی کردید.
آنچه شما آموخته اید
- توسعه InnerLoop با ایستگاه های کاری ابری
- ایجاد یک برنامه استارت جدید جاوا
- قدم زدن در فرآیند توسعه
- توسعه یک سرویس ساده CRUD REST
- برنامه اشکال زدایی در خوشه GKE
- اتصال برنامه به پایگاه داده CloudSQL