Hướng dẫn hội thảo thực hành kỹ thuật về Duet AI dành cho nhà phát triển trong lớp học lập trình

1. Mục tiêu

Mục đích của hội thảo này là cung cấp thông tin giáo dục thực tế về Duet AI cho người dùng và chuyên gia.

Trong lớp học lập trình này, bạn sẽ tìm hiểu những nội dung sau:

  1. Kích hoạt Duet AI trong dự án GCP của bạn và định cấu hình để sử dụng trong một IDE và Cloud Console.
  2. Sử dụng Duet AI để tạo, hoàn thành và giải thích mã.
  3. Sử dụng Duet AI để giải thích và khắc phục vấn đề về ứng dụng.
  4. Các tính năng của Duet AI như trò chuyện trên IDE và trò chuyện nhiều lượt, so sánh tính năng trò chuyện với tính năng tạo mã nội tuyến, các thao tác thông minh như giải thích mã và xác nhận đọc thuộc lòng, v.v.

Narrative

Để minh hoạ cách sử dụng Duet AI cho nhà phát triển một cách chân thực trong quá trình phát triển hằng ngày, các hoạt động của hội thảo này diễn ra trong một bối cảnh tường thuật.

Một nhà phát triển mới gia nhập một công ty thương mại điện tử. Họ có nhiệm vụ thêm một dịch vụ mới vào ứng dụng thương mại điện tử hiện có (bao gồm nhiều dịch vụ). Dịch vụ mới này cung cấp thêm thông tin (kích thước, trọng lượng, v.v.) về các sản phẩm trong danh mục sản phẩm. Dịch vụ này sẽ giúp bạn có phí vận chuyển thấp hơn/hợp lý hơn dựa trên kích thước và trọng lượng của sản phẩm.

Vì là nhà phát triển mới của công ty, nên họ sẽ sử dụng Duet AI để tạo, giải thích và lập tài liệu về mã.

Sau khi dịch vụ được mã hoá, quản trị viên nền tảng sẽ sử dụng Duet AI (tính năng trò chuyện) để giúp tạo cấu phần phần mềm (vùng chứa Docker) và các tài nguyên cần thiết để triển khai cấu phần phần mềm đó vào GCP (ví dụ: Artifact Registry, quyền IAM, kho lưu trữ mã, cơ sở hạ tầng điện toán, tức là GKE hoặc CloudRun, v.v.)

Sau khi triển khai ứng dụng lên GCP, nhà điều hành ứng dụng/SRE sẽ sử dụng Duet AI (và Cloud Ops) để giúp khắc phục lỗi trong dịch vụ mới.

Vai trò

Hội thảo này đề cập đến những người dùng sau:

  1. Nhà phát triển ứng dụng – Cần có một số kiến thức về lập trình và phát triển phần mềm.

Phiên bản này của hội thảo Duet AI chỉ dành cho nhà phát triển. Bạn không cần có kiến thức về tài nguyên đám mây GCP. Bạn có thể tìm thấy các tập lệnh về cách tạo tài nguyên GCP cần thiết để chạy ứng dụng này tại đây. Bạn có thể làm theo hướng dẫn trong tài liệu này để triển khai các tài nguyên GCP cần thiết.

2. Chuẩn bị môi trường

Kích hoạt Duet AI

Bạn có thể kích hoạt Duet AI trong một dự án trên GCP thông qua API (gcloud hoặc các công cụ IaC như Terraform) hoặc thông qua giao diện người dùng Cloud Console.

Để kích hoạt Duet AI trong một dự án trên Google Cloud, bạn cần bật Cloud AI Companion API và cấp cho người dùng các vai trò Quản lý danh tính và quyền truy cập (IAM) của Người dùng Cloud AI Companion và Người xem mức sử dụng dịch vụ.

Qua gcloud

Kích hoạt Cloud Shell:

Định cấu hình PROJECT_ID, USER và bật Cloud AI Companion API.

export PROJECT_ID=<YOUR PROJECT ID>
export USER=<YOUR USERNAME> # Use your full LDAP, e.g. name@example.com
gcloud config set project ${PROJECT_ID}
gcloud services enable cloudaicompanion.googleapis.com --project ${PROJECT_ID}

Kết quả sẽ như sau:

Updated property [core/project].
Operation "operations/acat.p2-60565640195-f37dc7fe-b093-4451-9b12-934649e2a435" finished successfully.

Cấp vai trò Quản lý danh tính và quyền truy cập (IAM) cho Người dùng Cloud AI Companion và Người xem mức sử dụng dịch vụ cho tài khoản NGƯỜI DÙNG. Cloud Companion API nằm sau các tính năng trong cả IDE và bảng điều khiển mà chúng ta sẽ sử dụng. Quyền xem thông tin sử dụng dịch vụ được dùng để kiểm tra nhanh trước khi bật giao diện người dùng trong bảng điều khiển (để giao diện người dùng Duet chỉ xuất hiện trong những dự án đã bật API).

gcloud projects add-iam-policy-binding  ${PROJECT_ID} \
--member=user:${USER} --role=roles/cloudaicompanion.user

gcloud projects add-iam-policy-binding  ${PROJECT_ID} \
--member=user:${USER} --role=roles/serviceusage.serviceUsageViewer

Kết quả sẽ như sau:

...
- members:
  - user:<YOUR USER ACCOUNT>
  role: roles/cloudaicompanion.user

...
- members:
  - user:<YOUR USER ACCOUNT>
  role: roles/serviceusage.serviceUsageViewer

Thông qua Cloud Console

Để bật API này, hãy chuyển đến trang Cloud AI Companion API trong bảng điều khiển Google Cloud.

Trong bộ chọn dự án, hãy chọn một dự án.

Nhấp vào Bật.

Trang này sẽ cập nhật và cho biết trạng thái Đã bật. Duet AI hiện đã có trong dự án trên đám mây của Google Cloud đã chọn cho tất cả người dùng có vai trò IAM bắt buộc.

Để cấp các vai trò IAM cần thiết để sử dụng Duet AI, hãy chuyển đến trang IAM.

Trong cột Chủ thể, hãy tìm NGƯỜI DÙNG mà bạn muốn cấp quyền truy cập vào Duet AI, sau đó nhấp vào biểu tượng bút chì ✏️ Chỉnh sửa chủ thể trong hàng đó.

Trong bảng Chỉnh sửa quyền truy cập, hãy nhấp vào Thêm vai trò khác.

Trong phần Chọn vai trò, hãy chọn Người dùng Cloud AI Companion.

Nhấp vào Thêm một vai trò khác rồi chọn Người xem mức sử dụng dịch vụ.

Nhấp vào Lưu.

Thiết lập IDE

Nhà phát triển có thể chọn trong số nhiều IDE phù hợp nhất với nhu cầu của họ. Tính năng hỗ trợ lập trình của Duet AI có trong nhiều IDE như Visual Studio Code, IDE của JetBrains (IntelliJ, PyCharm, GoLand, WebStorm và nhiều IDE khác), Cloud Workstations, Cloud Shell Editor.

Trong phòng thí nghiệm này, bạn có thể sử dụng Cloud Workstations hoặc Cloud Shell Editor.

Hội thảo này sử dụng Cloud Shell Editor.

Xin lưu ý rằng Cloud Workstations có thể mất từ 20 đến 30 phút để thiết lập.

Để sử dụng ngay, hãy dùng Cloud Shell Editor.

Mở Cloud Shell Editor bằng cách nhấp vào biểu tượng bút chì ✏️ trong thanh trình đơn trên cùng của Cloud Shell.

Cloud Shell Editor có giao diện người dùng và trải nghiệm người dùng rất giống với VSCode.

d6a6565f83576063.png

Nhấp vào CTRL (trong Windows)/CMD (trong Mac) + , (dấu phẩy) để chuyển đến ngăn Cài đặt.

Trong thanh Tìm kiếm, hãy nhập "duet ai".

Đảm bảo hoặc bật Cloudcode › Duet AI: Enable (Cloudcode › Duet AI: Bật) và Cloudcode › Duet AI › Inline Suggestions: Enable Auto (Cloudcode › Duet AI › Gợi ý nội tuyến: Bật tự động)

111b8d587330ec74.png

Trong Thanh trạng thái ở dưới cùng, hãy nhấp vào Cloud Code – Sign In (Cloud Code – Đăng nhập) rồi làm theo quy trình đăng nhập.

Nếu bạn đã đăng nhập, thanh trạng thái sẽ cho biết Cloud Code – No project (Cloud Code – Không có dự án).

Nhấp vào Cloud Code – No project (Cloud Code – Không có dự án) và một ngăn thả xuống hành động sẽ xuất hiện ở trên cùng. Nhấp vào Chọn một dự án trên đám mây của Google.

3241a59811e3c84a.png

Bắt đầu nhập MÃ DỰ ÁN và dự án của bạn sẽ xuất hiện trong danh sách.

c5358fc837588fe.png

Chọn PROJECT_ID của bạn trong danh sách dự án.

Thanh trạng thái ở dưới cùng sẽ cập nhật để cho biết mã dự án của bạn. Nếu không, bạn có thể cần làm mới thẻ Cloud Shell Editor.

Nhấp vào biểu tượng AI d97fc4e7b594c3af.png trong thanh trình đơn bên trái để mở cửa sổ trò chuyện của Duet AI. Nếu bạn thấy thông báo Chọn dự án GCP. Nhấp và chọn lại dự án.

Lúc này, bạn sẽ thấy cửa sổ trò chuyện của Duet AI

781f888360229ca6.png

3. Thiết lập cơ sở hạ tầng

d3234d237f00fdbb.png

Để chạy dịch vụ vận chuyển mới trong GCP, bạn cần có các tài nguyên GCP sau:

  1. Một phiên bản Cloud SQL có cơ sở dữ liệu.
  2. Một cụm GKE để chạy dịch vụ được chứa trong vùng chứa.
  3. Một Artifact Registry để lưu trữ hình ảnh Docker.
  4. Một Cloud Source Repository cho mã.

Trong cửa sổ dòng lệnh Cloud Shell, hãy sao chép kho lưu trữ sau đây và chạy các lệnh sau để thiết lập cơ sở hạ tầng trong dự án GCP của bạn.

# Set your project
export PROJECT_ID=<INSERT_YOUR_PROJECT_ID>
gcloud config set core/project ${PROJECT_ID}

# Enable Cloudbuild and grant Cloudbuild SA owner role 
export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format 'value(projectNumber)')
gcloud services enable cloudbuild.googleapis.com
gcloud projects add-iam-policy-binding ${PROJECT_ID} --member serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com --role roles/owner

# Clone the repo
git clone https://github.com/duetailabs/dev.git ~/duetaidev
cd ~/duetaidev

# Run Cloudbuild to create the necessary resources
gcloud builds submit --substitutions=_PROJECT_ID=${PROJECT_ID}

# To destroy all GCP resources, run the following
# gcloud builds submit --substitutions=_PROJECT_ID=${PROJECT_ID} --config=cloudbuild_destroy.yaml

4. Phát triển dịch vụ Flask Python

9745ba5c70782e76.png

Dịch vụ mà chúng ta sẽ tạo cuối cùng sẽ bao gồm các tệp sau. Bạn không cần tạo các tệp này ngay bây giờ và sẽ tạo từng tệp theo hướng dẫn bên dưới:

  1. package-service.yaml – Một quy cách API mở cho dịch vụ gói hàng có dữ liệu như chiều cao, chiều rộng, trọng lượng và hướng dẫn xử lý đặc biệt.
  2. data_model.py – Mô hình dữ liệu cho thông số kỹ thuật API dịch vụ gói. Đồng thời, tạo bảng packages trong DB product_details.
  3. connect_connector.py – Kết nối CloudSQL (xác định công cụ, Phiên và ORM cơ sở)
  4. db_init.py – Tạo dữ liệu mẫu trong bảng packages.
  5. main.py – Một dịch vụ Python Flask có điểm cuối GET để truy xuất thông tin chi tiết về gói từ dữ liệu packages dựa trên product_id.
  6. test.py – Kiểm thử đơn vị
  7. requirement.txt – Yêu cầu về Python
  8. Dockerfile – Để đóng gói ứng dụng này vào vùng chứa

Nếu bạn gặp phải vấn đề khó giải quyết trong các bài tập, thì tất cả các tệp cuối cùng đều nằm trong phần PHỤ LỤC của lớp học lập trình này để bạn tham khảo.

Ở bước trước, bạn đã tạo một Kho lưu trữ mã nguồn trên đám mây. Sao chép kho lưu trữ. Bạn sẽ tạo các tệp ứng dụng trong thư mục kho lưu trữ được sao chép.

Trong cửa sổ dòng lệnh Cloud Shell, hãy chạy lệnh sau để sao chép kho lưu trữ.

cd ~
gcloud source repos clone shipping shipping
cd ~/shipping 

Mở thanh bên trò chuyện của Duet AI trong trình đơn bên trái của Cloud Shell Editor. Biểu tượng này trông như 8b135a000b259175.png. Giờ đây, bạn có thể sử dụng Duet AI để được hỗ trợ về mã.

package-service.yaml

Khi không có tệp nào đang mở, hãy yêu cầu Duet tạo một quy cách Open API cho dịch vụ vận chuyển.

Câu lệnh 1: Tạo một quy cách OpenAPI yaml cho một dịch vụ cung cấp thông tin về việc vận chuyển và gói hàng dựa trên mã nhận dạng sản phẩm bằng số. Dịch vụ này phải có thông tin về chiều cao, chiều rộng, độ sâu, trọng lượng của gói hàng và mọi hướng dẫn đặc biệt về cách xử lý.

ba12626f491a1204.png

Có 3 lựa chọn được liệt kê ở trên cùng bên phải của cửa sổ mã được tạo.

Bạn có thể COPY 71194556d8061dae.pngmã rồi DÁN mã đó vào một tệp.

Bạn có thể ADD df645de8c65607a.png mã vào tệp hiện đang mở trong Trình chỉnh sửa.

Hoặc bạn có thể OPEN a4c7ed6d845df343.png mã này trong một tệp mới.

Nhấp vào OPEN a4c7ed6d845df343.png mã trong một tệp mới.

Nhấp vào CTRL/CMD + s để lưu tệp và lưu trữ tệp trong thư mục ứng dụng có tên tệp là package-service.yaml. Nhấp vào OK.

f6ebd5b836949366.png

Tệp cuối cùng nằm trong phần PHỤ LỤC của lớp học lập trình này. Nếu không, hãy tự thực hiện các thay đổi thích hợp.

Bạn cũng có thể thử nhiều câu lệnh để xem câu trả lời của Duet AI.

Xoá nhật ký trò chuyện của Duet AI bằng cách nhấp vào biểu tượng thùng rác f574ca2c1e114856.png ở đầu thanh bên của Duet AI.

data_model.py

Tiếp theo, bạn sẽ tạo tệp python mô hình dữ liệu cho dịch vụ dựa trên thông số kỹ thuật OpenAPI.

Khi mở tệp package-service.yaml, hãy nhập câu lệnh sau.

Câu lệnh 1: Sử dụng ORM sqlalchemy của python, hãy tạo một mô hình dữ liệu cho dịch vụ API này. Ngoài ra, hãy thêm một hàm riêng biệt và một điểm truy cập chính để tạo các bảng cơ sở dữ liệu.

b873a6a28bd28ca1.png

Hãy xem từng phần được tạo. Duet AI vẫn là một trợ lý và mặc dù có thể giúp bạn viết mã nhanh chóng, nhưng bạn vẫn nên xem xét và hiểu rõ nội dung được tạo trong quá trình viết mã.

Trước tiên, có một Lớp có tên là Package thuộc loại Base xác định mô hình dữ liệu cho cơ sở dữ liệu packages như sau:

class Package(Base):
    __tablename__ = 'packages'

    id = Column(Integer, primary_key=True)
    product_id = Column(String(255))
    height = Column(Float)
    width = Column(Float)
    depth = Column(Float)
    weight = Column(Float)
    special_handling_instructions = Column(String(255))

Tiếp theo, bạn cần một hàm tạo bảng trong cơ sở dữ liệu như sau:

def create_tables(engine):
    Base.metadata.create_all(engine)

Cuối cùng, bạn cần một hàm chính chạy hàm create_tables để thực sự tạo bảng trong cơ sở dữ liệu CloudSQL, chẳng hạn như sau:

if __name__ == '__main__':
    from sqlalchemy import create_engine

    engine = create_engine('sqlite:///shipping.db')
    create_tables(engine)

    print('Tables created successfully.')

Lưu ý rằng hàm main đang tạo một công cụ bằng cách sử dụng cơ sở dữ liệu sqlite cục bộ. Để sử dụng CloudSQL, bạn cần thay đổi giá trị này. Bạn sẽ làm việc đó sau.

Sử dụng OPEN a4c7ed6d845df343.png mã trong quy trình tạo tệp mới như trước. Lưu mã trong một tệp có tên là data_model.py (lưu ý dấu gạch dưới trong tên chứ không phải dấu gạch ngang).

Xoá nhật ký trò chuyện của Duet AI bằng cách nhấp vào biểu tượng thùng rác f574ca2c1e114856.png ở đầu thanh bên của Duet AI.

connect-connector.py

Tạo trình kết nối CloudSQL.

Khi mở tệp data_model.py, hãy nhập các câu lệnh sau.

Câu lệnh 1: Sử dụng thư viện cloud-sql-python-connector, tạo một hàm khởi tạo một nhóm kết nối cho một phiên bản Cloud SQL của Postgres.

ed05cb6ff85d34c5.png

Xin lưu ý rằng phản hồi này không sử dụng thư viện cloud-sql-python-connector. Bạn có thể tinh chỉnh câu lệnh để hướng dẫn Duet bằng cách thêm thông tin cụ thể vào cùng một chuỗi trò chuyện.

Hãy dùng một câu lệnh khác.

Lời nhắc 2: Phải sử dụng thư viện cloud-sql-python-connector.

d09095b44dde35bf.png

Đảm bảo rằng ứng dụng sử dụng thư viện cloud-sql-python-connector.

Sử dụng OPEN a4c7ed6d845df343.png mã trong quy trình tạo tệp mới như trước. Lưu mã trong một tệp có tên là connect_conector.py. Bạn có thể cần nhập thư viện pg8000 theo cách thủ công, vui lòng xem tệp bên dưới.

Xoá nhật ký trò chuyện của Duet AI và khi mở tệp connect_connector.py, hãy tạo ORM DB engine, sessionmakerbase để dùng trong ứng dụng.

Câu lệnh 1: Tạo một công cụ, lớp sessionmaker và Base ORM bằng phương thức connect_with_connector

6e4214b72ab13a63.png

Phản hồi có thể nối engine, SessionBase vào tệp connect_connector.py.

Tệp cuối cùng nằm trong phần PHỤ LỤC của lớp học lập trình này. Nếu không, hãy tự thực hiện các thay đổi thích hợp.

Bạn cũng có thể thử nhiều câu lệnh để xem các biến thể tiềm năng của câu trả lời từ Duet AI.

Xoá nhật ký trò chuyện của Duet AI bằng cách nhấp vào biểu tượng thùng rác f574ca2c1e114856.png ở đầu thanh bên của Duet AI.

Cập nhật data_model.py

Bạn cần sử dụng công cụ mà bạn đã tạo ở bước trước (trong tệp connect_connector.py) để tạo một bảng trong cơ sở dữ liệu CloudSQL.

Xoá nhật ký trò chuyện của Duet AI. Mở tệp data_model.py. Hãy thử câu lệnh sau.

Câu lệnh 1: Trong hàm chính, hãy nhập và sử dụng công cụ từ connect_connector.py

2e768c9b6c523b9a.png

Bạn sẽ thấy phản hồi nhập engine từ connect_connector (đối với CloudSQL). create_table sử dụng công cụ đó (thay vì DB cục bộ sqlite mặc định).

Cập nhật tệp data_model.py.

Tệp cuối cùng nằm trong phần PHỤ LỤC của lớp học lập trình này. Nếu không, hãy tự thực hiện các thay đổi thích hợp.

Bạn cũng có thể thử nhiều câu lệnh để xem các câu trả lời của Duet AI.

Xoá nhật ký trò chuyện của Duet AI bằng cách nhấp vào biểu tượng thùng rác f574ca2c1e114856.png ở đầu thanh bên của Duet AI.

requirements.txt

Tạo tệp requirements.txt cho ứng dụng.

Mở cả connect_connector.py và tệp data_model.py rồi nhập câu lệnh sau.

Câu lệnh 1: Tạo tệp yêu cầu pip cho mô hình dữ liệu và dịch vụ này

Câu lệnh 2: Tạo tệp yêu cầu pip cho mô hình dữ liệu và dịch vụ này bằng các phiên bản mới nhất

69fae373bc5c6a18.png

Xác minh rằng tên và phiên bản là chính xác. Ví dụ: trong phản hồi ở trên, cả tên và phiên bản google-cloud-sql-connecter đều không chính xác. Khắc phục các phiên bản theo cách thủ công và tạo một tệp requirements.txt có dạng như sau:

cloud-sql-python-connector==1.2.4
sqlalchemy==1.4.36
pg8000==1.22.0

Trong cửa sổ dòng lệnh, hãy chạy lệnh sau:

pip3 install -r requirements.txt

Xoá nhật ký trò chuyện của Duet AI bằng cách nhấp vào biểu tượng thùng rác f574ca2c1e114856.png ở đầu thanh bên của Duet AI.

Tạo bảng gói trong CloudSQL

Đặt các biến môi trường cho trình kết nối cơ sở dữ liệu CloudSQL.

export INSTANCE_NAME=$(gcloud sql instances list --format='value(name)')
export INSTANCE_CONNECTION_NAME=$(gcloud sql instances describe ${INSTANCE_NAME} --format="value(connectionName)")
export DB_USER=evolution
export DB_PASS=evolution
export DB_NAME=product_details

Bây giờ, hãy chạy data_model.py.

python data_model.py

Kết quả sẽ tương tự như sau (hãy kiểm tra mã để xem kết quả thực tế):

Tables created successfully.

Kết nối với phiên bản CloudSQL và kiểm tra xem cơ sở dữ liệu đã được tạo hay chưa.

gcloud sql connect ${INSTANCE_NAME} --user=evolution --database=product_details

Sau khi nhập mật khẩu (cũng là evolution), hãy lấy các bảng.

product_details=> \dt

Kết quả sẽ tương tự như sau:

           List of relations
 Schema |   Name   | Type  |   Owner   
--------+----------+-------+-----------
 public | packages | table | evolution
(1 row)

Bạn cũng có thể kiểm tra mô hình dữ liệu và thông tin chi tiết về bảng.

product_details=> \d+ packages

Kết quả sẽ tương tự như sau:

                                                                        Table "public.packages"
            Column             |       Type        | Collation | Nullable |               Default                | Storage  | Compression | Stats target | Description 
-------------------------------+-------------------+-----------+----------+--------------------------------------+----------+-------------+--------------+-------------
 id                            | integer           |           | not null | nextval('packages_id_seq'::regclass) | plain    |             |              | 
 product_id                    | integer           |           | not null |                                      | plain    |             |              | 
 height                        | double precision  |           | not null |                                      | plain    |             |              | 
 width                         | double precision  |           | not null |                                      | plain    |             |              | 
 depth                         | double precision  |           | not null |                                      | plain    |             |              | 
 weight                        | double precision  |           | not null |                                      | plain    |             |              | 
 special_handling_instructions | character varying |           |          |                                      | extended |             |              | 
Indexes:
    "packages_pkey" PRIMARY KEY, btree (id)
Access method: heap

Nhập \q để thoát CloudSQL.

db_init.py

Tiếp theo, hãy thêm một số dữ liệu mẫu vào bảng packages.

Xoá nhật ký trò chuyện của Duet AI. Khi mở tệp data_model.py, hãy thử các câu lệnh sau.

Câu lệnh 1: Tạo một hàm tạo 10 hàng gói mẫu và xác nhận các hàng đó vào bảng gói

Câu lệnh 2: Sử dụng phiên từ connect_connector, tạo một hàm tạo 10 hàng gói mẫu và xác nhận các hàng đó vào bảng packages

34a9afc5f04ba5.png

Sử dụng OPEN a4c7ed6d845df343.png mã trong quy trình tạo tệp mới như trước. Lưu mã trong một tệp có tên là db_init.py.

Tệp cuối cùng nằm trong phần PHỤ LỤC của lớp học lập trình này. Nếu không, hãy tự thực hiện các thay đổi thích hợp.

Bạn cũng có thể thử nhiều câu lệnh để xem các câu trả lời của Duet AI.

Xoá nhật ký trò chuyện của Duet AI bằng cách nhấp vào biểu tượng thùng rác f574ca2c1e114856.png ở đầu thanh bên của Duet AI.

Tạo dữ liệu mẫu về gói

Chạy db_init.py từ dòng lệnh.

python db_init.py

Kết quả sẽ tương tự như sau:

Packages created successfully.

Kết nối lại với phiên bản CloudSQL và xác minh rằng dữ liệu mẫu đã được thêm vào bảng gói.

Kết nối với phiên bản CloudSQL và kiểm tra xem cơ sở dữ liệu đã được tạo hay chưa.

gcloud sql connect ${INSTANCE_NAME} --user=evolution --database=product_details

Sau khi nhập mật khẩu (cũng là evolution), hãy lấy tất cả dữ liệu từ bảng packages.

product_details=> SELECT * FROM packages;

Kết quả sẽ tương tự như sau:

 id | product_id | height | width | depth | weight |   special_handling_instructions   
----+------------+--------+-------+-------+--------+-----------------------------------
  1 |          0 |     10 |    10 |    10 |     10 | No special handling instructions.
  2 |          1 |     10 |    10 |    10 |     10 | No special handling instructions.
  3 |          2 |     10 |    10 |    10 |     10 | No special handling instructions.
  4 |          3 |     10 |    10 |    10 |     10 | No special handling instructions.
  5 |          4 |     10 |    10 |    10 |     10 | No special handling instructions.
  6 |          5 |     10 |    10 |    10 |     10 | No special handling instructions.
  7 |          6 |     10 |    10 |    10 |     10 | No special handling instructions.
  8 |          7 |     10 |    10 |    10 |     10 | No special handling instructions.
  9 |          8 |     10 |    10 |    10 |     10 | No special handling instructions.
 10 |          9 |     10 |    10 |    10 |     10 | No special handling instructions.
(10 rows)

Nhập \q để thoát CloudSQL.

main.py

Khi mở các tệp data_model.py, package-service.yamlconnect_connector.py, hãy tạo một main.py cho ứng dụng.

Câu lệnh 1: Sử dụng thư viện python flask – tạo một phương thức triển khai sử dụng các điểm cuối http rest cho dịch vụ này

Câu lệnh 2: Sử dụng thư viện python flask – tạo một quy trình triển khai sử dụng các điểm cuối http rest cho dịch vụ này. nhập và sử dụng SessionMaker từ connect_conector.py để lấy dữ liệu gói.

Câu lệnh 3: Sử dụng thư viện python flask – tạo một phương thức triển khai sử dụng các điểm cuối http rest cho dịch vụ này. Nhập và sử dụng Gói từ data_model.py và SessionMaker từ connect_conector.py cho dữ liệu gói.

Câu lệnh 4: Sử dụng thư viện python flask – tạo một phương thức triển khai sử dụng các điểm cuối http rest cho dịch vụ này. nhập và sử dụng Gói từ data_model.py và SessionMaker từ connect_conector.py cho dữ liệu gói. Sử dụng IP máy chủ lưu trữ 0.0.0.0 cho app.run

6d794fc52a90e6ae.png

Cập nhật các yêu cầu đối với main.py.

Câu lệnh: Tạo tệp requirements cho main.py

1cc0b318d2d4ca2f.png

Thêm nội dung này vào tệp requirements.txt. Đảm bảo bạn sử dụng Flask phiên bản 3.0.0.

Sử dụng OPEN a4c7ed6d845df343.png mã trong quy trình tạo tệp mới như trước. Lưu mã trong một tệp có tên là main.py.

Tệp cuối cùng nằm trong phần PHỤ LỤC của lớp học lập trình này. Nếu không, hãy tự thực hiện các thay đổi thích hợp.

Xoá nhật ký trò chuyện của Duet AI bằng cách nhấp vào biểu tượng thùng rác f574ca2c1e114856.png ở đầu thanh bên của Duet AI.

5. Kiểm thử và chạy ứng dụng

Cài đặt các yêu cầu.

pip3 install -r requirements.txt

Chạy main.py.

python main.py

Kết quả sẽ tương tự như sau:

 * Serving Flask app 'main'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:5000
 * Running on http://10.88.0.3:5000
Press CTRL+C to quit

Từ thiết bị đầu cuối thứ hai, hãy kiểm thử điểm cuối /packages/<product_id>.

curl localhost:5000/packages/1

Kết quả sẽ tương tự như sau:

{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}

Bạn cũng có thể kiểm thử mọi mã sản phẩm khác trong dữ liệu mẫu.

Nhập CTRL_C để thoát khỏi vùng chứa docker đang chạy trong thiết bị đầu cuối.

Tạo các kiểm thử đơn vị

Khi mở tệp main.py, hãy tạo các kiểm thử đơn vị.

Câu lệnh 1: Tạo các kiểm thử đơn vị.

e861e5b63e1b2657.png

Sử dụng OPEN a4c7ed6d845df343.png mã trong quy trình tạo tệp mới như trước. Lưu mã trong một tệp có tên là test.py.

Trong hàm test_get_package, bạn phải xác định một product_id. Bạn có thể thêm thẻ này theo cách thủ công.

Tệp cuối cùng nằm trong phần PHỤ LỤC của lớp học lập trình này. Nếu không, hãy tự thực hiện các thay đổi thích hợp.

Xoá nhật ký trò chuyện của Duet AI bằng cách nhấp vào biểu tượng thùng rác f574ca2c1e114856.png ở đầu thanh bên của Duet AI.

Chạy kiểm thử đơn vị

Chạy kiểm thử đơn vị.

python test.py

Kết quả sẽ tương tự như sau:

.
----------------------------------------------------------------------
Ran 1 test in 1.061s

OK

Đóng tất cả các tệp trong Cloud Shell Editor và xoá nhật ký trò chuyện bằng cách nhấp vào biểu tượng thùng rác 1ecccfe10d6c540.png trong thanh trạng thái trên cùng.

tệp Docker

Tạo một Dockerfile cho ứng dụng này.

Mở main.py và thử các câu lệnh sau.

Câu lệnh 1: Tạo một Dockerfile cho ứng dụng này.

Câu lệnh 2: Tạo một Dockerfile cho ứng dụng này. Sao chép tất cả các tệp vào vùng chứa.

9c473caea437a5c3.png

Bạn cũng cần đặt ENVARS cho INSTANCE_CONNECTION_NAME, DB_USER, DB_PASSDB_NAME. Bạn có thể làm việc đó theo cách thủ công. Dockerfile của bạn sẽ có dạng như sau:

FROM python:3.10-slim

WORKDIR /app

COPY . ./

RUN pip install -r requirements.txt

# Add these manually for your project
ENV INSTANCE_CONNECTION_NAME=YOUR_INSTANCE_CONNECTION_NAME
ENV DB_USER=evolution
ENV DB_PASS=evolution
ENV DB_NAME=product_details

CMD ["python", "main.py"]

Sử dụng OPEN a4c7ed6d845df343.png mã trong quy trình tạo tệp mới như trước. Lưu mã trong một tệp có tên là Dockerfile.

Tệp cuối cùng nằm trong phần PHỤ LỤC của lớp học lập trình này. Nếu không, hãy tự thực hiện các thay đổi thích hợp.

Chạy ứng dụng cục bộ

Khi Dockerfile mở, hãy thử câu lệnh sau.

Câu lệnh 1: Làm cách nào để chạy một vùng chứa cục bộ bằng Dockerfile này

570fd5c296ca8c83.png

Làm theo hướng dẫn.

# Build
docker build -t shipping .
# And run
docker run -p 5000:5000 -it shipping

Kết quả sẽ tương tự như sau:

 * Serving Flask app 'main'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:5000
 * Running on http://172.17.0.2:5000
Press CTRL+C to quit

Từ cửa sổ dòng lệnh thứ hai, hãy truy cập vào vùng chứa.

curl localhost:5000/packages/1

Kết quả sẽ tương tự như sau:

{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}

Ứng dụng trong vùng chứa đang hoạt động.

Nhập CTRL_C để thoát khỏi vùng chứa docker đang chạy trong thiết bị đầu cuối.

Tạo hình ảnh vùng chứa trong Artifact Registry

Tạo hình ảnh vùng chứa và đẩy vào Artifact Registry.

cd ~/shipping
gcloud auth configure-docker us-central1-docker.pkg.dev
docker build -t us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping .
docker push us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping

Giờ đây, vùng chứa ứng dụng nằm tại us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping và có thể được triển khai đến GKE.

6. Triển khai ứng dụng vào cụm GKE

Một cụm GKE Autopilot đã được tạo khi bạn tạo các tài nguyên GCP cho hội thảo này. Kết nối với cụm GKE.

gcloud container clusters get-credentials gke1 \
    --region=us-central1

Chú thích tài khoản dịch vụ mặc định của Kubernetes bằng tài khoản dịch vụ của Google.

kubectl annotate serviceaccount default iam.gke.io/gcp-service-account=cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com

Kết quả sẽ tương tự như sau:

serviceaccount/default annotated

Chuẩn bị và áp dụng tệp k8s.yaml.

cp ~/duetaidev/k8s.yaml_tmpl ~/shipping/.
export INSTANCE_NAME=$(gcloud sql instances list --format='value(name)')
export INSTANCE_CONNECTION_NAME=$(gcloud sql instances describe ${INSTANCE_NAME} --format="value(connectionName)")
export IMAGE_REPO=us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping
envsubst < ~/shipping/k8s.yaml_tmpl > k8s.yaml
kubectl apply -f k8s.yaml

Kết quả sẽ tương tự như sau:

deployment.apps/shipping created
service/shipping created

Chờ cho đến khi các Pod đang chạy và Dịch vụ đã được chỉ định địa chỉ IP của trình cân bằng tải bên ngoài.

kubectl get pods
kubectl get service shipping

Kết quả sẽ tương tự như sau:

# kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
shipping-f5d6f8d5-56cvk   1/1     Running   0          4m47s
shipping-f5d6f8d5-cj4vv   1/1     Running   0          4m48s
shipping-f5d6f8d5-rrdj2   1/1     Running   0          4m47s

# kubectl get service shipping
NAME       TYPE           CLUSTER-IP       EXTERNAL-IP    PORT(S)        AGE
shipping   LoadBalancer   34.118.225.125   34.16.39.182   80:30076/TCP   5m41s

Đối với các cụm GKE Autopilot, hãy đợi vài phút cho đến khi các tài nguyên sẵn sàng.

Truy cập dịch vụ thông qua địa chỉ EXTERNAL-IP.

export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1

Kết quả sẽ tương tự như sau:

{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}

7. Tín chỉ bổ sung: Khắc phục sự cố cho ứng dụng

Xoá vai trò IAM của CloudSQL Client khỏi tài khoản dịch vụ cloudsqlsa. Điều này gây ra lỗi khi kết nối với cơ sở dữ liệu CloudSQL.

gcloud projects remove-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role="roles/cloudsql.client"

Khởi động lại Pod vận chuyển.

kubectl rollout restart deployment shipping

Sau khi Pod khởi động lại, hãy thử truy cập lại dịch vụ shipping.

export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1 

Kết quả sẽ tương tự như sau:

...
<title>500 Internal Server Error</title>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>

Kiểm tra nhật ký bằng cách chuyển đến phần Kubernetes Engine > Workloads (Kubernetes Engine > Tải công việc)

d225b1916c829167.png

Nhấp vào chế độ triển khai shipping rồi nhấp vào thẻ Nhật ký.

1d0459141483d6a7.png

Nhấp vào biểu tượng Xem trong Trình khám phá nhật ký df8b9d19a9fe4c73.png ở bên phải thanh trạng thái. Thao tác này sẽ mở một cửa sổ Log Explorer (Trình khám phá nhật ký) mới.

e86d1c265e176bc4.png

Nhấp vào một trong các mục lỗi Traceback, rồi nhấp vào Giải thích mục nhật ký này.

d6af045cf03008bc.png

Bạn có thể đọc phần giải thích về lỗi này.

Tiếp theo, hãy để Duet AI giúp bạn khắc phục lỗi.

Hãy thử câu lệnh sau.

Câu lệnh 1: Giúp tôi khắc phục lỗi này

9288dd6045369167.png

Nhập thông báo lỗi vào câu lệnh.

Lời nhắc 2: Bị cấm: Có vẻ như đối tượng chính IAM đã xác thực không được phép đưa ra yêu cầu API. Xác minh rằng "API Quản trị của Cloud SQL" đã được bật trong dự án GCP của bạn và vai trò "Cloud SQL Client" đã được cấp cho IAM principal

f1e64fbdc435d31c.png

Và sau đó.

Câu hỏi 3: Làm cách nào để chỉ định vai trò ứng dụng Cloud SQL cho một tài khoản dịch vụ của Google bằng gcloud?

bb8926b995a8875c.png

Chỉ định vai trò Ứng dụng Cloud SQL cho cloudsqlsa.

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role="roles/cloudsql.client"

Vui lòng đợi một lát rồi thử truy cập lại ứng dụng.

export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1

Kết quả sẽ tương tự như sau:

{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}

Bạn đã sử dụng thành công Duet AI trong Cloud Logging, Log Explorer và tính năng Log Explainer để khắc phục vấn đề.

8. Kết luận

Xin chúc mừng! Bạn đã hoàn tất thành công lớp học lập trình này.

Trong lớp học lập trình này, bạn đã tìm hiểu những nội dung sau:

  1. Kích hoạt Duet AI trong dự án GCP của bạn và định cấu hình để sử dụng trong một IDE và Cloud Console.
  2. Sử dụng Duet AI để tạo, hoàn thành và giải thích mã.
  3. Sử dụng Duet AI để giải thích và khắc phục vấn đề về ứng dụng.
  4. Các tính năng của Duet AI như trò chuyện trên IDE và trò chuyện nhiều lượt, so sánh tính năng trò chuyện với tính năng tạo mã nội tuyến, các thao tác thông minh như giải thích mã và xác nhận đọc thuộc lòng, v.v.

9. Phụ lục

package-service.yaml

swagger: "2.0"
info:
 title: Shipping and Package Information API
 description: This API provides information about shipping and packages.
 version: 1.0.0
host: shipping.googleapis.com
schemes:
 - https
produces:
 - application/json
paths:
 /packages/{product_id}:
   get:
     summary: Get information about a package
     description: This method returns information about a package, including its height, width, depth, weight, and any special handling instructions.
     parameters:
       - name: product_id
         in: path
         required: true
         type: integer
         format: int64
     responses:
       "200":
         description: A successful response
         schema:
           type: object
           properties:
             height:
               type: integer
               format: int64
             width:
               type: integer
               format: int64
             depth:
               type: integer
               format: int64
             weight:
               type: integer
               format: int64
             special_handling_instructions:
               type: string
       "404":
         description: The product_id was not found

data_model.py

from sqlalchemy import Column, Integer, String, Float
from sqlalchemy.ext.declarative import declarative_base

from connect_connector import engine

Base = declarative_base()

class Package(Base):
    __tablename__ = 'packages'

    id = Column(Integer, primary_key=True)
    product_id = Column(Integer, nullable=False)
    height = Column(Float, nullable=False)
    width = Column(Float, nullable=False)
    depth = Column(Float, nullable=False)
    weight = Column(Float, nullable=False)
    special_handling_instructions = Column(String, nullable=True)

def create_tables():
    Base.metadata.create_all(engine)

if __name__ == '__main__':
    create_tables()

    print('Tables created successfully.')

connect_connector.py

import os

from google.cloud.sql.connector import Connector, IPTypes
import sqlalchemy

# You may need to manually import pg8000 and Base as follows
import pg8000
from sqlalchemy.ext.declarative import declarative_base


def connect_with_connector() -> sqlalchemy.engine.base.Engine:
   """Initializes a connection pool for a Cloud SQL instance of Postgres."""
   # Note: Saving credentials in environment variables is convenient, but not
   # secure - consider a more secure solution such as
   # Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
   # keep secrets safe.
   instance_connection_name = os.environ[
       "INSTANCE_CONNECTION_NAME"
   ]  # e.g. 'project:region:instance'
   db_user = os.environ["DB_USER"]  # e.g. 'my-database-user'
   db_pass = os.environ["DB_PASS"]  # e.g. 'my-database-password'
   db_name = os.environ["DB_NAME"]  # e.g. 'my-database'

   ip_type = IPTypes.PRIVATE if os.environ.get("PRIVATE_IP") else IPTypes.PUBLIC

   connector = Connector()

   def getconn() -> sqlalchemy.engine.base.Engine:
       conn: sqlalchemy.engine.base.Engine = connector.connect(
           instance_connection_name,
           "pg8000",
           user=db_user,
           password=db_pass,
           db=db_name,
           ip_type=ip_type,
       )
       return conn

   pool = sqlalchemy.create_engine(
       "postgresql+pg8000://",
       creator=getconn,
       # ...
   )
   return pool

# Create a connection pool
engine = connect_with_connector()

# Create a sessionmaker class to create new sessions
SessionMaker = sqlalchemy.orm.sessionmaker(bind=engine)

# Create a Base class for ORM
# You may need to manually fix the following
Base = declarative_base()

db_init.py

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from connect_connector import engine

from data_model import Package

def create_packages():
    # Create a session
    session = sessionmaker(bind=engine)()

    # Create 10 sample packages
    for i in range(10):
        package = Package(
            product_id=i,
            height=10.0,
            width=10.0,
            depth=10.0,
            weight=10.0,
            special_handling_instructions="No special handling instructions."
        )

        # Add the package to the session
        session.add(package)

    # Commit the changes
    session.commit()

if __name__ == '__main__':
    create_packages()

    print('Packages created successfully.')

main.py

from flask import Flask, request, jsonify

from data_model import Package
from connect_connector import SessionMaker

app = Flask(__name__)

session_maker = SessionMaker()

@app.route("/packages/<int:product_id>", methods=["GET"])
def get_package(product_id):
  """Get information about a package."""

  session = session_maker

  package = session.query(Package).filter(Package.product_id == product_id).first()

  if package is None:
    return jsonify({"message": "Package not found."}), 404

  return jsonify(
      {
          "height": package.height,
          "width": package.width,
          "depth": package.depth,
          "weight": package.weight,
          "special_handling_instructions": package.special_handling_instructions,
      }
  ), 200

if __name__ == "__main__":
  app.run(host="0.0.0.0")

test.py

import unittest

from data_model import Package
from connect_connector import SessionMaker

from main import app

class TestPackage(unittest.TestCase):

    def setUp(self):
        self.session_maker = SessionMaker()

    def tearDown(self):
        self.session_maker.close()

    def test_get_package(self):
        """Test the `get_package()` function."""

        package = Package(
        product_id=11, # Ensure that the product_id different from the sample data
        height=10,
        width=10,
        depth=10,
        weight=10,
        special_handling_instructions="Fragile",
        )

        session = self.session_maker

        session.add(package)
        session.commit()

        response = app.test_client().get("/packages/11")

        self.assertEqual(response.status_code, 200)

        self.assertEqual(
            response.json,
            {
                "height": 10,
                "width": 10,
                "depth": 10,
                "weight": 10,
                "special_handling_instructions": "Fragile",
            },
        )

if __name__ == "__main__":
    unittest.main()

requirements.txt

cloud-sql-python-connector==1.2.4
sqlalchemy==1.4.36
pg8000==1.22.0
Flask==3.0.0
gunicorn==20.1.0
psycopg2-binary==2.9.3

tệp Docker

FROM python:3.10-slim

WORKDIR /app

COPY . ./

RUN pip install -r requirements.txt

# Add these manually for your project
ENV INSTANCE_CONNECTION_NAME=YOUR_INSTANCE_CONNECTION_NAME
ENV DB_USER=evolution
ENV DB_PASS=evolution
ENV DB_NAME=product_details

CMD ["python", "main.py"]