1. Обзор
В этой лабораторной работе демонстрируются функции и возможности, предназначенные для оптимизации рабочего процесса разработки для инженеров-программистов, которым поручено разрабатывать приложения Python в контейнерной среде. Типичная разработка контейнеров требует от пользователя понимания деталей контейнеров и процесса сборки контейнеров. Кроме того, разработчикам обычно приходится прерывать рабочий процесс, выходя из своей IDE для тестирования и отладки своих приложений в удаленных средах. С помощью инструментов и технологий, упомянутых в этом руководстве, разработчики могут эффективно работать с контейнерными приложениями, не выходя из своей IDE.
Что вы узнаете
В этой лабораторной работе вы изучите методы разработки с использованием контейнеров в GCP, в том числе:
- Создание нового стартового приложения Python
- Пройдите процесс разработки
- Разработайте простой сервис отдыха CRUD.
2. Настройка и требования
Самостоятельная настройка среды
- Войдите в Google Cloud Console и создайте новый проект или повторно используйте существующий. Если у вас еще нет учетной записи Gmail или Google Workspace, вам необходимо ее создать .
- Имя проекта — это отображаемое имя для участников этого проекта. Это строка символов, не используемая API Google, и вы можете обновить ее в любое время.
- Идентификатор проекта должен быть уникальным для всех проектов Google Cloud и неизменяемым (нельзя изменить после его установки). Cloud Console автоматически генерирует уникальную строку; обычно тебя не волнует, что это такое. В большинстве лабораторий кода вам потребуется указать идентификатор проекта (обычно он обозначается как
PROJECT_ID
), поэтому, если он вам не нравится, создайте другой случайный идентификатор или попробуйте свой собственный и посмотрите, доступен ли он. Затем он «замораживается» после создания проекта. - Существует третье значение — номер проекта , который используют некоторые API. Подробнее обо всех трех этих значениях читайте в документации .
- Далее вам необходимо включить выставление счетов в Cloud Console, чтобы использовать облачные ресурсы/API. Прохождение этой лаборатории кода не должно стоить много, если вообще стоит. Чтобы отключить ресурсы и не платить за выставление счетов за пределами этого руководства, следуйте инструкциям по «очистке», которые можно найти в конце лаборатории кода. Новые пользователи 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)')
Получить исходный код
- Исходный код этой лабораторной работы находится в мастерской разработчика контейнеров в GoogleCloudPlatform на GitHub. Клонируйте его с помощью команды ниже, а затем перейдите в каталог.
git clone https://github.com/GoogleCloudPlatform/container-developer-workshop.git &&
cd container-developer-workshop/labs/python
mkdir music-service && cd music-service
cloudshell workspace .
Если терминал НЕ открыт, используйте комбинацию клавиш `ctrl+``, чтобы открыть новое окно терминала.
Предоставление инфраструктуры, используемой в этой лаборатории
В ходе этой лабораторной работы вы развернете код в GKE и получите доступ к данным, хранящимся в базе данных Spanner. Приведенный ниже сценарий установки подготовит для вас эту инфраструктуру. Процесс подготовки займет более 10 минут. Вы можете продолжить выполнение следующих нескольких шагов, пока выполняется настройка.
../setup.sh
3. Создайте новое начальное приложение Python.
- Создайте файл с именем
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 позволяет автоматически перезагружать изменения кода в приложение Python flask. Этот 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 в работающий контейнер.
После изменений раздел сборки в файле 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 автоматически создадут образ вашего контейнера, отправят его в реестр контейнеров, а затем развернут ваше приложение в GKE. Это происходит «за кулисами», отвлекая детали от процесса разработки.
Развертывание в Kubernetes
- На панели внизу редактора Cloud Shell выберите Cloud Code 
- На появившейся вверху панели выберите «Выполнить в Kubernetes» . При появлении запроса выберите «Да», чтобы использовать текущий контекст Kubernetes.
Эта команда запускает сборку исходного кода, а затем запускает тесты. Сборка и тесты займут несколько минут. Эти тесты включают модульные тесты и этап проверки, на котором проверяются правила, установленные для среды развертывания. Этот этап проверки уже настроен, и он гарантирует, что вы получите предупреждение о проблемах с развертыванием, даже если вы все еще работаете в своей среде разработки.
- При первом запуске команды в верхней части экрана появится приглашение с вопросом, хотите ли вы использовать текущий контекст Kubernetes, выберите «Да», чтобы принять и использовать текущий контекст.
- Затем появится приглашение с вопросом, какой реестр контейнеров использовать. Нажмите Enter, чтобы принять предоставленное значение по умолчанию.
- Выберите вкладку «Вывод» на нижней панели, чтобы просмотреть ход выполнения и уведомления.
- Выберите «Kubernetes: Run/Debug — Detailed» в раскрывающемся списке каналов справа, чтобы просмотреть дополнительные сведения и журналы, транслируемые в реальном времени из контейнеров.
Когда сборка и тесты завершены, на вкладке «Вывод» отображается сообщение: Attached debugger to container "python-app-8476f4bbc-h6dsl" successfully.
, и отображается 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
.
- Обратите внимание, что в окне
Kubernetes Run/Debug - Detailed
представлениеOutput
» skaffold развернет это приложение в режиме отладки.
- При первом запуске появится запрос, где находится источник внутри контейнера. Это значение связано с каталогами в Dockerfile.
Нажмите Enter, чтобы принять значение по умолчанию
Сборка и развертывание приложения займет пару минут.
- Когда процесс завершится. Вы заметите прикрепленный отладчик.
Port forwarding pod/python-app-8bd64cf8b-cskfl in namespace default, remote port 5678 -> http://127.0.0.1:5678
- Нижняя строка состояния меняет цвет с синего на оранжевый, указывая на то, что система находится в режиме отладки.
- Обратите внимание, что в представлении
Kubernetes Run/Debug
запускается контейнер отладки.
**************URLs***************** Forwarded URL from service python-app: http://localhost:8080 Debuggable container started pod/python-app-8bd64cf8b-cskfl:python-app (default) Update succeeded ***********************************
Используйте точки останова
- Откройте файл
app.py
- Найдите оператор, который читает
return message
- Добавьте точку останова в эту строку, щелкнув пустое место слева от номера строки. Красный индикатор покажет, что точка останова установлена.
- Перезагрузите браузер и обратите внимание, что отладчик останавливает процесс в точке останова и позволяет вам исследовать переменные и состояние приложения, которое работает удаленно в GKE.
- Нажмите вниз в раздел ПЕРЕМЕННЫЕ.
- Нажмите «Локальные», там вы найдете переменную
"message"
. - Дважды щелкните имя переменной «сообщение» и во всплывающем окне измените значение на другое, например
"Greetings from Python"
- Нажмите кнопку «Продолжить» на панели управления отладкой.
- Просмотрите ответ в своем браузере, который теперь показывает обновленное значение, которое вы только что ввели.
- Остановите режим «Отладка», нажав кнопку «Стоп».
и удалите точку останова, снова нажав на точку останова.
5. Разработка простой службы отдыха CRUD
На этом этапе ваше приложение полностью настроено для контейнерной разработки, и вы прошли базовый рабочий процесс разработки с помощью Cloud Code. В следующих разделах вы попрактикуете полученные знания, добавив конечные точки службы отдыха, подключающиеся к управляемой базе данных в Google Cloud.
Код остальной службы
Код ниже создает простую службу отдыха, которая использует Spanner в качестве базы данных, поддерживающей приложение. Создайте приложение, скопировав в него следующий код.
- Создайте основное приложение, заменив
app.py
следующим содержимым.
import os
from flask import Flask, request, jsonify
from google.cloud import spanner
app = Flask(__name__)
instance_id = "music-catalog"
database_id = "musicians"
spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
@app.route('/singer', methods=['POST'])
def create():
try:
request_json = request.get_json()
singer_id = request_json['singer_id']
first_name = request_json['first_name']
last_name = request_json['last_name']
def insert_singers(transaction):
row_ct = transaction.execute_update(
f"INSERT Singers (SingerId, FirstName, LastName) VALUES" \
f"({singer_id}, '{first_name}', '{last_name}')"
)
print("{} record(s) inserted.".format(row_ct))
database.run_in_transaction(insert_singers)
return {"Success": True}, 200
except Exception as e:
return e
@app.route('/singer', methods=['GET'])
def get_singer():
try:
singer_id = request.args.get('singer_id')
def get_singer():
first_name = ''
last_name = ''
with database.snapshot() as snapshot:
results = snapshot.execute_sql(
f"SELECT SingerId, FirstName, LastName FROM Singers " \
f"where SingerId = {singer_id}",
)
for row in results:
first_name = row[1]
last_name = row[2]
return (first_name,last_name )
first_name, last_name = get_singer()
return {"first_name": first_name, "last_name": last_name }, 200
except Exception as e:
return e
@app.route('/singer', methods=['PUT'])
def update_singer_first_name():
try:
singer_id = request.args.get('singer_id')
request_json = request.get_json()
first_name = request_json['first_name']
def update_singer(transaction):
row_ct = transaction.execute_update(
f"UPDATE Singers SET FirstName = '{first_name}' WHERE SingerId = {singer_id}"
)
print("{} record(s) updated.".format(row_ct))
database.run_in_transaction(update_singer)
return {"Success": True}, 200
except Exception as e:
return e
@app.route('/singer', methods=['DELETE'])
def delete_singer():
try:
singer_id = request.args.get('singer')
def delete_singer(transaction):
row_ct = transaction.execute_update(
f"DELETE FROM Singers WHERE SingerId = {singer_id}"
)
print("{} record(s) deleted.".format(row_ct))
database.run_in_transaction(delete_singer)
return {"Success": True}, 200
except Exception as e:
return e
port = int(os.environ.get('PORT', 8080))
if __name__ == '__main__':
app.run(threaded=True, host='0.0.0.0', port=port)
Добавить конфигурации базы данных
Чтобы безопасно подключиться к Spanner, настройте приложение на использование удостоверений рабочей нагрузки. Это позволяет вашему приложению действовать как собственная учетная запись службы и иметь индивидуальные разрешения при доступе к базе данных.
- Обновите
deployment.yaml
. Добавьте следующий код в конец файла (убедитесь, что отступы табуляции сохранены, как в примере ниже):
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
, добавьте эти переменные в окно Watch.
- Обратите внимание, что значение, присвоенное
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 container-developer-workshop
- Удалите проект, чтобы удалить всю связанную инфраструктуру и ресурсы.