1. Цели
Цель этого семинара — предоставить пользователям и специалистам практическое обучение работе с Duet AI.
В ходе этого практического занятия вы изучите следующее:
- Активируйте Duet AI в своем проекте GCP и настройте его для использования в IDE и облачной консоли.
- Используйте Duet AI для генерации кода, автозавершения и пояснения.
- Используйте Duet AI для объяснения и устранения неполадок в приложении.
- Функции Duet AI включают в себя чат в IDE и многоходовый чат, генерацию кода в чате и непосредственно в коде, интеллектуальные действия, такие как объяснение кода и подтверждение участия в обсуждении, и многое другое.
Повествование
Чтобы продемонстрировать, как Duet AI for Developers используется в повседневной разработке, занятия на этом семинаре проходят в повествовательном контексте.
В компанию, занимающуюся электронной коммерцией, приходит новый разработчик. Ему поручено добавить новый сервис в существующее приложение для электронной коммерции (которое состоит из нескольких сервисов). Новый сервис предоставляет дополнительную информацию (размеры, вес и т. д.) о товарах в каталоге. Этот сервис позволит снизить стоимость доставки в зависимости от размеров и веса товара.
Поскольку разработчик недавно работает в компании, он будет использовать Duet AI для генерации кода, его объяснений и документирования.
После завершения разработки сервиса администратор платформы использует Duet AI (чат) для создания артефакта (контейнера Docker) и ресурсов, необходимых для развертывания артефакта в GCP (например, реестр артефактов, разрешения IAM, репозиторий кода, вычислительная инфраструктура, например, GKE или CloudRun и т. д.).
После развертывания приложения в GCP оператор приложения/SRE будет использовать Duet AI (и Cloud Ops) для устранения ошибок в новом сервисе.
Персона
Данный семинар охватывает следующие категории участников:
- Разработчик приложений — требуются базовые знания в области программирования и разработки программного обеспечения.
Этот вариант мастер-класса Duet AI предназначен только для разработчиков. Знание облачных ресурсов GCP не требуется. Скрипты для сборки необходимых ресурсов GCP для запуска этого приложения можно найти здесь . Вы можете следовать инструкциям в этом руководстве для развертывания необходимых ресурсов GCP.
2. Подготовка окружающей среды
Активация Duet AI
Вы можете активировать Duet AI в проекте GCP либо через API (gcloud или инструменты IaC, такие как Terraform), либо через пользовательский интерфейс Cloud Console.
Для активации Duet AI в проекте Google Cloud необходимо включить API Cloud AI Companion и предоставить пользователям роли управления идентификацией и доступом (IAM) для Cloud AI Companion User и Service Usage Viewer.
Через gcloud
Активировать Cloud Shell:
Настройте PROJECT_ID ) и USER , а также включите API Cloud AI Companion.
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}
Результат выглядит следующим образом:
Updated property [core/project]. Operation "operations/acat.p2-60565640195-f37dc7fe-b093-4451-9b12-934649e2a435" finished successfully.
Предоставьте учетной записи пользователя роли управления идентификацией и доступом (IAM) для Cloud AI Companion User и Service Usage Viewer. API Cloud Companion работает в фоновом режиме как в IDE, так и в консоли, которые мы будем использовать. Разрешение Service Usage Viewer используется для быстрой проверки перед включением пользовательского интерфейса в консоли (чтобы пользовательский интерфейс Duet отображался только в проектах, в которых включен 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
Результат выглядит следующим образом:
... - members: - user:<YOUR USER ACCOUNT> role: roles/cloudaicompanion.user ... - members: - user:<YOUR USER ACCOUNT> role: roles/serviceusage.serviceUsageViewer
Через облачную консоль
Чтобы включить API, перейдите на страницу Cloud AI Companion API в консоли Google Cloud.
В окне выбора проекта выберите проект.
Нажмите «Включить» .
Страница обновляется и отображает статус «Включено» . Duet AI теперь доступен в выбранном проекте Google Cloud всем пользователям, имеющим необходимые роли IAM.
Чтобы предоставить необходимые роли IAM для использования Duet AI, перейдите на страницу IAM .
В столбце «Основной пользователь» найдите пользователя, которому вы хотите предоставить доступ к Duet AI, а затем нажмите значок карандаша ✏️ «Изменить основной пользователь» в этой строке.
В панели «Редактировать доступ» нажмите « Добавить еще одну роль» .
В разделе «Выберите роль» выберите «Пользователь Cloud AI Companion» .
Нажмите «Добавить еще одну роль» и выберите «Просмотрщик использования сервиса» .
Нажмите « Сохранить ».
Настройка IDE
Разработчики могут выбирать из множества IDE, которые наилучшим образом соответствуют их потребностям. Функция помощи в написании кода Duet AI доступна в нескольких IDE, таких как Visual Studio Code , IDE от JetBrains (IntelliJ, PyCharm, GoLand, WebStorm и другие), Cloud Workstations , Cloud Shell Editor .
В этой лабораторной работе вы можете использовать либо облачные рабочие станции , либо редактор облачной оболочки.
В этом мастер-классе используется редактор Cloud Shell.
Обратите внимание, что настройка облачных рабочих станций может занять 20-30 минут.
Для немедленного использования воспользуйтесь редактором Cloud Shell Editor .
Откройте редактор Cloud Shell, нажав на значок карандаша ✏️ в верхней панели меню Cloud Shell.
Редактор Cloud Shell имеет очень похожий пользовательский интерфейс и взаимодействие с пользователем, как и VSCode.

Нажмите CTRL (в Windows)/CMD (в Mac) + , (запятая), чтобы открыть панель настроек.
В строке поиска введите "duet ai".
Убедитесь или включите Cloudcode › Duet AI: включить и Cloudcode › Duet AI › Встроенные предложения: включить автоматически

В нижней строке состояния нажмите «Cloud Code — Войти» и следуйте инструкциям по входу в систему.
Если вы уже вошли в систему, в строке состояния отобразится Cloud Code - Нет проекта .
Нажмите на «Cloud Code - No project», и вверху появится выпадающее меню действий. Нажмите « Select a Google Cloud project» .

Начните вводить идентификатор вашего проекта, и ваш проект должен появиться в списке.

Выберите свой PROJECT_ID из списка проектов.
В нижней строке состояния отображается идентификатор вашего проекта. Если этого не происходит, возможно, вам потребуется обновить вкладку «Редактор Cloud Shell».
Нажмите на значок Duet AI.
В левой боковой панели меню появится окно чата Duet AI. Если появится сообщение «Выберите проект GCP», щелкните по нему и выберите проект снова.
Теперь вы видите окно чата Duet AI.

3. Создание инфраструктуры

Для запуска новой службы доставки в GCP вам потребуются следующие ресурсы GCP:
- Экземпляр Cloud SQL с базой данных.
- Кластер GKE для запуска контейнеризированного сервиса.
- Реестр артефактов для хранения образа Docker.
- Облачный репозиторий исходного кода.
В терминале Cloud Shell клонируйте следующий репозиторий и выполните следующие команды для настройки инфраструктуры в вашем проекте GCP.
# 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. Разработка сервиса Flask на Python.

Создаваемый нами сервис в конечном итоге будет состоять из следующих файлов. Вам не нужно создавать эти файлы сейчас, вы будете создавать их по одному, следуя инструкциям ниже:
-
package-service.yaml— Спецификация Open API для службы доставки пакетов, содержащая такие данные, как высота, ширина, вес и специальные инструкции по обработке. -
data_model.py— Модель данных для спецификации API package-service. Также создает таблицуpackagesв базе данных product_details. -
connect_connector.py— Подключение к CloudSQL (определяет движок, сессию и базовый ORM) -
db_init.py— генерирует примерные данные для таблицыpackages. -
main.py- Сервис Python Flask сGETзапросом для получения сведений о пакете на основе данныхpackagesпо полю product_id. -
test.py- Модульный тест -
requirement.txt- Требования Python -
Dockerfile— для контейнеризации этого приложения.
Если во время выполнения упражнений у вас возникнут какие-либо сложности, все итоговые файлы находятся в ПРИЛОЖЕНИИ к данному практическому руководству.
На предыдущем шаге вы создали репозиторий облачных источников. Клонируйте этот репозиторий. Вы будете собирать файлы приложения в папке клонированного репозитория.
В терминале Cloud Shell выполните следующую команду для клонирования репозитория.
cd ~ gcloud source repos clone shipping shipping cd ~/shipping
Откройте боковую панель чата Duet AI из левого меню редактора Cloud Shell. Значок выглядит так:
Теперь вы можете использовать Duet AI для помощи в написании кода.
package-service.yaml
Не открывая никаких файлов, попросите Duet сгенерировать спецификацию Open API для службы доставки.
Задание 1: Сгенерируйте спецификацию OpenAPI в формате YAML для сервиса, предоставляющего информацию о доставке и упаковке на основе числового идентификатора продукта. Сервис должен включать информацию о высоте, ширине, глубине, весе упаковки и любых специальных инструкциях по обработке.

В правом верхнем углу окна сгенерированного кода перечислены три варианта.
Вы можете либо COPY
Вставьте код в файл.
Вы можете ADD
Код открытого в данный момент файла в редакторе.
Или вы можете OPEN
Код находится в новом файле.
Нажмите кнопку « OPEN
Код находится в новом файле.
Нажмите CTRL/CMD + s , чтобы сохранить файл, и сохраните его в папке приложения под именем package-service.yaml . Нажмите OK.

Итоговый файл находится в разделе ПРИЛОЖЕНИЕ к данному практическому заданию. Если его там нет, внесите необходимые изменения вручную.
Вы также можете попробовать различные подсказки, чтобы увидеть ответы Duet AI.
Чтобы сбросить историю чата Duet AI, нажмите на значок корзины.
в верхней части боковой панели Duet AI.
data_model.py
Далее вы создаете файл Python с моделью данных для сервиса на основе спецификации OpenAPI.
Откройте файл package-service.yaml и введите следующую команду.
Задание 1: Используя ORM sqlalchemy для Python, сгенерируйте модель данных для этого API-сервиса. Также добавьте отдельную функцию и основную точку входа, которые создают таблицы базы данных.

Давайте рассмотрим каждую сгенерированную часть. Duet AI по-прежнему является помощником, и хотя он может помочь быстро создавать код, вам все равно следует проверять сгенерированный контент и понимать его по ходу работы.
Во-первых, существует класс под названием Package типа Base , который определяет модель данных для базы данных packages следующим образом:
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))
Далее вам понадобится функция, которая создаст таблицу в базе данных, примерно следующего вида:
def create_tables(engine):
Base.metadata.create_all(engine)
Наконец, вам потребуется основная функция, которая запускает функцию create_tables для фактического создания таблицы в базе данных CloudSQL, примерно следующего вида:
if __name__ == '__main__':
from sqlalchemy import create_engine
engine = create_engine('sqlite:///shipping.db')
create_tables(engine)
print('Tables created successfully.')
Обратите внимание, что main функция — создание движка с использованием локальной базы данных sqlite . Для использования CloudSQL вам потребуется внести изменения. Это вы сделаете чуть позже.
Используя OPEN
Сохраните код в новом файле, как и раньше. Затем сохраните код в файле с именем data_model.py (обратите внимание на нижнее подчеркивание в имени, а не на дефис).
Чтобы сбросить историю чата Duet AI, нажмите на значок корзины.
в верхней части боковой панели Duet AI.
connect-connector.py
Создайте коннектор CloudSQL.
Откройте файл data_model.py и введите следующие команды.
Задание 1: Используя библиотеку cloud-sql-python-connector, создайте функцию, которая инициализирует пул соединений для экземпляра Cloud SQL в Postgres.

Обратите внимание, что в ответе не используется библиотека cloud-sql-python-connector . Вы можете уточнить подсказки, чтобы немного подтолкнуть Duet к действиям, добавив конкретные детали в тот же чат.
Давайте воспользуемся другой подсказкой.
Подсказка 2: Необходимо использовать библиотеку cloud-sql-python-connector.

Убедитесь, что используется библиотека cloud-sql-python-connector .
Используя OPEN
Сохраните код в новом файле, как и раньше. Затем сохраните код в файле с именем connect_conector.py . Возможно, вам потребуется вручную импортировать библиотеку pg8000 ; см. файл ниже.
Очистите историю чата Duet AI, а затем, открыв файл connect_connector.py , сгенерируйте DB engine , sessionmaker и base ORM для использования в приложении.
Задание 1: Создайте движок, класс SessionMaker и базовый ORM, используя метод connect_with_connector.

В ответном сообщении могут быть добавлены данные engine , Session и Base в файл connect_connector.py .
Итоговый файл находится в разделе ПРИЛОЖЕНИЕ к данному практическому заданию. Если его там нет, внесите необходимые изменения вручную.
Вы также можете попробовать различные варианты ответов, чтобы увидеть, насколько разнообразными могут быть ответы Duet AI.
Чтобы сбросить историю чата Duet AI, нажмите на значок корзины.
в верхней части боковой панели Duet AI.
Обновление файла data_model.py
Для создания таблицы в базе данных CloudSQL вам необходимо использовать механизм, созданный на предыдущем шаге (в файле connect_connector.py ).
Очистите историю чата Duet AI. Откройте файл data_model.py . Попробуйте выполнить следующую команду.
Задание 1: В главной функции импортируйте и используйте движок из файла connect_connector.py.

Вы должны увидеть ответ, в котором импортируется engine из connect_connector (для CloudSQL). Функция create_table использует этот движок (вместо локальной базы данных sqlite по умолчанию).
Обновите файл data_model.py .
Итоговый файл находится в разделе ПРИЛОЖЕНИЕ к данному практическому заданию. Если его там нет, внесите необходимые изменения вручную.
Вы также можете попробовать различные подсказки, чтобы увидеть разные ответы ИИ в Duet.
Чтобы сбросить историю чата Duet AI, нажмите на значок корзины.
в верхней части боковой панели Duet AI.
requirements.txt
Создайте файл requirements.txt для приложения.
Откройте файлы connect_connector.py и data_model.py и введите следующую команду.
Задание 1: Сгенерируйте файл требований pip для этой модели данных и сервиса.
Задание 2: Сгенерируйте файл требований pip для этой модели данных и сервиса, используя последние версии.

Убедитесь в правильности названий и версий. Например, в приведенном выше ответе название и версия google-cloud-sql-connecter указаны неверно. Исправьте версии вручную и создайте файл requirements.txt следующего вида:
cloud-sql-python-connector==1.2.4
sqlalchemy==1.4.36
pg8000==1.22.0
В командной строке выполните следующую команду:
pip3 install -r requirements.txt
Чтобы сбросить историю чата Duet AI, нажмите на значок корзины.
в верхней части боковой панели Duet AI.
Создание таблицы пакетов в CloudSQL
Настройте переменные среды для коннектора базы данных 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
Теперь запустите файл data_model.py.
python data_model.py
Результат будет примерно таким (проверьте код, чтобы увидеть, что на самом деле ожидается):
Tables created successfully.
Подключитесь к экземпляру CloudSQL и убедитесь, что база данных создана.
gcloud sql connect ${INSTANCE_NAME} --user=evolution --database=product_details
После ввода пароля (также evolution ) получите таблицы.
product_details=> \dt
Результат будет примерно следующим:
List of relations Schema | Name | Type | Owner --------+----------+-------+----------- public | packages | table | evolution (1 row)
Вы также можете проверить модель данных и подробные сведения о таблице.
product_details=> \d+ packages
Результат будет примерно следующим:
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
Для выхода из CloudSQL введите \q .
db_init.py
Далее добавим несколько примеров данных в таблицу packages .
Очистите историю чата Duet AI. Откройте файл data_model.py и попробуйте выполнить следующие действия.
Задание 1: Создайте функцию, которая создаст 10 строк с примерами пакетов и добавит их в таблицу пакетов.
Задание 2: Используя сессию из connect_connector, создайте функцию, которая создаст 10 строк с примерами пакетов и добавит их в таблицу packages.

Используя OPEN
Как и прежде, создайте новый файл с кодом. Сохраните код в файле с именем db_init.py .
Итоговый файл находится в разделе ПРИЛОЖЕНИЕ к данному практическому заданию. Если его там нет, внесите необходимые изменения вручную.
Вы также можете попробовать различные подсказки, чтобы увидеть разные ответы ИИ в Duet.
Чтобы сбросить историю чата Duet AI, нажмите на значок корзины.
в верхней части боковой панели Duet AI.
Создание образцов данных пакетов
Запустите файл db_init.py из командной строки.
python db_init.py
Результат будет примерно следующим:
Packages created successfully.
Подключитесь к экземпляру CloudSQL еще раз и убедитесь, что тестовые данные добавлены в таблицу пакетов.
Подключитесь к экземпляру CloudSQL и убедитесь, что база данных создана.
gcloud sql connect ${INSTANCE_NAME} --user=evolution --database=product_details
После ввода пароля (также evolution ) получите все данные из таблицы пакетов.
product_details=> SELECT * FROM packages;
Результат будет примерно следующим:
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)
Для выхода из CloudSQL введите \q .
main.py
Откройте файлы data_model.py , package-service.yaml и connect_connector.py и создайте файл main.py для приложения.
Задание 1: Используя библиотеку Python Flask, создайте реализацию, которая использует HTTP REST-конечные точки для этого сервиса.
Задание 2: Используя библиотеку Python Flask, создайте реализацию, которая использует HTTP REST-конечные точки для этого сервиса. Импортируйте и используйте SessionMaker из файла connect_conector.py для работы с данными пакетов.
Задание 3: Используя библиотеку Python Flask, создайте реализацию, которая использует HTTP REST-конечные точки для этого сервиса. Импортируйте и используйте Package из файла data_model.py и SessionMaker из файла connect_conector.py для работы с данными пакетов.
Задание 4: Используя библиотеку Python Flask, создайте реализацию, которая использует HTTP REST-конечные точки для этого сервиса. Импортируйте и используйте Package из файла data_model.py и SessionMaker из файла connect_conector.py для работы с данными пакетов. Используйте IP-адрес хоста 0.0.0.0 для запуска приложения.

Обновите зависимости для main.py
Подсказка: Создайте файл требований для main.py

Добавьте это в файл requirements.txt . Убедитесь, что используете Flask версии 3.0.0.
Используя OPEN
Как и раньше, создайте новый файл с кодом в рамках одного рабочего процесса. Сохраните код в файле с именем main.py
Итоговый файл находится в разделе ПРИЛОЖЕНИЕ к данному практическому заданию. Если его там нет, внесите необходимые изменения вручную.
Чтобы сбросить историю чата Duet AI, нажмите на значок корзины.
в верхней части боковой панели Duet AI.
5. Тестирование и запуск приложения
Установите необходимые зависимости.
pip3 install -r requirements.txt
Запустите main.py
python main.py
Результат будет примерно следующим:
* 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
Проверьте доступ к конечной точке /packages/<product_id> со второго терминала.
curl localhost:5000/packages/1
Результат будет примерно следующим:
{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}
Вы также можете протестировать любой другой идентификатор продукта в ваших примерах данных.
Нажмите CTRL_C , чтобы выйти из запущенного контейнера Docker в терминале.
Генерация модульных тестов
Откройте файл main.py и сгенерируйте модульные тесты.
Задание 1: Сгенерируйте модульные тесты.

Используя OPEN
Как и раньше, создайте новый файл с кодом в рамках одного рабочего процесса. Сохраните код в файле с именем test.py
В функции test_get_package необходимо указать product_id . Вы можете добавить его вручную.
Итоговый файл находится в разделе ПРИЛОЖЕНИЕ к данному практическому заданию. Если его там нет, внесите необходимые изменения вручную.
Чтобы сбросить историю чата Duet AI, нажмите на значок корзины.
в верхней части боковой панели Duet AI.
Выполнение модульных тестов
Запустите модульный тест.
python test.py
Результат будет примерно следующим:
. ---------------------------------------------------------------------- Ran 1 test in 1.061s OK
Закройте все файлы в редакторе Cloud Shell и очистите историю чата, нажав на значок корзины.
в верхней строке состояния.
Dockerfile
Создайте Dockerfile для этого приложения.
Откройте main.py и попробуйте выполнить следующие действия.
Задание 1: Сгенерируйте Dockerfile для этого приложения.
Задание 2: Сгенерируйте Dockerfile для этого приложения. Скопируйте все файлы в контейнер.

Также необходимо установить ENVARS для INSTANCE_CONNECTION_NAME , DB_USER , DB_PASS и DB_NAME . Это можно сделать вручную. Ваш 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"]
Используя OPEN
Как и раньше, создайте новый файл с кодом в рамках рабочего процесса. Сохраните код в файле с именем Dockerfile.
Итоговый файл находится в разделе ПРИЛОЖЕНИЕ к данному практическому заданию. Если его там нет, внесите необходимые изменения вручную.
Запуск приложения локально.
Откройте файл Dockerfile и попробуйте ввести следующую команду.
Вопрос 1: Как запустить контейнер локально, используя этот Dockerfile?

Следуйте инструкциям.
# Build docker build -t shipping . # And run docker run -p 5000:5000 -it shipping
Результат будет примерно следующим:
* 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
Во втором окне терминала получите доступ к контейнеру.
curl localhost:5000/packages/1
Результат будет примерно следующим:
{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}
Контейнеризированное приложение работает.
Нажмите CTRL_C , чтобы выйти из запущенного контейнера Docker в терминале.
Создание образа контейнера в реестре артефактов
Создайте образ контейнера и загрузите его в реестр артефактов.
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
Контейнер приложения теперь находится по адресу us-central1-docker.pkg.dev/${PROJECT_ID}/shipping/shipping и может быть развернут в GKE.
6. Развертывание приложения в кластере GKE
При создании ресурсов GCP для этого семинара был создан кластер GKE Autopilot. Подключитесь к кластеру GKE.
gcloud container clusters get-credentials gke1 \
--region=us-central1
Добавьте в аннотацию к учетной записи службы Kubernetes по умолчанию учетную запись службы Google.
kubectl annotate serviceaccount default iam.gke.io/gcp-service-account=cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com
Результат будет примерно следующим:
serviceaccount/default annotated
Подготовьте и примените файл 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
Результат будет примерно следующим:
deployment.apps/shipping created service/shipping created
Дождитесь, пока поды запустятся и сервису будет назначен IP-адрес внешнего балансировщика нагрузки.
kubectl get pods kubectl get service shipping
Результат будет примерно следующим:
# 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
Для кластеров GKE Autopilot подождите несколько минут, пока ресурсы не будут готовы.
Для доступа к сервису используйте EXTERNAL-IP адрес.
export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1
Результат будет примерно следующим:
{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}
7. Дополнительное задание: Устранение неполадок в приложении.
Удалите роль IAM клиента CloudSQL из учетной записи службы cloudsqlsa . Это приведет к ошибке подключения к базе данных CloudSQL.
gcloud projects remove-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="roles/cloudsql.client"
Перезапустите транспортировочный модуль.
kubectl rollout restart deployment shipping
После перезагрузки Pod попробуйте снова получить доступ к службе shipping .
export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1
Результат будет примерно следующим:
... <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>
Просмотрите журналы, перейдя в раздел Kubernetes Engine > Workloads.

Перейдите в раздел shipping , а затем во вкладку «Журналы» .

Нажмите « Просмотреть в обозревателе журналов».
Значок находится в правой части строки состояния. Он открывает новое окно «Проводник журналов» .

Щелкните по одной из записей об ошибке Traceback , а затем нажмите «Показать эту запись в журнале» .

Вы можете ознакомиться с объяснением ошибки.
Далее, давайте воспользуемся помощью Duet AI для устранения ошибки.
Попробуйте выполнить следующую команду.
Задание 1: Помогите мне устранить эту ошибку.

Введите сообщение об ошибке в подсказке.
Сообщение 2: Запрещено: Аутентифицированный субъект IAM, по-видимому, не авторизован для выполнения запроса к API. Убедитесь, что «Cloud SQL Admin API» включен в вашем проекте GCP и что роль «Cloud SQL Client» предоставлена субъекту IAM.

А потом.
Вопрос 3: Как назначить роль клиента Cloud SQL учетной записи службы Google с помощью gcloud?

Назначьте роль Cloud SQL Client пользователю cloudsqlsa .
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:cloudsqlsa@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="roles/cloudsql.client"
Подождите несколько минут и попробуйте снова войти в приложение.
export EXTERNAL_IP=$(kubectl get svc shipping --output jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl http://${EXTERNAL_IP}/packages/1
Результат будет примерно следующим:
{"depth":10.0,"height":10.0,"special_handling_instructions":"No special handling instructions.","weight":10.0,"width":10.0}
Вы успешно использовали Duet AI в Cloud Logging , Log Explorer и функцию Log Explainer для устранения проблемы.
8. Заключение
Поздравляем! Вы успешно завершили этот практический курс.
В ходе этой практической работы вы изучили следующее:
- Активируйте Duet AI в своем проекте GCP и настройте его для использования в IDE и облачной консоли.
- Используйте Duet AI для генерации кода, автозавершения и пояснения.
- Используйте Duet AI для объяснения и устранения неполадок в приложении.
- Функции Duet AI включают в себя чат в IDE и многоходовый чат, генерацию кода в чате и непосредственно в коде, интеллектуальные действия, такие как объяснение кода и подтверждение участия в обсуждении, и многое другое.
9. Приложение
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")
тест.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"]