1. Обзор
В этой лабораторной работе демонстрируются функции и возможности, разработанные для оптимизации рабочего процесса разработки программного обеспечения для инженеров-программистов, занимающихся разработкой приложений на Python в контейнеризированной среде. Типичная разработка в контейнерах требует от пользователя понимания деталей контейнеров и процесса сборки контейнеров. Кроме того, разработчикам обычно приходится прерывать свой рабочий процесс, выходя из IDE для тестирования и отладки своих приложений в удаленных средах. С помощью инструментов и технологий, упомянутых в этом руководстве, разработчики могут эффективно работать с контейнеризированными приложениями, не покидая свою IDE.
Что вы узнаете
В этой лабораторной работе вы изучите методы разработки с использованием контейнеров в GCP, в том числе:
- Создание нового стартового приложения на Python
- Проследите за процессом разработки.
- Разработайте простой REST-сервис для операций CRUD (создание, выполнение, обновление, удаление)
- Развертывание в GKE
- Отладка состояния ошибки
- Использование точек останова / логов
- Горячее развертывание изменений обратно в GKE

2. Настройка и требования
Настройка среды для самостоятельного обучения
- Войдите в консоль Google Cloud и создайте новый проект или используйте существующий. Если у вас еще нет учетной записи Gmail или Google Workspace, вам необходимо ее создать .



- Название проекта — это отображаемое имя участников данного проекта. Это строка символов, не используемая API Google. Вы можете изменить её в любое время.
- Идентификатор проекта уникален для всех проектов Google Cloud и является неизменяемым (его нельзя изменить после установки). Консоль Cloud автоматически генерирует уникальную строку; обычно вам неважно, какая она. В большинстве практических заданий вам потребуется указать идентификатор проекта (обычно он обозначается как
PROJECT_ID). Если сгенерированный идентификатор вас не устраивает, вы можете сгенерировать другой случайный идентификатор. В качестве альтернативы вы можете попробовать свой собственный и посмотреть, доступен ли он. После этого шага его нельзя изменить, и он останется неизменным на протяжении всего проекта. - К вашему сведению, существует третье значение — номер проекта , который используется некоторыми API. Подробнее обо всех трех значениях можно узнать в документации .
- Далее вам потребуется включить оплату в консоли Cloud для использования ресурсов/API Cloud. Выполнение этого практического задания не должно стоить дорого, если вообще что-либо. Чтобы отключить ресурсы и избежать дополнительных расходов после завершения этого урока, вы можете удалить созданные ресурсы или удалить весь проект. Новые пользователи Google Cloud имеют право на бесплатную пробную версию стоимостью 300 долларов США .
Запустить редактор Cloudshell
Данная лабораторная работа разработана и протестирована для использования с редактором Google Cloud Shell. Для доступа к редактору,
- Получите доступ к своему проекту Google по адресу https://console.cloud.google.com .
- В правом верхнем углу нажмите на значок редактора облачной оболочки.

- В нижней части вашего окна откроется новое окно.
- Нажмите кнопку «Открыть редактор».

- В начале редактора справа будет изображен исследователь, а в центре — сам редактор.
- В нижней части экрана также должна быть доступна панель терминала.
- Если терминал НЕ открыт, используйте комбинацию клавиш `Ctrl+`, чтобы открыть новое окно терминала.
Настройка среды
В Cloud Shell укажите идентификатор проекта и номер проекта. Сохраните их как переменные PROJECT_ID и PROJECT_ID .
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID \
--format='value(projectNumber)')
Обеспечьте наличие инфраструктуры, используемой в этой лаборатории.
В этой лабораторной работе вы развернете код в GKE и получите доступ к данным, хранящимся в базе данных Spanner. В качестве IDE вы также будете использовать облачные рабочие станции. Приведенный ниже скрипт настройки подготовит для вас эту инфраструктуру.
- Скачайте установочный скрипт и сделайте его исполняемым.
wget https://raw.githubusercontent.com/GoogleCloudPlatform/container-developer-workshop/main/labs/python/setup_with_cw.sh
chmod +x setup_with_cw.sh
- Откройте файл
setup_with_cw.shи отредактируйте значения паролей, которые в данный момент установлены на CHANGEME. - Запустите скрипт настройки, чтобы развернуть кластер GKE и базу данных Spanner, которые вы будете использовать в этой лабораторной работе.
./setup_with_cw.sh &
Кластер облачных рабочих станций
- Откройте Cloud Workstations в Cloud Console. Дождитесь, пока кластер перейдет в состояние
READY.
Создание конфигурации рабочих станций
- Если ваша сессия Cloud Shell была разорвана, нажмите «Переподключиться», а затем выполните команду cli gcloud, чтобы установить идентификатор проекта. Перед выполнением команды замените указанный ниже пример идентификатора проекта на идентификатор вашего проекта qwiklabs.
gcloud config set project qwiklabs-gcp-project-id
- Загрузите и запустите приведенный ниже скрипт в терминале, чтобы создать конфигурацию облачных рабочих станций.
wget https://raw.githubusercontent.com/GoogleCloudPlatform/container-developer-workshop/main/labs/python/workstation_config_setup.sh
chmod +x workstation_config_setup.sh
./workstation_config_setup.sh
- Проверьте результаты в разделе «Конфигурации». Переход в состояние «ГОТОВО» займет 2 минуты.

- Откройте раздел «Облачные рабочие станции» в консоли и создайте новый экземпляр.

- Измените имя на
my-workstationи выберите существующую конфигурацию:codeoss-python.

- Проверьте результаты в разделе «Рабочие станции».
Запуск рабочей станции
- Запустите рабочую станцию. Запуск рабочей станции займет несколько минут.

- Разрешите использование сторонних файлов cookie, нажав на значок в адресной строке.


- Нажмите «Сайт не работает?».

- Нажмите «Разрешить файлы cookie».

- После запуска рабочей станции вы увидите запущенную среду разработки Code OSS IDE. На странице «Начало работы» в среде разработки рабочей станции нажмите кнопку «Готово».

3. Создайте новое стартовое приложение на Python.
В этом разделе вы создадите новое приложение на Python.
- Откройте новый терминал.

- Создайте новую директорию и откройте её как рабочее пространство.
mkdir music-service && cd music-service
code-oss-cloud-workstations -r --folder-uri="$PWD"
Если вы видите это сообщение, нажмите кнопку «Разрешить», чтобы иметь возможность скопировать и вставить текст на рабочую станцию.

- Создайте файл с именем
requirements.txtи скопируйте в него следующее содержимое.

Flask
gunicorn
google-cloud-spanner
ptvsd==4.3.2
- Создайте файл с именем
app.pyи вставьте в него следующий код.
import os
from flask import Flask, request, jsonify
from google.cloud import spanner
app = Flask(__name__)
@app.route("/")
def hello_world():
message="Hello, World!"
return message
if __name__ == '__main__':
server_port = os.environ.get('PORT', '8080')
app.run(debug=False, port=server_port, host='0.0.0.0')
- Создайте файл с именем
Dockerfileи вставьте в него следующий код.
FROM python:3.8
ARG FLASK_DEBUG=0
ENV FLASK_DEBUG=$FLASK_DEBUG
ENV FLASK_APP=app.py
WORKDIR /app
COPY requirements.txt .
RUN pip install --trusted-host pypi.python.org -r requirements.txt
COPY . .
ENTRYPOINT ["python3", "-m", "flask", "run", "--port=8080", "--host=0.0.0.0"]
Примечание : Параметр FLASK_DEBUG=1 позволяет автоматически перезагружать изменения кода в приложении Flask на Python. В этом Dockerfile вы можете передать это значение в качестве аргумента сборки.
Создать манифесты
В терминале выполните следующую команду, чтобы сгенерировать файлы skaffold.yaml и deployment.yaml по умолчанию.
- Инициализируйте Skaffold с помощью следующей команды.
skaffold init --generate-manifests
При появлении запроса используйте стрелки для перемещения курсора и пробел для выбора параметров.
Выбирать:
-
8080для порта - Нажмите
yдля сохранения конфигурации.
Обновить конфигурации Skaffold
- Изменить название приложения по умолчанию
- Откройте
skaffold.yaml - Выберите имя образа, которое в данный момент установлено как
dockerfile-image - Щелкните правой кнопкой мыши и выберите «Изменить все вхождения».
- Введите новое имя как
python-app - Дополнительно отредактируйте раздел сборки, чтобы
- Добавьте
docker.buildArgs, чтобы передатьFLASK_DEBUG=1 - Синхронизация настроек для загрузки любых изменений в файлы
*.pyиз IDE в запущенный контейнер.
После внесения изменений раздел build в файле skaffold.yaml будет выглядеть следующим образом:
build:
artifacts:
- image: python-app
docker:
buildArgs:
FLASK_DEBUG: "1"
dockerfile: Dockerfile
sync:
infer:
- '**/*.py'
Изменение файла конфигурации Kubernetes
- Изменить имя по умолчанию
- Откройте файл
deployment.yaml - Выберите имя образа, которое в данный момент установлено как
dockerfile-image - Щелкните правой кнопкой мыши и выберите «Изменить все вхождения».
- Введите новое имя как
python-app
4. Обзор процесса разработки.
После добавления бизнес-логики вы можете развернуть и протестировать свое приложение. В следующем разделе будет продемонстрировано использование плагина Cloud Code. Помимо прочего, этот плагин интегрируется со Skaffold для оптимизации процесса разработки. При развертывании в GKE на следующих шагах Cloud Code и Skaffold автоматически создадут образ контейнера, загрузят его в реестр контейнеров, а затем развернут your приложение в GKE. Это происходит в фоновом режиме, абстрагируя детали от процесса разработки.
Войдите в Google Cloud
- Нажмите на значок Cloud Code и выберите «Войти в Google Cloud»:

- Нажмите «Перейти к входу».

- Проверьте вывод в терминале и откройте ссылку:

- Войдите в систему, используя свои учетные данные студента Qwiklabs.

- Выберите «Разрешить»:

- Скопируйте проверочный код и вернитесь на вкладку «Рабочая станция».

- Вставьте проверочный код и нажмите Enter.

Добавить кластер Kubernetes
- Добавить кластер

- Выберите Google Kubernetes Engine:

- Выберите проект.

- Выберите "python-cluster", созданный при первоначальной настройке.

- Теперь кластер отображается в списке кластеров Kubernetes в разделе Cloud Code. Отсюда вы можете перейти к изучению кластера и просмотреть его содержимое.

Установите идентификатор текущего проекта с помощью gcloud cli.
- Скопируйте идентификатор проекта для этой лабораторной работы со страницы qwiklabs.

- В терминале выполните команду gcloud cli, чтобы установить идентификатор проекта. Замените пример идентификатора проекта перед выполнением команды. Замените идентификатор проекта перед выполнением команды ниже.
gcloud config set project qwiklabs-gcp-project-id
Развертывание в Kubernetes
- В нижней части окна редактора Cloud Shell выберите Cloud Code.

- В появившейся вверху панели выберите «Запустить в Kubernetes» . Если появится запрос, выберите «Да», чтобы использовать текущий контекст Kubernetes.

Эта команда запускает сборку исходного кода, а затем выполняет тесты. Сборка и тестирование займут несколько минут. Эти тесты включают модульные тесты и этап проверки, который проверяет правила, установленные для среды развертывания. Этот этап проверки уже настроен и гарантирует получение предупреждений о проблемах развертывания, даже если вы все еще работаете в среде разработки.
- При первом запуске команды в верхней части экрана появится запрос, спрашивающий, хотите ли вы использовать текущий контекст Kubernetes. Выберите «Да», чтобы принять запрос и использовать текущий контекст.
- Далее появится запрос о том, какой реестр контейнеров использовать. Нажмите Enter, чтобы принять предоставленное значение по умолчанию.
- Чтобы просмотреть ход выполнения и уведомления, выберите вкладку «Вывод» в нижней панели. В раскрывающемся списке выберите «Kubernetes: Запуск/Отладка».

- Выберите «Kubernetes: Запуск/Отладка — Подробная информация» в раскрывающемся списке каналов справа, чтобы просмотреть дополнительные сведения и журналы, транслируемые в режиме реального времени из контейнеров.

После завершения сборки и тестирования в логах вкладки «Вывод» в представлении «Kubernetes: Запуск/Отладка» будет указан URL-адрес http://localhost:8080.
- В терминале Cloud Code наведите курсор на первый URL-адрес в выводе (http://localhost:8080), а затем во всплывающей подсказке выберите «Открыть предварительный просмотр веб-страницы».
- Откроется новая вкладка браузера, на которой отобразится сообщение
Hello, World!
Горячая перезарядка
- Откройте файл
app.py - Измените приветственное сообщение на
Hello from Python
Обратите внимание, что в окне Output , в представлении Kubernetes: Run/Debug , наблюдатель синхронизирует обновленные файлы с контейнером в Kubernetes.
Update initiated Build started for artifact python-app Build completed for artifact python-app Deploy started Deploy completed Status check started Resource pod/python-app-6f646ffcbb-tn7qd status updated to In Progress Resource deployment/python-app status updated to In Progress Resource deployment/python-app status completed successfully Status check succeeded ...
- Если вы переключитесь на
Kubernetes: Run/Debug - Detailedпросмотр, вы заметите, что он распознает изменения файлов, а затем выполняет сборку и повторное развертывание приложения.
files modified: [app.py]
Syncing 1 files for gcr.io/veer-pylab-01/python-app:3c04f58-dirty@sha256:a42ca7250851c2f2570ff05209f108c5491d13d2b453bb9608c7b4af511109bd
Copying files:map[app.py:[/app/app.py]]togcr.io/veer-pylab-01/python-app:3c04f58-dirty@sha256:a42ca7250851c2f2570ff05209f108c5491d13d2b453bb9608c7b4af511109bd
Watching for changes...
[python-app] * Detected change in '/app/app.py', reloading
[python-app] * Restarting with stat
[python-app] * Debugger is active!
[python-app] * Debugger PIN: 744-729-662
- Чтобы увидеть обновленные результаты, обновите вкладку браузера, где вы видели предыдущие результаты.
Отладка
- Перейдите в режим отладки и остановите текущий поток.
Если система спросит, вы можете выбрать опцию очистки после каждого запуска. 
- В нижнем меню нажмите на
Cloud Codeи выберитеDebug on Kubernetes, чтобы запустить приложение в режимеdebug.
- В окне «Подробный просмотр
OutputKubernetes Run/Debug - Detailedобратите внимание, что skaffold развернет это приложение в режиме отладки.
- После завершения процесса вы увидите подключенный отладчик, а на вкладке «Вывод» отобразится сообщение:
Attached debugger to container "python-app-8476f4bbc-h6dsl" successfully., и будет указан URL-адрес http://localhost:8080.
Port forwarding pod/python-app-8bd64cf8b-cskfl in namespace default, remote port 5678 -> http://127.0.0.1:5678
- Цвет нижней строки состояния меняется с синего на оранжевый, указывая на то, что устройство находится в режиме отладки.
- В окне
Kubernetes Run/Debugобратите внимание, что запущен отлаживаемый контейнер.
**************URLs***************** Forwarded URL from service python-app: http://localhost:8080 Debuggable container started pod/python-app-8bd64cf8b-cskfl:python-app (default) Update succeeded ***********************************
Используйте точки останова
- Откройте файл
app.py - Найдите оператор, который гласит
return message - Установите точку останова на этой строке, щелкнув по пустому месту слева от номера строки. Красный индикатор покажет, что точка останова установлена.
- При первом запуске появится запрос на указание местоположения исходного кода внутри контейнера. Это значение связано с каталогами, указанными в Dockerfile.
Нажмите Enter, чтобы принять значение по умолчанию.

Сборка и развертывание приложения займут несколько минут.
- Перезагрузите браузер и обратите внимание, что отладчик останавливает процесс в точке останова и позволяет вам исследовать переменные и состояние приложения, работающего удаленно в GKE.
- Прокрутите вниз до раздела ПЕРЕМЕННЫЕ
- Нажмите на «Локальные переменные», там вы найдете переменную
"message". - Дважды щелкните по имени переменной "message" и во всплывающем окне измените её значение на что-нибудь другое, например,
"Greetings from Python" - Нажмите кнопку «Продолжить» на панели управления отладкой.

- Проверьте ответ в браузере, где теперь отображается обновленное значение, которое вы только что ввели.
- Остановите режим отладки, нажав кнопку «Стоп».
и снимите точку останова, снова щелкнув по ней.
5. Разработка простого REST-сервиса с операциями CRUD.
На этом этапе ваше приложение полностью настроено для контейнерной разработки, и вы прошли базовый рабочий процесс разработки с помощью Cloud Code. В следующих разделах вы попрактикуетесь в применении полученных знаний, добавив конечные точки REST-сервиса, подключающиеся к управляемой базе данных в Google Cloud.
Напишите код для REST-сервиса
Приведённый ниже код создаёт простой REST-сервис, использующий Spanner в качестве базы данных для работы приложения. Создайте приложение, скопировав следующий код в своё приложение.
- Создайте основное приложение, заменив содержимое
app.pyследующим содержимым.
import os
from flask import Flask, request, jsonify
from google.cloud import spanner
app = Flask(__name__)
instance_id = "music-catalog"
database_id = "musicians"
spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
@app.route('/singer', methods=['POST'])
def create():
try:
request_json = request.get_json()
singer_id = request_json['singer_id']
first_name = request_json['first_name']
last_name = request_json['last_name']
def insert_singers(transaction):
row_ct = transaction.execute_update(
f"INSERT Singers (SingerId, FirstName, LastName) VALUES" \
f"({singer_id}, '{first_name}', '{last_name}')"
)
print("{} record(s) inserted.".format(row_ct))
database.run_in_transaction(insert_singers)
return {"Success": True}, 200
except Exception as e:
return e
@app.route('/singer', methods=['GET'])
def get_singer():
try:
singer_id = request.args.get('singer_id')
def get_singer():
first_name = ''
last_name = ''
with database.snapshot() as snapshot:
results = snapshot.execute_sql(
f"SELECT SingerId, FirstName, LastName FROM Singers " \
f"where SingerId = {singer_id}",
)
for row in results:
first_name = row[1]
last_name = row[2]
return (first_name,last_name )
first_name, last_name = get_singer()
return {"first_name": first_name, "last_name": last_name }, 200
except Exception as e:
return e
@app.route('/singer', methods=['PUT'])
def update_singer_first_name():
try:
singer_id = request.args.get('singer_id')
request_json = request.get_json()
first_name = request_json['first_name']
def update_singer(transaction):
row_ct = transaction.execute_update(
f"UPDATE Singers SET FirstName = '{first_name}' WHERE SingerId = {singer_id}"
)
print("{} record(s) updated.".format(row_ct))
database.run_in_transaction(update_singer)
return {"Success": True}, 200
except Exception as e:
return e
@app.route('/singer', methods=['DELETE'])
def delete_singer():
try:
singer_id = request.args.get('singer')
def delete_singer(transaction):
row_ct = transaction.execute_update(
f"DELETE FROM Singers WHERE SingerId = {singer_id}"
)
print("{} record(s) deleted.".format(row_ct))
database.run_in_transaction(delete_singer)
return {"Success": True}, 200
except Exception as e:
return e
port = int(os.environ.get('PORT', 8080))
if __name__ == '__main__':
app.run(threaded=True, host='0.0.0.0', port=port)
Добавить настройки базы данных
Для безопасного подключения к Spanner настройте приложение на использование идентификаторов рабочей нагрузки. Это позволит вашему приложению выступать в качестве собственной учетной записи службы и иметь индивидуальные разрешения при доступе к базе данных.
- Обновите
deployment.yaml. Добавьте следующий код в конец файла (убедитесь, что вы сохранили отступы табуляции, как в примере ниже).
serviceAccountName: python-ksa
nodeSelector:
iam.gke.io/gke-metadata-server-enabled: "true"
После внесения изменений раздел спецификации должен выглядеть следующим образом.
spec:
containers:
- name: python-app
image: python-app
serviceAccountName: python-ksa
nodeSelector:
iam.gke.io/gke-metadata-server-enabled: "true"
Развертывание и проверка приложения
- В нижней части окна редактора Cloud Shell выберите
Cloud Code, а затем в верхней части экрана выберитеDebug on Kubernetes. - После завершения сборки и тестирования на вкладке «Вывод» отображается сообщение:
Resource deployment/python-app status completed successfully, а также указан URL-адрес: «Перенаправленный URL-адрес из сервиса python-app: http://localhost:8080». - Добавьте пару записей.
В терминале CloudShell выполните следующую команду.
curl -X POST http://localhost:8080/singer -H 'Content-Type: application/json' -d '{"first_name":"Cat","last_name":"Meow", "singer_id": 6}'
- Проверьте выполнение запроса GET, запустив следующую команду в терминале.
curl -X GET http://localhost:8080/singer?singer_id=6
- Тестовое удаление: Теперь попробуйте удалить запись, выполнив следующую команду. При необходимости измените значение item-id.
curl -X DELETE http://localhost:8080/singer?singer_id=6
This throws an error message
500 Internal Server Error
Выявите и устраните проблему.
- Включите режим отладки и найдите проблему. Вот несколько советов:
- Мы знаем, что что-то не так с оператором DELETE, поскольку он не возвращает желаемый результат. Поэтому вам следует установить точку останова в
app.pyв методеdelete_singer. - Выполните пошаговое выполнение программы и наблюдайте за переменными на каждом шаге, чтобы увидеть значения локальных переменных в левом окне.
- Чтобы отслеживать определенные значения, такие как
singer_idиrequest.args, добавьте эти переменные в окно «Отслеживание».
- Обратите внимание, что значение, присвоенное
singer_id, равноNone. Измените код, чтобы исправить эту проблему.
Исправленный фрагмент кода будет выглядеть так.
@app.route('/delete-singer', methods=['DELETE', 'GET'])
def delete_singer():
try:
singer_id = request.args.get('singer_id')
- После перезапуска приложения проверьте еще раз, попробовав удалить файл.
- Остановите сеанс отладки, нажав на красный квадрат на панели инструментов отладки.

6. Уборка
Поздравляем! В этой лабораторной работе вы создали с нуля новое приложение на Python и настроили его для эффективной работы с контейнерами. Затем вы развернули и отладили свое приложение в удаленном кластере GKE, следуя тому же процессу разработки, что и в традиционных стеках приложений.
После завершения лабораторной работы необходимо провести уборку:
- Удалите файлы, использованные в лабораторной работе.
cd ~ && rm -rf ~/music-service
- Удалите проект, чтобы удалить всю связанную с ним инфраструктуру и ресурсы.
