Codelab Workshop Interaktif Duet AI untuk Developer

1. Tujuan

Tujuan workshop ini adalah memberikan edukasi interaktif tentang Duet AI kepada pengguna dan praktisi.

Dalam codelab ini, Anda akan mempelajari hal berikut:

  1. Aktifkan Duet AI di project GCP Anda dan konfigurasikan untuk digunakan di IDE dan Konsol Cloud.
  2. Gunakan Gemini untuk pembuatan, penyelesaian, dan penjelasan kode.
  3. Menggunakan Gemini untuk menjelaskan dan memecahkan masalah aplikasi.
  4. Fitur Duet AI seperti chat IDE dan chat multi-giliran, chat vs pembuatan kode inline, tindakan cerdas seperti penjelasan kode dan pengakuan pembacaan, dan banyak lagi.

Naratif

Untuk menunjukkan bagaimana Duet AI untuk Developer digunakan secara autentik dalam pengembangan sehari-hari, aktivitas workshop ini berlangsung dalam konteks naratif.

Developer baru bergabung dengan perusahaan e-commerce. Mereka ditugaskan untuk menambahkan layanan baru ke aplikasi e-commerce yang ada (yang terdiri dari beberapa layanan). Layanan baru memberikan informasi tambahan (dimensi, berat, dll.) tentang produk dalam katalog produk. Layanan ini akan memungkinkan biaya pengiriman yang lebih baik/lebih murah berdasarkan dimensi dan berat produk.

Karena developer baru bergabung di perusahaan ini, mereka akan menggunakan Duet AI untuk pembuatan, penjelasan, dan dokumentasi Kode.

Setelah layanan dikodekan, administrator platform akan menggunakan Duet AI (chat) untuk membantu membuat artefak (container docker), dan resource yang diperlukan untuk men-deploy artefak ke GCP (misalnya Artifact Registry, izin IAM, repositori kode, infrastruktur komputasi, misalnya GKE atau CloudRun, dll.)

Setelah aplikasi di-deploy ke GCP, Operator aplikasi/SRE akan menggunakan Duet AI (dan Cloud Ops) untuk membantu memecahkan masalah error di layanan baru.

Persona

Workshop ini akan membahas persona berikut:

  1. Developer Aplikasi - Diperlukan pengetahuan tentang pemrograman dan pengembangan software.

Variasi workshop Duet AI ini ditujukan khusus untuk developer. Tidak diperlukan pengetahuan tentang resource cloud GCP. Skrip tentang cara membangun resource GCP yang diperlukan untuk menjalankan aplikasi ini dapat ditemukan di sini. Anda dapat mengikuti petunjuk dalam panduan ini untuk men-deploy resource GCP yang diperlukan.

2. Mempersiapkan lingkungan

Mengaktifkan Duet AI

Anda dapat mengaktifkan Duet AI di project GCP melalui API (gcloud atau alat IaC seperti Terraform) atau melalui UI Cloud Console.

Untuk mengaktifkan Duet AI di project Google Cloud, Anda mengaktifkan Cloud AI Companion API dan memberikan peran Cloud AI Companion User dan Service Usage Viewer Identity and Access Management (IAM) kepada pengguna.

Melalui gcloud

Aktifkan Cloud Shell:

Konfigurasikan PROJECT_ID, USER, dan aktifkan 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}

Output-nya seperti berikut:

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

Berikan peran Cloud AI Companion User dan Service Usage Viewer Identity and Access Management (IAM) ke akun USER. Cloud Companion API berada di belakang fitur dalam IDE dan konsol yang akan kita gunakan. Izin Usage Usage Viewer layanan digunakan sebagai pemeriksaan cepat sebelum mengaktifkan UI di konsol (sehingga UI Duet hanya muncul dalam project tempat API diaktifkan).

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

Output-nya seperti berikut:

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

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

Melalui Cloud Console

Untuk mengaktifkan API, buka halaman Cloud AI Companion API di Konsol Google Cloud.

Di pemilih project, pilih project.

Klik Aktifkan.

Halaman akan diperbarui dan menampilkan status Diaktifkan. Duet AI kini tersedia di project Google Cloud yang dipilih untuk semua pengguna yang memiliki peran IAM yang diperlukan.

Untuk memberikan peran IAM yang diperlukan untuk menggunakan Duet AI, buka halaman IAM.

Di kolom Principal, cari PENGGUNA yang ingin Anda aktifkan aksesnya ke Duet AI, lalu klik ikon pensil ✏️ Edit akun utama di baris tersebut.

Di panel akses Edit, klik tambahkan Add another role.

Di bagian Select a role, pilih Cloud AI Companion User.

Klik Add another role dan pilih Service Usage Viewer.

Klik Simpan.

Menyiapkan IDE

Developer dapat memilih dari berbagai IDE yang paling sesuai dengan kebutuhan mereka. Bantuan kode Duet AI tersedia di beberapa IDE seperti Visual Studio Code, JetBrains IDEs (IntelliJ, PyCharm, GoLand, WebStorm, dan lainnya), Cloud Workstations, Cloud Shell Editor.

Di lab ini, Anda dapat menggunakan Cloud Workstations atau Cloud Shell Editor.

Workshop ini menggunakan Cloud Shell Editor.

Perhatikan bahwa penyiapan Cloud Workstation dapat memerlukan waktu 20-30 menit.

Untuk langsung menggunakannya, gunakan Cloud Shell Editor.

Buka Cloud Shell Editor dengan mengklik ikon pensil ✏️ di panel menu atas Cloud Shell.

Cloud Shell Editor memiliki UI dan UX yang sangat mirip dengan VSCode.

d6a6565f83576063.png

Klik CTRL (di Windows)/CMD (di Mac) + , (comma) untuk masuk ke panel Settings.

Di Kotak penelusuran, ketik "duet ai".

Pastikan atau aktifkan Cloudcode › Duet AI: Enable dan Cloudcode › Duet AI › Inline Suggestions: Enable Auto

111b8d587330ec74.pngS

Di Status Bar bawah, klik Cloud Code - Sign In, lalu ikuti alur kerja login.

Jika Anda sudah login, status bar akan menampilkan Cloud Code - Tidak ada project.

Klik Cloud Code - No project dan panel dropdown tindakan akan muncul di bagian atas. Klik Select a Google Cloud project.

3241a59811e3c84a.pngS

Mulailah mengetik PROJECT ID dan project Anda akan muncul dalam daftar.

c5358fc837588fe.png

Pilih PROJECT_ID dari daftar project.

Status bar bawah akan diperbarui untuk menampilkan project ID Anda. Jika tidak, Anda mungkin perlu me-refresh tab Cloud Shell Editor.

Klik ikon Duet AI d97fc4e7b594c3af.png di panel menu sebelah kiri dan jendela chat Duet AI akan muncul. Jika Anda mendapatkan pesan yang bertuliskan Select GCP Project. Klik dan pilih ulang project.

Anda sekarang melihat jendela chat Duet AI

781f888360229ca6.pngS

3. Menyiapkan infrastruktur

d3234d237f00fdbb.png

Untuk menjalankan layanan pengiriman baru di GCP, Anda memerlukan resource GCP berikut:

  1. Instance Cloud SQL, dengan database.
  2. Cluster GKE untuk menjalankan layanan dalam container.
  3. Artifact Registry untuk menyimpan image Docker.
  4. Cloud Source Repository untuk kode.

Di terminal Cloud Shell, clone repo berikut dan jalankan perintah berikut untuk menyiapkan infrastruktur di project GCP Anda.

# 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. Mengembangkan layanan python Flask

9745ba5c70782e76.pngS

Layanan yang akan kita buat pada akhirnya terdiri dari file-file berikut. Anda tidak perlu membuat file ini sekarang dan akan membuat file ini satu per satu dengan mengikuti petunjuk di bawah:

  1. package-service.yaml - Spesifikasi Open API untuk layanan paket yang memiliki data seperti tinggi, lebar, berat, dan petunjuk penanganan khusus.
  2. data_model.py - Model data untuk spesifikasi API layanan paket. Juga membuat tabel packages di DB product_details.
  3. connect_connector.py - Koneksi CloudSQL (menentukan mesin, ORM Dasar, dan Sesi)
  4. db_init.py - Menghasilkan data sampel ke dalam tabel packages.
  5. main.py - Layanan Python Flask dengan endpoint GET untuk mengambil detail paket dari data packages berdasarkan product_id.
  6. test.py - Pengujian unit
  7. requirement.txt - Persyaratan Python
  8. Dockerfile - Untuk memasukkan aplikasi ini ke dalam container

Jika Anda mengalami masalah melekat selama latihan, semua file akhir ada di LAMPIRAN codelab ini sebagai referensi.

Pada langkah sebelumnya, Anda membuat Cloud Source Repository. Buat cloning repositori: Anda akan membangun file aplikasi di folder repositori yang di-clone.

Di terminal Cloud Shell, jalankan perintah berikut untuk meng-clone repositori.

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

Buka sidebar chat Duet AI dari menu sebelah kiri Cloud Shell Editor. Ikonnya terlihat seperti 8b135a000b259175.pngS. Sekarang Anda dapat menggunakan Duet AI untuk bantuan kode.

package-service.yaml

Tanpa ada file yang terbuka, minta Duet AI untuk membuat spesifikasi Open API untuk layanan pengiriman.

Perintah 1: Buat spesifikasi yaml OpenAPI untuk layanan yang menyediakan informasi pengiriman dan paket berdasarkan ID produk numerik. Layanan harus menyertakan informasi tentang tinggi, lebar, kedalaman, berat paket, dan semua petunjuk penanganan khusus.

ba12626f491a1204.png

Ada tiga opsi yang tercantum di kanan atas jendela kode yang dihasilkan.

Anda dapat COPY 71194556d8061dae.pngSkode dan MENEMPELnya ke file.

Anda dapat ADD df645de8c65607a.png kode ke file yang sedang dibuka di Editor.

Atau Anda dapat OPEN a4c7ed6d845df343.png kode di file baru.

Klik OPEN a4c7ed6d845df343.png kode dalam file baru.

Klik CTRL/CMD + s untuk menyimpan file, dan simpan file di folder aplikasi dengan nama file yang disebut package-service.yaml. Klik OK.

f6ebd5b836949366.png

File final ada di bagian APPENDIX di codelab ini. Jika tidak, lakukan perubahan yang sesuai secara manual.

Anda juga dapat mencoba berbagai perintah untuk melihat respons Duet AI.

Reset histori chat Duet AI dengan mengklik ikon sampah f574ca2c1e114856.png di bagian atas sidebar Duet AI.

data_model.py

Selanjutnya, Anda membuat file python model data untuk layanan berdasarkan spesifikasi OpenAPI.

Dengan file package-service.yaml terbuka, masukkan perintah berikut.

Perintah 1: Dengan ORM sqlalchemy python, buat model data untuk layanan API ini. Sertakan juga fungsi terpisah dan titik entri utama yang membuat tabel database.

b873a6a28bd28ca1.png

Mari kita lihat setiap bagian yang dihasilkan. Duet AI masih merupakan asisten, dan meskipun dapat membantu menulis kode dengan cepat, Anda harus meninjau konten yang dihasilkan dan memahaminya selagi menggunakannya.

Pertama, ada Class yang disebut Package dari jenis Base yang menentukan model data untuk database packages seperti berikut:

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

Selanjutnya, Anda memerlukan fungsi yang membuat tabel dalam {i>database<i} seperti berikut:

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

Terakhir, Anda memerlukan fungsi utama yang menjalankan fungsi create_tables untuk benar-benar membangun tabel dalam database CloudSQL, seperti berikut:

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

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

    print('Tables created successfully.')

Perhatikan bahwa fungsi main membuat mesin menggunakan database sqlite lokal. Untuk menggunakan CloudSQL, Anda perlu mengubahnya. Anda akan melakukannya nanti.

Menggunakan OPEN a4c7ed6d845df343.png kode dalam alur kerja file baru seperti sebelumnya. Simpan kode dalam file bernama data_model.py (perhatikan garis bawah dalam nama, bukan tanda hubung).

Reset histori chat Duet AI dengan mengklik ikon sampah f574ca2c1e114856.png di bagian atas sidebar Duet AI.

connect-connector.py

Membuat konektor CloudSQL.

Dengan file data_model.py terbuka, masukkan perintah berikut.

Perintah 1: Dengan menggunakan library cloud-sql-python-connector, buat fungsi yang menginisialisasi kumpulan koneksi untuk instance Postgres Cloud SQL.

ed05cb6ff85d34c5.png

Perhatikan bahwa respons tidak menggunakan library cloud-sql-python-connector. Anda dapat menyempurnakan perintah, untuk memberikan sedikit dorongan pada Duet, dengan menambahkan detail ke rangkaian pesan chat yang sama.

Mari kita gunakan prompt lain.

Perintah 2: Harus menggunakan library cloud-sql-python-connector.

d09095b44dde35bf.png

Pastikan file tersebut menggunakan library cloud-sql-python-connector.

Menggunakan OPEN a4c7ed6d845df343.png kode dalam alur kerja file baru seperti sebelumnya. Simpan kode dalam file bernama connect_conector.py. Anda mungkin perlu mengimpor library pg8000 secara manual. Lihat file di bawah ini.

Hapus histori chat Duet AI, dan dengan file connect_connector.py terbuka, buat ORM DB engine, sessionmaker, dan base yang akan digunakan dalam aplikasi.

Perintah 1: Buat class engine, sessionmaker, dan Base ORM menggunakan metode connect_with_connector

6e4214b72ab13a63.pngS

Respons dapat menambahkan engine, Session, dan Base ke file connect_connector.py.

File final ada di bagian APPENDIX di codelab ini. Jika tidak, lakukan perubahan yang sesuai secara manual.

Anda juga dapat mencoba berbagai perintah untuk melihat variasi potensial respons Duet AI.

Reset histori chat Duet AI dengan mengklik ikon sampah f574ca2c1e114856.png di bagian atas sidebar Duet AI.

Memperbarui data_model.py

Anda harus menggunakan mesin yang dibuat pada langkah sebelumnya (dalam file connect_connector.py) untuk membuat tabel di database CloudSQL.

Hapus histori chat Duet AI. Buka file data_model.py. Coba perintah berikut.

Perintah 1: Dalam fungsi utama, impor dan gunakan engine dari connect_connector.py

2e768c9b6c523b9a.pngS

Anda akan melihat respons yang mengimpor engine dari connect_connector (untuk CloudSQL). create_table menggunakan mesin tersebut (bukan DB lokal sqlite default).

Perbarui file data_model.py.

File final ada di bagian APPENDIX di codelab ini. Jika tidak, lakukan perubahan yang sesuai secara manual.

Anda juga dapat mencoba berbagai perintah untuk melihat berbagai respons Duet AI.

Reset histori chat Duet AI dengan mengklik ikon sampah f574ca2c1e114856.png di bagian atas sidebar Duet AI.

requirements.txt

Buat file requirements.txt untuk aplikasi.

Buka file connect_connector.py dan data_model.py, lalu masukkan perintah berikut.

Perintah 1: Buat file persyaratan pip untuk model data dan layanan ini

Perintah 2: Buat file persyaratan pip untuk model data dan layanan ini menggunakan versi terbaru

69fae373bc5c6a18.pngS

Pastikan nama dan versinya sudah benar. Misalnya, dalam respons di atas, nama dan versi google-cloud-sql-connecter salah. Perbaiki versi secara manual dan buat file requirements.txt yang terlihat seperti ini:

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

Di terminal perintah, jalankan perintah berikut:

pip3 install -r requirements.txt

Reset histori chat Duet AI dengan mengklik ikon sampah f574ca2c1e114856.png di bagian atas sidebar Duet AI.

Membuat tabel paket di CloudSQL

Menetapkan variabel lingkungan untuk konektor database 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

Sekarang jalankan data_model.py.

python data_model.py

Outputnya mirip dengan berikut ini (periksa kode untuk melihat apa yang sebenarnya diharapkan):

Tables created successfully.

Menghubungkan ke instance CloudSQL dan memeriksa bahwa database telah dibuat.

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

Setelah memasukkan sandi (juga evolusi), dapatkan tabelnya.

product_details=> \dt

Outputnya mirip dengan hal berikut ini:

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

Anda juga dapat memeriksa detail model data dan tabel.

product_details=> \d+ packages

Outputnya mirip dengan hal berikut ini:

                                                                        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

Ketik \q untuk keluar dari CloudSQL.

db_init.py

Selanjutnya, mari tambahkan beberapa contoh data ke tabel packages.

Hapus histori chat Duet AI. Dengan file data_model.py terbuka, coba perintah berikut.

Perintah 1: Buat fungsi yang membuat 10 baris paket contoh dan melakukan commit ke tabel paket

Perintah 2: Dengan menggunakan sesi dari connect_connector, buat fungsi yang membuat 10 baris paket contoh dan meng-commit baris tersebut ke tabel paket

34a9afc5f04ba5.pngS

Menggunakan OPEN a4c7ed6d845df343.png kode dalam alur kerja file baru seperti sebelumnya. Simpan kode dalam file bernama db_init.py.

File final ada di bagian APPENDIX di codelab ini. Jika tidak, lakukan perubahan yang sesuai secara manual.

Anda juga dapat mencoba berbagai perintah untuk melihat berbagai respons Duet AI.

Reset histori chat Duet AI dengan mengklik ikon sampah f574ca2c1e114856.png di bagian atas sidebar Duet AI.

Membuat data paket sampel

Jalankan db_init.py dari command line.

python db_init.py

Outputnya mirip dengan hal berikut ini:

Packages created successfully.

Hubungkan lagi ke instance CloudSQL dan pastikan data sampel ditambahkan ke tabel paket.

Menghubungkan ke instance CloudSQL dan memeriksa bahwa database telah dibuat.

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

Setelah memasukkan sandi (juga evolusi), dapatkan semua data dari tabel paket.

product_details=> SELECT * FROM packages;

Outputnya mirip dengan hal berikut ini:

 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)

Ketik \q untuk keluar dari CloudSQL.

main.py

Dengan file data_model.py, package-service.yaml, dan connect_connector.py terbuka, buat main.py untuk aplikasi.

Perintah 1: Menggunakan library python flask - buat implementasi yang menggunakan endpoint http rest untuk layanan ini

Perintah 2: Menggunakan library python flask - buat implementasi yang menggunakan endpoint http rest untuk layanan ini. impor dan gunakan SessionMaker dari connect_conector.py ke untuk data paket.

Perintah 3: Menggunakan library python flask - buat implementasi yang menggunakan endpoint http rest untuk layanan ini. impor dan gunakan Package dari data_model.py dan SessionMaker dari connect_conector.py ke untuk data paket.

Perintah 4: Menggunakan library python flask - buat implementasi yang menggunakan endpoint http rest untuk layanan ini. impor dan gunakan Package dari data_model.py dan SessionMaker dari connect_conector.py ke untuk data paket. Gunakan IP host 0.0.0.0 untuk app.run

6d794fc52a90e6ae.pngS

Perbarui persyaratan untuk main.py.

Perintah: Buat file persyaratan untuk main.py

1cc0b318d2d4ca2f.pngS

Tambahkan ini ke file requirements.txt. Pastikan untuk menggunakan Flask versi 3.0.0.

Menggunakan OPEN a4c7ed6d845df343.png kode dalam alur kerja file baru seperti sebelumnya. Simpan kode dalam file bernama main.py.

File final ada di bagian APPENDIX di codelab ini. Jika tidak, lakukan perubahan yang sesuai secara manual.

Reset histori chat Duet AI dengan mengklik ikon sampah f574ca2c1e114856.png di bagian atas sidebar Duet AI.

5. Menguji dan menjalankan aplikasi

Instal persyaratan.

pip3 install -r requirements.txt

Jalankan main.py.

python main.py

Outputnya mirip dengan hal berikut ini:

 * 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

Dari terminal kedua, uji endpoint /packages/<product_id>.

curl localhost:5000/packages/1

Outputnya mirip dengan hal berikut ini:

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

Anda juga dapat menguji ID produk lainnya dalam sampel data.

Masukkan CTRL_C untuk keluar dari container docker yang sedang berjalan di terminal.

Membuat pengujian unit

Dengan file main.py terbuka, buat pengujian unit.

Perintah 1: Buat pengujian unit.

e861e5b63e1b2657.png

Menggunakan OPEN a4c7ed6d845df343.png kode dalam alur kerja file baru seperti sebelumnya. Simpan kode dalam file bernama test.py.

Dalam fungsi test_get_package, product_id harus ditentukan. Anda dapat menambahkannya secara manual.

File final ada di bagian APPENDIX di codelab ini. Jika tidak, lakukan perubahan yang sesuai secara manual.

Reset histori chat Duet AI dengan mengklik ikon sampah f574ca2c1e114856.png di bagian atas sidebar Duet AI.

Menjalankan pengujian unit

Jalankan pengujian unit.

python test.py

Outputnya mirip dengan hal berikut ini:

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

OK

Tutup semua file di Cloud Shell Editor dan hapus histori chat dengan mengklik ikon tempat sampah 1ecccfe10d6c540.pngS di status bar bagian atas.

Dockerfile

Buat Dockerfile untuk aplikasi ini.

Buka main.py dan coba perintah berikut.

Perintah 1: Buat Dockerfile untuk aplikasi ini.

Perintah 2: Buat Dockerfile untuk aplikasi ini. Salin semua file ke container.

9c473caea437a5c3.pngS

Anda juga perlu menyetel ENVARS untuk INSTANCE_CONNECTION_NAME, DB_USER, DB_PASS, dan DB_NAME. Anda dapat melakukannya secara manual. Dockerfile Anda akan terlihat seperti berikut:

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"]

Menggunakan OPEN a4c7ed6d845df343.png kode dalam alur kerja file baru seperti sebelumnya. Simpan kode dalam file bernama Dockerfile.

File final ada di bagian APPENDIX di codelab ini. Jika tidak, lakukan perubahan yang sesuai secara manual.

Menjalankan aplikasi secara lokal

Saat Dockerfile terbuka, coba perintah berikut.

Perintah 1: Bagaimana cara menjalankan container secara lokal menggunakan Dockerfile ini

570fd5c296ca8c83.pngS

Ikuti petunjuknya.

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

Outputnya mirip dengan hal berikut ini:

 * 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

Dari jendela terminal kedua, akses container.

curl localhost:5000/packages/1

Outputnya mirip dengan hal berikut ini:

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

Aplikasi dalam container sedang berfungsi.

Masukkan CTRL_C untuk keluar dari container docker yang sedang berjalan di terminal.

Membangun image container di Artifact Registry

Bangun image container dan kirim ke 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

Container aplikasi kini berada di us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping yang dapat di-deploy ke GKE.

6. Men-deploy aplikasi ke cluster GKE

Cluster GKE Autopilot dibuat saat Anda membuat resource GCP untuk workshop ini. Hubungkan ke cluster GKE.

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

Menganotasi akun layanan default Kubernetes dengan akun layanan Google.

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

Outputnya mirip dengan hal berikut ini:

serviceaccount/default annotated

Siapkan dan terapkan file 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

Outputnya mirip dengan hal berikut ini:

deployment.apps/shipping created
service/shipping created

Tunggu hingga Pod berjalan dan Service memiliki alamat IP load balancer eksternal yang ditetapkan.

kubectl get pods
kubectl get service shipping

Outputnya mirip dengan hal berikut ini:

# 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

Untuk cluster Autopilot GKE, tunggu beberapa saat hingga resource siap.

Akses layanan melalui alamat EXTERNAL-IP.

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

Outputnya mirip dengan hal berikut ini:

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

7. Kredit Tambahan: Memecahkan masalah aplikasi

Hapus peran IAM Klien CloudSQL dari akun layanan cloudsqlsa. Tindakan ini menyebabkan error saat menghubungkan ke database CloudSQL.

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

Memulai ulang Pod pengiriman.

kubectl rollout restart deployment shipping

Setelah Pod dimulai ulang, coba akses layanan shipping lagi.

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

Outputnya mirip dengan hal berikut ini:

...
<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>

Periksa Log dengan membuka Kubernetes Engine > Workload

d225b1916c829167.png

Klik deployment shipping, lalu tab Logs.

1d0459141483d6a7.pngS

Klik ikon View in Log Explorer df8b9d19a9fe4c73.pngdi sisi kanan status bar. Tindakan ini akan membuka jendela Log Explorer baru.

e86d1c265e176bc4.png

Klik salah satu entri error Traceback, lalu klik Explain this Log Entry.

d6af045cf03008bc.png

Anda dapat membaca penjelasan error.

Selanjutnya, mari kita gunakan Duet AI untuk membantu memecahkan error tersebut.

Coba perintah berikut.

Perintah 1: Bantu saya memecahkan masalah error ini

9288dd6045369167.pngS

Masukkan pesan error pada dialog.

Perintah 2: Dilarang: Akun utama IAM yang diautentikasi tampaknya tidak diberi otorisasi untuk membuat permintaan API. Verifikasi 'Cloud SQL Admin API' diaktifkan dalam project GCP dan 'Klien Cloud SQL' peran telah diberikan ke akun utama IAM

f1e64fbdc435d31c.png

Lalu.

Perintah 3: Bagaimana cara menetapkan peran Klien Cloud SQL ke akun layanan Google menggunakan gcloud?

bb8926b995a8875c.png

Tetapkan peran Klien Cloud SQL ke cloudsqlsa.

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

Tunggu beberapa saat dan coba akses aplikasi lagi.

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

Outputnya mirip dengan hal berikut ini:

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

Anda telah berhasil menggunakan Duet AI di Cloud Logging, Log Explorer, dan fitur Log Explainer untuk memecahkan masalah tersebut.

8. Kesimpulan

Selamat! Anda berhasil menyelesaikan codelab ini.

Dalam codelab ini, Anda telah mempelajari hal berikut:

  1. Aktifkan Duet AI di project GCP Anda dan konfigurasikan untuk digunakan di IDE dan Konsol Cloud.
  2. Gunakan Gemini untuk pembuatan, penyelesaian, dan penjelasan kode.
  3. Menggunakan Gemini untuk menjelaskan dan memecahkan masalah aplikasi.
  4. Fitur Duet AI seperti chat IDE dan chat multi-giliran, chat vs pembuatan kode inline, tindakan cerdas seperti penjelasan kode dan pengakuan pembacaan, dan banyak lagi.

9. Lampiran

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

Dockerfile

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"]