1. بررسی اجمالی
این آزمایشگاه ویژگیها و قابلیتهایی را نشان میدهد که برای سادهسازی گردش کار توسعه برای مهندسان نرمافزاری که وظیفه توسعه برنامههای پایتون را در یک محیط کانتینری دارند، طراحی شده است. توسعه کانتینر معمولی به کاربر نیاز دارد که جزئیات کانتینرها و فرآیند ساخت کانتینر را درک کند. علاوه بر این، توسعه دهندگان معمولاً باید جریان خود را قطع کنند و از IDE خود خارج شوند تا برنامه های خود را در محیط های راه دور آزمایش و اشکال زدایی کنند. با ابزارها و فناوری های ذکر شده در این آموزش، توسعه دهندگان می توانند بدون خروج از IDE خود، با برنامه های کانتینری به طور موثر کار کنند.
آنچه خواهید آموخت
در این آزمایشگاه روش هایی برای توسعه با کانتینرها در GCP از جمله:
- ایجاد یک برنامه شروع جدید پایتون
- روند توسعه را طی کنید
- یک سرویس استراحت ساده CRUD ایجاد کنید
2. راه اندازی و الزامات
تنظیم محیط خود به خود
- به Google Cloud Console وارد شوید و یک پروژه جدید ایجاد کنید یا از یک موجود استفاده مجدد کنید. اگر قبلاً یک حساب Gmail یا Google Workspace ندارید، باید یک حساب ایجاد کنید .
- نام پروژه نام نمایشی برای شرکت کنندگان این پروژه است. این یک رشته کاراکتری است که توسط API های Google استفاده نمی شود و می توانید هر زمان که بخواهید آن را به روز کنید.
- شناسه پروژه باید در تمام پروژههای Google Cloud منحصربهفرد باشد و تغییرناپذیر باشد (پس از تنظیم نمیتوان آن را تغییر داد). Cloud Console به طور خودکار یک رشته منحصر به فرد تولید می کند. معمولاً برای شما مهم نیست که چیست. در اکثر کدها، باید به شناسه پروژه ارجاع دهید (و معمولاً به عنوان
PROJECT_ID
شناخته میشود)، بنابراین اگر آن را دوست ندارید، یک نمونه تصادفی دیگر ایجاد کنید، یا میتوانید شناسه پروژه را امتحان کنید و ببینید در دسترس است. سپس پس از ایجاد پروژه "یخ زده" می شود. - یک مقدار سوم وجود دارد، یک شماره پروژه که برخی از API ها از آن استفاده می کنند. در مورد هر سه این مقادیر در مستندات بیشتر بیاموزید.
- در مرحله بعد، برای استفاده از منابع Cloud/APIها، باید صورتحساب را در کنسول Cloud فعال کنید . اجرا کردن از طریق این کد لبه نباید هزینه زیادی داشته باشد، اگر اصلاً باشد. برای اینکه منابع را خاموش کنید تا بیش از این آموزش متحمل صورتحساب نشوید، دستورالعملهای «پاکسازی» را که در انتهای Codelab یافت میشود دنبال کنید. کاربران جدید Google Cloud واجد شرایط برنامه آزمایشی رایگان 300 دلاری هستند.
ویرایشگر Cloudshell را شروع کنید
این آزمایشگاه برای استفاده با Google Cloud Shell Editor طراحی و آزمایش شده است. برای دسترسی به ویرایشگر،
- به پروژه Google خود در https://console.cloud.google.com دسترسی پیدا کنید.
- در گوشه بالا سمت راست روی نماد ویرایشگر پوسته ابری کلیک کنید
- یک صفحه جدید در پایین پنجره شما باز می شود
- بر روی دکمه Open Editor کلیک کنید
- ویرایشگر با یک کاوشگر در سمت راست و ویرایشگر در ناحیه مرکزی باز می شود
- یک صفحه ترمینال نیز باید در پایین صفحه موجود باشد
- اگر ترمینال باز نیست، از کلید ترکیبی «ctrl+» برای باز کردن پنجره ترمینال جدید استفاده کنید
راه اندازی محیط
در Cloud Shell، شناسه پروژه و شماره پروژه را برای پروژه خود تنظیم کنید. آنها را به عنوان متغیرهای PROJECT_ID
و PROJECT_ID
ذخیره کنید.
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/python
mkdir music-service && cd music-service
cloudshell workspace .
اگر ترمینال باز نیست، از کلید ترکیبی «ctrl+» برای باز کردن پنجره ترمینال جدید استفاده کنید
زیرساخت های مورد استفاده در این آزمایشگاه را فراهم کنید
در این آزمایشگاه شما کد را در GKE مستقر خواهید کرد و به داده های ذخیره شده در پایگاه داده Spanner دسترسی خواهید داشت. اسکریپت راه اندازی زیر این زیرساخت را برای شما آماده می کند. فرآیند تهیه بیش از 10 دقیقه طول خواهد کشید. در حالی که تنظیمات در حال پردازش است، می توانید چند مرحله بعدی را ادامه دهید.
../setup.sh
3. یک برنامه شروع جدید پایتون ایجاد کنید
- فایلی به نام
requirements.txt
ایجاد کنید و مطالب زیر را در آن کپی کنید
Flask
gunicorn
google-cloud-spanner
ptvsd==4.3.2
- یک فایل به نام
app.py
ایجاد کنید و کد زیر را در آن قرار دهید
import os
from flask import Flask, request, jsonify
from google.cloud import spanner
app = Flask(__name__)
@app.route("/")
def hello_world():
message="Hello, World!"
return message
if __name__ == '__main__':
server_port = os.environ.get('PORT', '8080')
app.run(debug=False, port=server_port, host='0.0.0.0')
- یک فایل به نام Dockerfile ایجاد کنید و موارد زیر را در آن قرار دهید
FROM python:3.8
ARG FLASK_DEBUG=0
ENV FLASK_DEBUG=$FLASK_DEBUG
ENV FLASK_APP=app.py
WORKDIR /app
COPY requirements.txt .
RUN pip install --trusted-host pypi.python.org -r requirements.txt
COPY . .
ENTRYPOINT ["python3", "-m", "flask", "run", "--port=8080", "--host=0.0.0.0"]
توجه : FLASK_DEBUG=1 به شما امکان میدهد تا تغییرات کد را در یک برنامه فلاسک پایتون بارگیری مجدد کنید. این Dockerfile به شما اجازه می دهد تا این مقدار را به عنوان یک آرگومان ساخت ارسال کنید.
ایجاد مانیفست
در ترمینال خود دستور زیر را برای ایجاد skaffold.yaml و deployment.yaml پیش فرض اجرا کنید
- Skaffold را با دستور زیر مقدار دهی اولیه کنید
skaffold init --generate-manifests
وقتی از شما خواسته شد از فلش ها برای حرکت مکان نما و از نوار فاصله برای انتخاب گزینه ها استفاده کنید.
انتخاب کنید:
-
8080
برای پورت -
y
برای ذخیره تنظیمات
پیکربندی های Skaffold را به روز کنید
- نام برنامه پیش فرض را تغییر دهید
-
skaffold.yaml
باز کنید - نام تصویری که در حال حاضر به عنوان
dockerfile-image
تنظیم شده را انتخاب کنید - کلیک راست کرده و Change All Occurrences را انتخاب کنید
- نام جدید را به عنوان
python-app
وارد کنید - در ادامه بخش ساخت را ویرایش کنید
- برای عبور
FLASK_DEBUG=1
docker.buildArgs
را اضافه کنید - تنظیمات را برای بارگیری هرگونه تغییر در فایل های
*.py
از IDE به ظرف در حال اجرا، همگام کنید
پس از ویرایش ها، بخش ساخت در فایل skaffold.yaml
به صورت زیر خواهد بود:
build:
artifacts:
- image: python-app
docker:
buildArgs:
FLASK_DEBUG: 1
dockerfile: Dockerfile
sync:
infer:
- '**/*.py'
فایل پیکربندی Kubernetes را اصلاح کنید
- نام پیش فرض را تغییر دهید
- فایل
deployment.yaml
را باز کنید - نام تصویری که در حال حاضر به عنوان
dockerfile-image
تنظیم شده را انتخاب کنید - کلیک راست کرده و Change All Occurrences را انتخاب کنید
- نام جدید را به عنوان
python-app
وارد کنید
4. قدم زدن در فرآیند توسعه
با اضافه شدن منطق تجاری، اکنون می توانید برنامه خود را مستقر کرده و آزمایش کنید. بخش زیر استفاده از افزونه Cloud Code را برجسته می کند. از جمله موارد دیگر، این افزونه با skaffold ادغام می شود تا روند توسعه شما را ساده کند. هنگامی که در مراحل زیر در GKE مستقر می شوید، Cloud Code و Skaffold به طور خودکار تصویر کانتینر شما را می سازند، آن را به یک رجیستری کانتینر فشار می دهند و سپس برنامه شما را در GKE مستقر می کنند. این در پشت صحنه اتفاق می افتد و جزئیات را به دور از جریان توسعه دهنده انتزاع می کند.
به Kubernetes مستقر شوید
- در قسمت پایین Cloud Shell Editor، Cloud Code  را انتخاب کنید
- در پانلی که در بالا ظاهر میشود، Run on Kubernetes را انتخاب کنید. در صورت درخواست، Yes را برای استفاده از زمینه Kubernetes فعلی انتخاب کنید.
این دستور یک بیلد از کد منبع را شروع می کند و سپس تست ها را اجرا می کند. ساخت و آزمایش چند دقیقه طول می کشد تا اجرا شود. این تست ها شامل تست های واحد و یک مرحله اعتبار سنجی است که قوانین تنظیم شده برای محیط استقرار را بررسی می کند. این مرحله اعتبار سنجی قبلاً پیکربندی شده است، و تضمین می کند که شما در مورد مشکلات استقرار هشدار دریافت می کنید، حتی زمانی که هنوز در محیط توسعه خود کار می کنید.
- اولین باری که دستور را اجرا میکنید، یک فرمان در بالای صفحه ظاهر میشود که از شما میپرسد آیا میخواهید زمینه فعلی kubernetes را داشته باشید، برای پذیرش و استفاده از زمینه فعلی، «بله» را انتخاب کنید.
- سپس یک درخواست نمایش داده می شود که از کدام رجیستری کانتینری استفاده کنید. اینتر را فشار دهید تا مقدار پیش فرض ارائه شده را بپذیرید
- برای مشاهده پیشرفت و اعلان ها، تب Output را در قسمت پایین انتخاب کنید
- "Kubernetes: Run/Debug - Detailed" را در منوی کشویی کانال به سمت راست انتخاب کنید تا جزئیات بیشتر و گزارشها را به صورت زنده از کانتینرها مشاهده کنید.
هنگامی که ساخت و آزمایش انجام شد، برگه خروجی میگوید: Attached debugger to container "python-app-8476f4bbc-h6dsl" successfully.
، و URL http://localhost:8080 فهرست شده است.
- در ترمینال Cloud Code، ماوس را روی اولین URL در خروجی نگه دارید (http://localhost:8080) و سپس در نکته ابزار ظاهر شده Open Web Preview را انتخاب کنید.
- یک تب جدید مرورگر باز می شود و پیام
Hello, World!
بارگذاری مجدد داغ
- فایل
app.py
باز کنید - پیام تبریک را
Hello from Python
تغییر دهید
فوراً توجه کنید که در پنجره Output
، نمایش Kubernetes: Run/Debug
، ناظر فایل های به روز شده را با ظرف در Kubernetes همگام می کند.
Update initiated Build started for artifact python-app Build completed for artifact python-app Deploy started Deploy completed Status check started Resource pod/python-app-6f646ffcbb-tn7qd status updated to In Progress Resource deployment/python-app status updated to In Progress Resource deployment/python-app status completed successfully Status check succeeded ...
- اگر به
Kubernetes: Run/Debug - Detailed
، متوجه خواهید شد که تغییرات فایل را تشخیص میدهد و سپس برنامه را میسازد و مجدداً مستقر میکند.
files modified: [app.py]
Syncing 1 files for gcr.io/veer-pylab-01/python-app:3c04f58-dirty@sha256:a42ca7250851c2f2570ff05209f108c5491d13d2b453bb9608c7b4af511109bd
Copying files:map[app.py:[/app/app.py]]togcr.io/veer-pylab-01/python-app:3c04f58-dirty@sha256:a42ca7250851c2f2570ff05209f108c5491d13d2b453bb9608c7b4af511109bd
Watching for changes...
[python-app] * Detected change in '/app/app.py', reloading
[python-app] * Restarting with stat
[python-app] * Debugger is active!
[python-app] * Debugger PIN: 744-729-662
- مرورگر خود را به روز کنید تا نتایج به روز شده را ببینید.
اشکال زدایی
- به نمای Debug بروید و رشته فعلی را متوقف کنید
.
- روی
Cloud Code
در منوی پایین کلیک کنید وDebug on Kubernetes
را انتخاب کنید تا برنامه در حالتdebug
اجرا شود.
- در
Kubernetes Run/Debug - Detailed
پنجرهOutput
، توجه کنید که skaffold این برنامه را در حالت اشکال زدایی مستقر می کند.
- اولین باری که این کار اجرا می شود، از شما می پرسد که منبع در داخل ظرف کجاست. این مقدار مربوط به دایرکتوری های موجود در Dockerfile است.
برای پذیرش پیش فرض، Enter را فشار دهید
چند دقیقه طول می کشد تا برنامه ساخته و اجرا شود.
- زمانی که فرآیند تکمیل شد. متوجه خواهید شد که یک دیباگر پیوست شده است.
Port forwarding pod/python-app-8bd64cf8b-cskfl in namespace default, remote port 5678 -> http://127.0.0.1:5678
- نوار وضعیت پایین رنگ خود را از آبی به نارنجی تغییر می دهد که نشان می دهد در حالت Debug قرار دارد.
- در نمای
Kubernetes Run/Debug
، توجه کنید که یک ظرف اشکالزدایی راهاندازی شده است
**************URLs***************** Forwarded URL from service python-app: http://localhost:8080 Debuggable container started pod/python-app-8bd64cf8b-cskfl:python-app (default) Update succeeded ***********************************
از نقاط شکست استفاده کنید
- فایل
app.py
باز کنید - بیانیه ای را که
return message
می خواند پیدا کنید - با کلیک بر روی فضای خالی سمت چپ شماره خط، یک نقطه شکست به آن خط اضافه کنید. یک نشانگر قرمز نشان می دهد تا توجه داشته باشید که نقطه شکست تنظیم شده است
- مرورگر خود را دوباره بارگیری کنید و توجه داشته باشید که دیباگر فرآیند را در نقطه شکست متوقف می کند و به شما امکان می دهد متغیرها و وضعیت برنامه ای را که از راه دور در GKE اجرا می شود بررسی کنید.
- در قسمت VARIABLES پایین کلیک کنید
- در آنجا روی Locals کلیک کنید و متغیر
"message"
پیدا خواهید کرد. - روی نام متغیر "message" دوبار کلیک کنید و در پنجره بازشو مقدار را به چیزی متفاوت مانند
"Greetings from Python"
تغییر دهید. - روی دکمه Continue در کنترل پنل اشکال زدایی کلیک کنید
- پاسخ را در مرورگر خود مرور کنید که اکنون مقدار به روز شده ای را که وارد کرده اید نشان می دهد.
- با فشار دادن دکمه توقف، حالت "Debug" را متوقف کنید
و با کلیک مجدد بر روی نقطه شکست، نقطه شکست را حذف کنید.
5. توسعه یک سرویس استراحت ساده CRUD
در این مرحله برنامه شما به طور کامل برای توسعه کانتینری پیکربندی شده است و شما در جریان کار توسعه اولیه با Cloud Code قدم زده اید. در بخشهای بعدی، آنچه را که آموختهاید، با افزودن نقاط پایانی سرویس استراحت برای اتصال به پایگاه داده مدیریتشده در Google Cloud تمرین میکنید.
سرویس بقیه را کد کنید
کد زیر یک سرویس استراحت ساده ایجاد می کند که از Spanner به عنوان پایگاه داده پشتیبان برنامه استفاده می کند. برنامه را با کپی کردن کد زیر در برنامه خود ایجاد کنید.
- برنامه اصلی را با جایگزین کردن
app.py
با محتوای زیر ایجاد کنید
import os
from flask import Flask, request, jsonify
from google.cloud import spanner
app = Flask(__name__)
instance_id = "music-catalog"
database_id = "musicians"
spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
@app.route('/singer', methods=['POST'])
def create():
try:
request_json = request.get_json()
singer_id = request_json['singer_id']
first_name = request_json['first_name']
last_name = request_json['last_name']
def insert_singers(transaction):
row_ct = transaction.execute_update(
f"INSERT Singers (SingerId, FirstName, LastName) VALUES" \
f"({singer_id}, '{first_name}', '{last_name}')"
)
print("{} record(s) inserted.".format(row_ct))
database.run_in_transaction(insert_singers)
return {"Success": True}, 200
except Exception as e:
return e
@app.route('/singer', methods=['GET'])
def get_singer():
try:
singer_id = request.args.get('singer_id')
def get_singer():
first_name = ''
last_name = ''
with database.snapshot() as snapshot:
results = snapshot.execute_sql(
f"SELECT SingerId, FirstName, LastName FROM Singers " \
f"where SingerId = {singer_id}",
)
for row in results:
first_name = row[1]
last_name = row[2]
return (first_name,last_name )
first_name, last_name = get_singer()
return {"first_name": first_name, "last_name": last_name }, 200
except Exception as e:
return e
@app.route('/singer', methods=['PUT'])
def update_singer_first_name():
try:
singer_id = request.args.get('singer_id')
request_json = request.get_json()
first_name = request_json['first_name']
def update_singer(transaction):
row_ct = transaction.execute_update(
f"UPDATE Singers SET FirstName = '{first_name}' WHERE SingerId = {singer_id}"
)
print("{} record(s) updated.".format(row_ct))
database.run_in_transaction(update_singer)
return {"Success": True}, 200
except Exception as e:
return e
@app.route('/singer', methods=['DELETE'])
def delete_singer():
try:
singer_id = request.args.get('singer')
def delete_singer(transaction):
row_ct = transaction.execute_update(
f"DELETE FROM Singers WHERE SingerId = {singer_id}"
)
print("{} record(s) deleted.".format(row_ct))
database.run_in_transaction(delete_singer)
return {"Success": True}, 200
except Exception as e:
return e
port = int(os.environ.get('PORT', 8080))
if __name__ == '__main__':
app.run(threaded=True, host='0.0.0.0', port=port)
افزودن تنظیمات پایگاه داده
برای اتصال ایمن به Spanner، برنامه را طوری تنظیم کنید که از Workload Identities استفاده کند. این به برنامه شما امکان می دهد تا به عنوان حساب سرویس خود عمل کند و هنگام دسترسی به پایگاه داده مجوزهای فردی داشته باشد.
- به روز رسانی
deployment.yaml
. کد زیر را در انتهای فایل اضافه کنید (مطمئن شوید که تورفتگی های تب را در مثال زیر حفظ کرده اید)
serviceAccountName: python-ksa
nodeSelector:
iam.gke.io/gke-metadata-server-enabled: "true"
استقرار و اعتبارسنجی برنامه
- در قسمت پایین Cloud Shell Editor،
Cloud Code
را انتخاب کنید و سپسDebug on Kubernetes
در بالای صفحه انتخاب کنید. - هنگامی که ساخت و آزمایش انجام شد، برگه خروجی میگوید:
Resource deployment/python-app status completed successfully
، و یک آدرس اینترنتی فهرست میشود: «URL فوروارد شده از سرویس python-app: http://localhost:8080» - چند ورودی اضافه کنید.
از ترمینال cloudshell، دستور زیر را اجرا کنید
curl -X POST http://localhost:8080/singer -H 'Content-Type: application/json' -d '{"first_name":"Cat","last_name":"Meow", "singer_id": 6}'
- GET را با اجرای دستور زیر در ترمینال تست کنید
curl -X GET http://localhost:8080/singer?singer_id=6
- Test Delete: اکنون با اجرای دستور زیر سعی کنید یک ورودی را حذف کنید. در صورت نیاز مقدار item-id را تغییر دهید.
curl -X DELETE http://localhost:8080/singer?singer_id=6
This throws an error message
500 Internal Server Error
مشکل را شناسایی و برطرف کنید
- حالت Debug و پیدا کردن مشکل. در اینجا چند نکته وجود دارد:
- ما می دانیم که مشکلی در DELETE وجود دارد زیرا نتیجه دلخواه را بر نمی گرداند. بنابراین شما باید نقطه شکست را در
app.py
در روشdelete_singer
تنظیم کنید. - اجرای مرحله به مرحله را اجرا کنید و متغیرها را در هر مرحله مشاهده کنید تا مقادیر متغیرهای محلی را در پنجره سمت چپ مشاهده کنید.
- برای مشاهده مقادیر خاصی مانند
singer_id
وrequest.args
در افزودن این متغیرها به پنجره Watch.
- توجه داشته باشید که مقدار اختصاص داده شده به
singer_id
None
است. کد را تغییر دهید تا مشکل برطرف شود.
قطعه کد ثابت به این شکل خواهد بود.
@app.route('/delete-singer', methods=['DELETE', 'GET']) def delete_singer(): try: singer_id = request.args.get('singer_id')
- پس از راه اندازی مجدد برنامه، با تلاش برای حذف دوباره تست کنید.
- با کلیک بر روی مربع قرمز در نوار ابزار اشکال زدایی، جلسه اشکال زدایی را متوقف کنید
6. پاکسازی
تبریک می گویم! در این آزمایشگاه شما یک برنامه جدید پایتون را از ابتدا ایجاد کرده اید و آن را پیکربندی کرده اید تا به طور موثر با کانتینرها کار کند. سپس برنامه خود را به دنبال همان جریان توسعهدهنده موجود در پشتههای برنامههای سنتی، در یک خوشه راهدور GKE مستقر کرده و اشکال زدایی کردید.
برای تمیز کردن پس از تکمیل آزمایشگاه:
- فایل های مورد استفاده در آزمایشگاه را حذف کنید
cd ~ && rm -rf container-developer-workshop
- برای حذف تمام زیرساخت ها و منابع مرتبط، پروژه را حذف کنید