Python'da HTTP Cloud Functions

1. Giriş

b158ce75c3cccd6d.png

Python; veri bilimciler, web uygulaması geliştiricileri, sistem yöneticileri ve daha pek çok kişi tarafından kullanılan popüler bir açık kaynak programlama dilidir.

Cloud Functions, etkinlik odaklı, sunucusuz bir işlem platformudur. Cloud Functions, kaynak sağlama veya değişen gereksinimleri karşılamak için ölçeklendirme yapma konusunda endişelenmeden kodunuzu yazmanıza olanak tanır.

İki tür Cloud Functions işlevi vardır:

  • HTTP işlevleri HTTP isteklerine yanıt verir. Bu codelab'de birkaç çift oluşturacaksınız.
  • Arka plan işlevleri, Cloud Pub/Sub'da yayınlanan bir mesaj veya Cloud Storage'a yüklenen bir dosya gibi etkinlikler tarafından tetiklenir. Bu laboratuvarda bu konuya değinmeyeceğiz, ancak belgelerde daha fazla bilgi bulabilirsiniz.

efb3268e3b74ed4f.png

Bu codelab'de, Python'da kendi Cloud Functions işlevlerinizi nasıl oluşturacağınız açıklanmaktadır.

Neler oluşturacaksınız?

Bu codelab'de, HTTP aracılığıyla çağrıldığında "Python Destekli" logo:

a7aaf656b78050fd.png

Neler öğreneceksiniz?

  • HTTP Cloud Functions işlevi yazma.
  • Bağımsız değişken alan bir HTTP Cloud Functions işlevi yazma.
  • HTTP Cloud Functions işlevini test etme.
  • İşlevi denemek için yerel bir Python HTTP sunucusu çalıştırma.
  • Görüntü döndüren HTTP Cloud Functions işlevi yazma.

2. Kurulum ve şartlar

Kendi hızınızda ortam kurulumu

  1. Google Cloud Console'da oturum açıp yeni bir proje oluşturun veya mevcut bir projeyi yeniden kullanın. Gmail veya Google Workspace hesabınız yoksa hesap oluşturmanız gerekir.

fbef9caa1602edd0.png

a99b7ace416376c4.png

5e3ff691252acf41.png

  • Proje adı, bu projenin katılımcıları için görünen addır. Google API'leri tarafından kullanılmayan bir karakter dizesidir. İstediğiniz zaman güncelleyebilirsiniz.
  • Proje Kimliği, tüm Google Cloud projelerinde benzersizdir ve değiştirilemez (belirlendikten sonra değiştirilemez). Cloud Console, otomatik olarak benzersiz bir dize oluşturur. bunun ne olduğunu umursamıyorsunuz. Çoğu codelab'de proje kimliğinizi (genellikle PROJECT_ID olarak tanımlanır) belirtmeniz gerekir. Oluşturulan kimliği beğenmezseniz rastgele bir kimlik daha oluşturabilirsiniz. Alternatif olarak, kendi ölçümünüzü deneyip mevcut olup olmadığına bakabilirsiniz. Bu adımdan sonra değiştirilemez ve proje süresince kalır.
  • Bilginiz olması açısından, bazı API'lerin kullandığı üçüncü bir değer, yani Proje Numarası daha vardır. Bu değerlerin üçü hakkında daha fazla bilgiyi belgelerde bulabilirsiniz.
  1. Sonraki adımda, Cloud kaynaklarını/API'lerini kullanmak için Cloud Console'da faturalandırmayı etkinleştirmeniz gerekir. Bu codelab'i çalıştırmanın maliyeti, yüksek değildir. Bu eğitim dışında faturalandırmanın tekrarlanmasını önlemek amacıyla kaynakları kapatmak için oluşturduğunuz kaynakları silebilir veya projeyi silebilirsiniz. Yeni Google Cloud kullanıcıları 300 ABD doları değerindeki ücretsiz denemeden yararlanabilir.

Cloud Shell'i Başlatma

Google Cloud, dizüstü bilgisayarınızdan uzaktan çalıştırılabilse de bu codelab'de Cloud'da çalışan bir komut satırı ortamı olan Cloud Shell'i kullanacaksınız.

Cloud Shell'i etkinleştirme

  1. Cloud Console'da, Cloud Shell'i etkinleştir 853e55310c205094.png simgesini tıklayın.

3c1dabeca90e44e5.png

Cloud Shell'i ilk kez başlatıyorsanız ne olduğunu açıklayan bir ara ekran gösterilir. Ara bir ekran görüntülendiyse Devam'ı tıklayın.

9c92662c6a846a5c.png

Temel hazırlık ve Cloud Shell'e bağlanmak yalnızca birkaç dakika sürer.

9f0e51b578fecce5.png

Gereken tüm geliştirme araçları bu sanal makinede yüklüdür. 5 GB boyutunda kalıcı bir ana dizin sunar ve Google Cloud'da çalışarak ağ performansını ve kimlik doğrulamasını büyük ölçüde iyileştirir. Bu codelab'deki çalışmalarınızın tamamı olmasa bile büyük bir kısmı tarayıcıyla yapılabilir.

Cloud Shell'e bağlandıktan sonra kimliğinizin doğrulandığını ve projenin proje kimliğinize ayarlandığını göreceksiniz.

  1. Kimlik doğrulamanızın tamamlandığını onaylamak için Cloud Shell'de aşağıdaki komutu çalıştırın:
gcloud auth list

Komut çıkışı

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. gcloud komutunun projenizi bildiğini onaylamak için Cloud Shell'de aşağıdaki komutu çalıştırın:
gcloud config list project

Komut çıkışı

[core]
project = <PROJECT_ID>

Doğru değilse aşağıdaki komutla ayarlayabilirsiniz:

gcloud config set project <PROJECT_ID>

Komut çıkışı

Updated property [core/project].

Cloud Functions ve Cloud Build API'lerinin etkinleştirildiğinden emin olun

Cloud Functions ve Cloud Build API'lerinin etkinleştirildiğinden emin olmak için Cloud Shell'de aşağıdaki komutu çalıştırın:

gcloud services enable \
  cloudfunctions.googleapis.com \
  cloudbuild.googleapis.com

Not: Cloud Build, gcloud functions deploy komutu ile çağrılır ve kodunuzu otomatik olarak bir container görüntüsünde derler.

Kaynak kodu indirme

Cloud Shell terminalinden aşağıdaki komutları çalıştırın:

REPO_NAME="codelabs"
REPO_URL="https://github.com/GoogleCloudPlatform/$REPO_NAME"
SOURCE_DIR="cloud-functions-python-http"

git clone --no-checkout --filter=blob:none --depth=1 $REPO_URL
cd $REPO_NAME
git sparse-checkout set $SOURCE_DIR
git checkout
cd $SOURCE_DIR

Kaynak dizinin içeriğini kontrol edin:

ls

Şu dosyalara sahip olmanız gerekir:

main.py  python-powered.png  test_main.py  web_app.py

3. HTTP Cloud Functions ile Tanışın

Python'daki HTTP Cloud İşlevleri, normal Python işlevleri olarak yazılır. İşlev, genellikle request adlı tek bir flask.Request bağımsız değişkenini kabul etmelidir.

main.py

import flask


def hello_world(request: flask.Request) -> flask.Response:
    """HTTP Cloud Function.

    Returns:
    - "Hello World! 👋"
    """
    response = "Hello World! 👋"

    return flask.Response(response, mimetype="text/plain")

# ...

Dosyayı tercih ettiğiniz komut satırı düzenleyiciyle (nano, vim veya emacs) açabilirsiniz. Kaynak dizini çalışma alanı olarak ayarladıktan sonra dosyayı Cloud Shell Düzenleyici'de de açabilirsiniz:

cloudshell open-workspace .

gcloud functions deploy komutunu kullanarak bu işlevi HTTP Cloud Functions işlevi olarak dağıtalım:

FUNCTION_NAME="hello_world"

gcloud functions deploy $FUNCTION_NAME \
  --runtime python312 \
  --trigger-http \
  --allow-unauthenticated

Komut çıkışı:

...
Deploying function (may take a while - up to 2 minutes)...done.
availableMemoryMb: 256
...
entryPoint: FUNCTION_NAME
httpsTrigger:
  url: https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME
...

gcloud functions deploy seçenekleriyle ilgili notlar:

  • --runtime: Bu, dil çalışma zamanını belirtir. Python için bu, şu anda python37, python38, python39, python310 veya python312 olabilir. Çalışma zamanları bölümünü inceleyin.
  • --trigger-http: İşleve bir uç nokta atanır. Uç noktaya gönderilen HTTP istekleri (POST, PUT, GET, DELETE ve OPTIONS), işlevin yürütülmesini tetikler.
  • --allow-unauthenticated: İşlev herkese açık olacak ve kimlik doğrulaması kontrol edilmeden tüm arayanlara izin verilecektir.
  • Daha fazla bilgi edinmek için gcloud Functions dağıtımı başlıklı makaleyi inceleyin.

İşlevi test etmek için yukarıdaki komut çıkışında gösterilen httpsTrigger.url URL'sini tıklayabilirsiniz. Ayrıca, URL'yi programlı bir şekilde alabilir ve aşağıdaki komutları kullanarak işlevi çağırabilirsiniz:

URL=$(gcloud functions describe $FUNCTION_NAME --format "value(httpsTrigger.url)")
curl -w "\n" $URL

Aşağıdaki sonucu alırsınız:

Hello World! 👋

4. Bağımsız değişken alan bir HTTP Cloud Functions işlevi yazma

İşlevler, bağımsız değişkenleri kabul ettiğinde daha çok yönlüdür. Şimdi, name parametresini destekleyen yeni bir hello_name fonksiyonu tanımlayalım:

main.py

# ...

def hello_name(request: flask.Request) -> flask.Response:
    """HTTP Cloud Function.

    Returns:
    - "Hello {NAME}! 🚀" if "name=NAME" is defined in the GET request
    - "Hello World! 🚀" otherwise
    """
    name = request.args.get("name", "World")
    response = f"Hello {name}! 🚀"

    return flask.Response(response, mimetype="text/plain")

# ...

Bu yeni işlevi dağıtalım:

FUNCTION_NAME="hello_name"

gcloud functions deploy $FUNCTION_NAME \
  --runtime python312 \
  --trigger-http \
  --allow-unauthenticated

Komut çıkışı:

...
Deploying function (may take a while - up to 2 minutes)...done.
availableMemoryMb: 256
...
entryPoint: FUNCTION_NAME
httpsTrigger:
  url: https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME
...

İşlevi test etmek için yukarıdaki komut çıkışında gösterilen httpsTrigger.url URL'sini tıklayabilirsiniz. Ayrıca, URL'yi programlı bir şekilde alabilir ve aşağıdaki komutları kullanarak işlevi çağırabilirsiniz:

URL=$(gcloud functions describe $FUNCTION_NAME --format "value(httpsTrigger.url)")
curl -w "\n" $URL

Varsayılan sonucu alırsınız:

Hello World! 🚀

name bağımsız değişkeni ayarlanmadığı için varsayılan sonucu alıyorsunuz. URL'ye bir parametre ekleyin:

curl -w "\n" $URL?name=YOUR%20NAME

Bu kez özel yanıtınızı alacaksınız:

Hello YOUR NAME! 🚀

Bir sonraki adım, kaynak kodu güncellendiğinde işlevlerinizin amaçlandığı gibi çalışmaya devam etmesini sağlamak için birim testleri eklemektir.

5. Test yazma

Python'daki HTTP Cloud Functions işlevleri, standart kitaplıktaki unittest modülü kullanılarak test edilir. İşlevinizi test etmek için emülatör veya başka bir simülasyon çalıştırmanız gerekmez. Normal Python kodu yeterlidir.

hello_world ve hello_name işlevleri için bir test şu şekilde görünür:

test_main.py

import unittest
import unittest.mock

import main


class TestHello(unittest.TestCase):
    def test_hello_world(self):
        request = unittest.mock.Mock()

        response = main.hello_world(request)
        assert response.status_code == 200
        assert response.get_data(as_text=True) == "Hello World! 👋"

    def test_hello_name_no_name(self):
        request = unittest.mock.Mock(args={})

        response = main.hello_name(request)
        assert response.status_code == 200
        assert response.get_data(as_text=True) == "Hello World! 🚀"

    def test_hello_name_with_name(self):
        name = "FirstName LastName"
        request = unittest.mock.Mock(args={"name": name})

        response = main.hello_name(request)
        assert response.status_code == 200
        assert response.get_data(as_text=True) == f"Hello {name}! 🚀"
  1. Python testleri, diğer Python dosyalarıyla aynı şekilde yazılır. İlk olarak bir dizi içe aktarma işlemi yapılır, ardından sınıf ve işlev tanımlanır.
  2. Test beyanı class TestHello(TestCase) biçimindedir. unittest.TestCase öğesinden devralan bir sınıf olmalıdır.
  3. Test sınıfında, her biri test_ ile başlamalıdır ve bağımsız test durumlarını temsil eden yöntemler bulunur.
  4. Her test durumu, request parametresiyle dalga geçerek (test için gereken belirli verilerle sahte bir nesneyle değiştirerek) işlevlerimizden birini test eder.
  5. Her işlev çağrıldıktan sonra test, beklediğimiz gibi olduğundan emin olmak için HTTP yanıtını kontrol eder.

main.py, flask alanına bağlı olduğundan Flask çerçevesinin test ortamınızda yüklü olduğundan emin olun:

pip install flask

Flask'ı yüklediğinizde aşağıdakine benzer bir sonuç görüntülenir:

Collecting flask
...
Successfully installed ... flask-3.0.2 ...

Bu testleri yerel olarak çalıştırın:

python -m unittest

Üç birim testinin başarılı olması gerekir:

...
----------------------------------------------------------------------
Ran 3 tests in 0.001s

OK

Şimdi, "Python Destekli" işlevini döndüren yeni bir işlev oluşturacaksınız logosundan sonra.

6. "Python Destekli" HTTP Cloud Functions işlevi

"Python Destekli" işlevini döndürerek yeni işlevi biraz daha eğlenceli hale getirelim her istek için bir resim ekleyin:

a7aaf656b78050fd.png

Aşağıdaki listede bunun için gereken kod gösterilmektedir:

main.py

# ...

def python_powered(request: flask.Request) -> flask.Response:
    """HTTP Cloud Function.

    Returns:
    - The official "Python Powered" logo
    """
    return flask.send_file("python-powered.png")

Yeni bir python_powered işlevi dağıtın:

FUNCTION_NAME="python_powered"

gcloud functions deploy $FUNCTION_NAME \
  --runtime python312 \
  --trigger-http \
  --allow-unauthenticated

Komut çıkışı:

...
Deploying function (may take a while - up to 2 minutes)...done.
availableMemoryMb: 256
...
entryPoint: FUNCTION_NAME
httpsTrigger:
  url: https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME
...

İşlevi test etmek için yukarıdaki komut çıkışında gösterilen httpsTrigger.url URL'sini tıklayın. Her şey düzgün çalışıyorsa "Python Destekli" mesajını görürsünüz. logosunu yeni bir tarayıcı sekmesinde açın!

Ardından, dağıtımdan önce işlevinizi yerel olarak çalıştırıp deneyebilmeniz için bir uygulama oluşturacaksınız.

7. İşlevi yerel olarak çalıştırma

Bir web uygulaması oluşturup işlevinizi bir rota üzerinden çağırarak bir HTTP işlevini yerel olarak çalıştırabilirsiniz. Kodu, fonksiyonunuzla aynı dizine ekleyebilirsiniz. web_app.py adlı dosya şu içeriğe sahip:

web_app.py

import flask

import main

app = flask.Flask(__name__)


@app.get("/")
def index():
    return main.python_powered(flask.request)


if __name__ == "__main__":
    # Local development only
    # Run "python web_app.py" and open http://localhost:8080
    app.run(host="localhost", port=8080, debug=True)
  1. Bu dosya bir Flask uygulaması oluşturur.
  2. Temel URL'de, index() adlı bir işlevle işlenen bir rota kaydeder.
  3. Ardından index() işlevi, mevcut isteği ileterek python_powered işlevimizi çağırır.

Flask çerçevesinin geliştirme ortamınızda yüklü olduğundan emin olun:

pip install flask

Flask'ı yüklediğinizde aşağıdakine benzer bir sonuç görüntülenir:

Collecting flask
...
Successfully installed ... flask-3.0.2 ...

Bu uygulamayı yerel olarak çalıştırmak için aşağıdaki komutu çalıştırın:

python web_app.py

Şimdi, tarayıcınızda web uygulamasını test etmek için Cloud Shell Web Önizlemesi'ni kullanın. Cloud Shell'de "Web Önizlemesi"ni tıklayın düğmesini tıklayın ve "8080 bağlantı noktasında önizle"yi seçin:

6c9ff9e5c692c58e.gif

Cloud Shell, proxy hizmetindeki önizleme URL'sini yeni bir tarayıcı penceresinde açar. Web önizlemesi, HTTPS üzerinden erişimi yalnızca kullanıcı hesabınızla kısıtlar. Her şey düzgün çalışıyorsa "Python Destekli" mesajını görürsünüz. logoyu kullanmanızı öneririz.

8e5c3ead11cfd103.png

8. Tebrikler!

b158ce75c3cccd6d.png

Web isteklerini Flask çerçevesiyle işleyen deyimsel işlevler kullanarak HTTP Cloud Functions'ı dağıttınız.

Cloud Functions fiyatlandırması, işlevinizin çağrılma sıklığına göre belirlenir. Sık çalışmayan işlevler için ücretsiz katman da buna dahildir. Cloud Functions işlevlerini test ettikten sonra gcloud aracını kullanarak bunları silebilirsiniz:

gcloud functions delete hello_world --quiet
gcloud functions delete hello_name --quiet
gcloud functions delete python_powered --quiet

İşlevleri Google Cloud konsolundan da silebilirsiniz.

Python'da Cloud Functions'ı kullanmaktan keyif alacağınızı umuyoruz.