App Engine Blobstore'dan Cloud Storage'a Taşıma (Modül 16)

1. Genel Bakış

Serverless Migration Station codelab serisi (kendi hızınızda ilerleyebileceğiniz uygulamalı eğitimler) ve ilgili videolar, Google Cloud sunucusuz geliştiricilerinin bir veya daha fazla taşıma işleminde (özellikle eski hizmetlerden uzaklaşma) onlara rehberlik ederek uygulamalarını modernize etmelerine yardımcı olmayı amaçlar. Böylece uygulamalarınız daha taşınabilir hale gelir ve daha fazla seçenek ve esneklik elde edersiniz. Bu sayede daha geniş bir Cloud ürünleri yelpazesiyle entegrasyon yapabilir ve bunlara erişebilir, ayrıca daha yeni dil sürümlerine daha kolay yükseltme yapabilirsiniz. Başlangıçta en eski Cloud kullanıcılarına, özellikle de App Engine (standart ortam) geliştiricilerine odaklanan bu seri, Cloud Functions ve Cloud Run gibi diğer sunucusuz platformları veya uygun olan diğer platformları da kapsayacak kadar geniştir.

Bu codelab'de, App Engine Blobstore'dan Cloud Storage'a nasıl geçiş yapacağınızı öğreneceksiniz. Aşağıdaki kaynaklardan dolaylı taşıma işlemleri de vardır:

Adım adım daha fazla bilgi için ilgili taşıma modüllerine bakın.

Demoda aşağıdaki işlemleri yapmayı öğreneceksiniz:

  • App Engine Blobstore API'sinin/kitaplığının kullanımını ekleme
  • Kullanıcı yüklemelerini Blobstore hizmetinde depolama
  • Cloud Storage'a geçiş için sonraki adıma hazırlanma

Gerekenler

Anket

Bu eğitimden nasıl yararlanacaksınız?

Yalnızca okuyun Okuyun ve alıştırmaları tamamlayın

Python deneyiminizi nasıl değerlendirirsiniz?

Başlangıç düzeyi Orta düzey İleri düzey

Google Cloud hizmetlerini kullanma deneyiminizi nasıl değerlendirirsiniz?

Başlangıç düzeyi Orta düzey İleri düzey

2. Arka plan

Bu codelab, 15. modüldeki örnek uygulamayla başlar ve Blobstore (ve NDB)'dan Cloud Storage (ve Cloud NDB)'a nasıl geçiş yapılacağını gösterir. Taşıma işlemi, App Engine'in eski paket hizmetlerine olan bağımlılıkların değiştirilmesini içerir. Bu sayede, uygulamalarınızı isterseniz başka bir Cloud sunucusuz platformuna veya başka bir barındırma platformuna taşıyabilirsiniz.

Bu taşıma işlemi, bu serideki diğer taşıma işlemlerine kıyasla biraz daha fazla çaba gerektirir. Blobstore, orijinal webapp çerçevesine bağımlıdır. Bu nedenle örnek uygulama, Flask yerine webapp2 çerçevesini kullanır. Bu eğitimde Cloud Storage, Cloud NDB, Flask ve Python 3'e geçiş işlemleri ele alınmaktadır.

Uygulama, son kullanıcı "ziyaretlerini" kaydetmeye ve en son on ziyareti göstermeye devam eder ancak önceki (Modül 15) codelab, Blobstore kullanımına uyum sağlamak için yeni işlevler ekledi: Uygulama, son kullanıcılardan "ziyaretlerine" karşılık gelen bir yapıyı (dosya) yüklemelerini ister. Kullanıcılar bu işlemi yapabilir veya kapsamı dışında kalmayı seçmek için "atla"yı seçebilir. Kullanıcının kararından bağımsız olarak, sonraki sayfa bu uygulamanın önceki sürümleriyle aynı çıkışı oluşturarak en son ziyaretleri gösterir. İlgili yapay öğeleri içeren ziyaretlerde, ziyaretin yapay öğesini görüntülemek için bir "görüntüle" bağlantısı bulunur. Bu codelab'de, açıklanan işlevler korunarak daha önce bahsedilen taşıma işlemleri uygulanır.

3. Kurulum/Ön çalışma

Eğitimin ana bölümüne geçmeden önce projemizi ayarlayalım, kodu alalım ve ardından temel uygulamayı dağıtalım. Böylece çalışan bir kodla başladığımızdan emin oluruz.

1. Proje oluşturma

15. modül uygulamasını zaten dağıttıysanız aynı projeyi (ve kodu) yeniden kullanmanızı öneririz. Alternatif olarak, yepyeni bir proje oluşturabilir veya mevcut başka bir projeyi yeniden kullanabilirsiniz. Projenin etkin bir faturalandırma hesabı olduğundan ve App Engine'in etkinleştirildiğinden emin olun.

2. Temel örnek uygulamayı alma

Bu codelab'in ön koşullarından biri, çalışan bir Modül 15 örnek uygulamanızın olmasıdır. Uygulamanız yoksa Modül 15 "START" klasöründen (aşağıdaki bağlantı) indirebilirsiniz. Bu codelab'de her adımda size yol gösterilir ve Modül 16 "FINISH" klasöründekine benzer bir kodla tamamlanır.

15. modülün BAŞLANGIÇ dosyalarının dizini şu şekilde görünmelidir:

$ ls
README.md       app.yaml        main-gcs.py     main.py         templates

main-gcs.py dosyası, Modül 15'teki main.py dosyasının alternatif bir sürümüdür. Bu dosya, projenin kimliğine göre bir uygulamanın atanan URL'sinin varsayılanından farklı bir Cloud Storage paketi seçilmesine olanak tanır: PROJECT_ID.appspot.com. Bu dosyanın bu (Modül 16) codelab'de bir rolü yoktur. Ancak isterseniz benzer taşıma tekniklerini bu dosyaya da uygulayabilirsiniz.

3. Temel uygulamayı (yeniden) dağıtma

Şimdi uygulamanız gereken kalan ön çalışma adımları:

  1. gcloud komut satırı aracını tekrar inceleme
  2. Örnek uygulamayı gcloud app deploy ile yeniden dağıtma
  3. Uygulamanın App Engine'de sorunsuz çalıştığını doğrulama

Bu adımları başarıyla uyguladıktan sonra Modül 15 uygulamanızın çalıştığını onaylayın. İlk sayfada, kullanıcılar bir formla karşılanır. Bu formda, ziyaret yapay nesnesi dosyasının yüklenmesi istenir ve "atla" düğmesiyle bu işlemi atlama seçeneği sunulur:

f5b5f9f19d8ae978.png

Kullanıcılar bir dosya yükledikten veya bu adımı atladıktan sonra uygulama, tanıdık "en son ziyaretler" sayfasını oluşturur:

f5ac6b98ee8a34cb.png

Yapı içeren ziyaretlerde, yapıyı görüntülemek (veya indirmek) için ziyaret zaman damgasının sağında bir "görüntüle" bağlantısı bulunur. Uygulamanın işlevselliğini onayladıktan sonra App Engine'in eski hizmetlerinden (webapp2, NDB, Blobstore) modern alternatiflere (Flask, Cloud NDB, Cloud Storage) geçiş yapmaya hazırsınız demektir.

4. Yapılandırma dosyalarını güncelleme

Uygulamamızın güncellenmiş sürümü için üç yapılandırma dosyası kullanılır. Gerekli görevler şunlardır:

  1. app.yaml uygulamasında gerekli yerleşik üçüncü taraf kitaplıklarını güncelleyin ve Python 3'e geçişe olanak tanıyın.
  2. Yerleşik olmayan tüm gerekli kitaplıkları belirten bir requirements.txt ekleyin.
  3. Uygulamanın hem yerleşik hem de yerleşik olmayan üçüncü taraf kitaplıklarını desteklemesi için appengine_config.py ekleyin.

app.yaml

libraries bölümünü güncelleyerek app.yaml dosyanızı düzenleyin. jinja2 öğesini kaldırıp grpcio, setuptools ve ssl öğelerini ekleyin. Üç kitaplık için de mevcut olan en yeni sürümü seçin. Ayrıca Python 3 runtime yönergesini de ekleyin ancak açıklama satırı yapın. İşlemi tamamladığınızda, ekranınız aşağıdaki gibi görünmelidir (Python 3.9'u seçtiyseniz):

ÖNCE:

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

libraries:
- name: jinja2
  version: latest

AFTER:

#runtime: python39
runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

libraries:
- name: grpcio
  version: latest
- name: setuptools
  version: latest
- name: ssl
  version: latest

Değişiklikler, temel olarak App Engine sunucularında bulunan Python 2 yerleşik kitaplıkları ile ilgilidir (böylece bunları kendiniz paketlemek zorunda kalmazsınız). Jinja2'yi kaldırdık çünkü reqs.txt dosyasına ekleyeceğimiz Flask ile birlikte geliyor. Cloud NDB ve Cloud Storage gibi Google Cloud istemci kitaplıkları kullanıldığında grpcio ve setuptools gerekir. Son olarak, Cloud Storage'ın kendisi ssl kitaplığını gerektirir. Üst kısımdaki açıklama satırı yapılmış çalışma zamanı yönergesi, bu uygulamayı Python 3'e taşımaya hazır olduğunuzda kullanılır. Bu konuyu bu eğitimin sonunda ele alacağız.

requirements.txt

Flask çerçevesi ile Cloud NDB ve Cloud Storage istemci kitaplıklarını gerektiren bir requirements.txt dosyası ekleyin. Bu bileşenlerin hiçbiri yerleşik değildir. Dosyayı şu içerikle oluşturun:

flask
google-cloud-ndb
google-cloud-storage

Python 2 App Engine çalışma zamanı, yerleşik olmayan üçüncü taraf kitaplıklarının kendi kendine paketlenmesini gerektirir. Bu nedenle, bu kitaplıkları lib klasörüne yüklemek için aşağıdaki komutu yürütün:

pip install -t lib -r requirements.txt

Geliştirme makinenizde hem Python 2 hem de Python 3 varsa bu kitaplıkların Python 2 sürümlerini almak için pip2 komutunu kullanmanız gerekebilir. Python 3'e geçtikten sonra artık kendi paketlerinizi oluşturmanız gerekmez.

appengine_config.py

Yerleşik ve yerleşik olmayan üçüncü taraf kitaplıklarını destekleyen bir appengine_config.py dosyası ekleyin. Dosyayı şu içerikle oluşturun:

import pkg_resources
from google.appengine.ext import vendor

# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)
# Add libraries to pkg_resources working set to find the distribution.
pkg_resources.working_set.add_entry(PATH)

Az önce tamamlanan adımlar, App Engine belgelerinin Python 2 uygulamaları için kitaplık yükleme bölümünde listelenen adımlara benzer veya aynı olmalıdır. Daha açık belirtmek gerekirse appengine_config.py içeriği, buradaki 5. adımda yer alan içerikle eşleşmelidir.

Yapılandırma dosyalarıyla ilgili çalışma tamamlandığına göre uygulamaya geçelim.

5. Uygulama dosyalarını değiştirme

İçe aktarılanlar

main.py için yapılan ilk değişiklikler, değiştirilen tüm öğelerin kaldırılmasını içerir. Değişiklikler şu şekildedir:

  1. webapp2, Flask ile değiştirildi
  2. webapp2_extras üzerinden Jinja2 kullanmak yerine Flask ile birlikte gelen Jinja2'yi kullanın.
  3. App Engine Blobstore ve NDB'nin yerini Cloud NDB ve Cloud Storage aldı.
  4. webapp uygulamasındaki Blobstore işleyicileri, io standart kitaplık modülü, Flask ve werkzeug yardımcı programlarının bir kombinasyonuyla değiştirilir.
  5. Blobstore, varsayılan olarak uygulamanızın URL'sinin (PROJECT_ID.appspot.com) adını taşıyan bir Cloud Storage paketine yazar. Cloud Storage istemci kitaplığına taşıma yaptığımız için tam olarak aynı paket adını belirtmek üzere proje kimliğini almak için google.auth kullanılır. (Paket adı artık sabit kodlu olmadığından adı değiştirebilirsiniz.)

ÖNCE:

import webapp2
from webapp2_extras import jinja2
from google.appengine.ext import blobstore, ndb
from google.appengine.ext.webapp import blobstore_handlers

main.py dosyasındaki mevcut içe aktarma bölümünü aşağıdaki kod snippet'iyle değiştirerek yukarıdaki listede yer alan değişiklikleri uygulayın.

AFTER:

import io

from flask import (Flask, abort, redirect, render_template,
        request, send_file, url_for)
from werkzeug.utils import secure_filename

import google.auth
from google.cloud import exceptions, ndb, storage

Başlatma ve gereksiz Jinja2 desteği

Değiştirilecek bir sonraki kod bloğu, webapp2_extras'dan Jinja2 kullanımını belirten BaseHandler bloğudur. Jinja2, Flask ile birlikte gelir ve varsayılan şablon motorudur. Bu nedenle, Jinja2'yi kaldırmanız gerekir.

16. modül tarafında, eski uygulamada bulunmayan nesneleri örneklendirin. Buna Flask uygulamasını başlatma ve Cloud NDB ile Cloud Storage için API istemcileri oluşturma dahildir. Son olarak, Cloud Storage paketi adını yukarıda içe aktarma bölümünde açıklandığı şekilde oluştururuz. Bu güncellemeler uygulanmadan önce ve uygulandıktan sonraki durum şu şekildedir:

ÖNCE:

class BaseHandler(webapp2.RequestHandler):
    'Derived request handler mixing-in Jinja2 support'
    @webapp2.cached_property
    def jinja2(self):
        return jinja2.get_jinja2(app=self.app)

    def render_response(self, _template, **context):
        self.response.write(self.jinja2.render_template(_template, **context))

AFTER:

app = Flask(__name__)
ds_client = ndb.Client()
gcs_client = storage.Client()
_, PROJECT_ID = google.auth.default()
BUCKET = '%s.appspot.com' % PROJECT_ID

Datastore erişimini güncelleme

Cloud NDB, App Engine NDB ile büyük ölçüde uyumludur. Daha önce bahsedilen bir fark, API istemcisine duyulan ihtiyaçtır. Diğer bir fark ise Datastore erişiminin API istemcisinin Python bağlam yöneticisi tarafından kontrol edilmesini gerektirmesidir. Bu, Cloud NDB istemci kitaplığını kullanan tüm Datastore erişim çağrılarının yalnızca Python with bloklarında gerçekleşebileceği anlamına gelir.

Bu, değişikliklerden biridir. Diğer değişiklik ise Blobstore ve nesnelerinin (ör. BlobKey) Cloud Storage tarafından desteklenmemesidir. Bu nedenle, file_blob yerine ndb.StringProperty kullanın. Aşağıda, veri modeli sınıfı ve bu değişiklikleri yansıtan güncellenmiş store_visit() ve fetch_visits() işlevleri verilmiştir:

ÖNCE:

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)
    file_blob = ndb.BlobKeyProperty()

def store_visit(remote_addr, user_agent, upload_key):
    'create new Visit entity in Datastore'
    Visit(visitor='{}: {}'.format(remote_addr, user_agent),
            file_blob=upload_key).put()

def fetch_visits(limit):
    'get most recent visits'
    return Visit.query().order(-Visit.timestamp).fetch(limit)

AFTER:

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)
    file_blob = ndb.StringProperty()

def store_visit(remote_addr, user_agent, upload_key):
    'create new Visit entity in Datastore'
    with ds_client.context():
        Visit(visitor='{}: {}'.format(remote_addr, user_agent),
                file_blob=upload_key).put()

def fetch_visits(limit):
    'get most recent visits'
    with ds_client.context():
        return Visit.query().order(-Visit.timestamp).fetch(limit)

Şimdiye kadar yapılan değişikliklerin görsel bir gösterimini aşağıda bulabilirsiniz:

a8f74ca392275822.png

İşleyicileri güncelleme

Yükleme işleyici

webapp2'da işleyiciler sınıflarken Flask'ta işlevlerdir. Flask, HTTP fiil yöntemi yerine işlevi süslemek için fiili kullanır. Blobstore ve webapp işleyicilerinin yerini Cloud Storage'ın yanı sıra Flask ve yardımcı programlarının işlevleri alır:

ÖNCE:

class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
    'Upload blob (POST) handler'
    def post(self):
        uploads = self.get_uploads()
        blob_id = uploads[0].key() if uploads else None
        store_visit(self.request.remote_addr, self.request.user_agent, blob_id)
        self.redirect('/', code=307)

AFTER:

@app.route('/upload', methods=['POST'])
def upload():
    'Upload blob (POST) handler'
    fname = None
    upload = request.files.get('file', None)
    if upload:
        fname = secure_filename(upload.filename)
        blob = gcs_client.bucket(BUCKET).blob(fname)
        blob.upload_from_file(upload, content_type=upload.content_type)
    store_visit(request.remote_addr, request.user_agent, fname)
    return redirect(url_for('root'), code=307)

Bu güncellemeyle ilgili bazı notlar:

  • Dosya çıktıları artık blob_id yerine varsa dosya adıyla (fname), yoksa None ile tanımlanır (kullanıcı dosya yüklemeyi devre dışı bıraktı).
  • Blobstore işleyicileri, yükleme işlemini kullanıcılarından soyutlar ancak Cloud Storage bunu yapmaz. Bu nedenle, dosyanın blob nesnesini ve konumunu (paket) ayarlayan yeni eklenen kodu ve gerçek yüklemeyi gerçekleştiren çağrıyı görebilirsiniz. (upload_from_file()).
  • webapp2, uygulama dosyasının alt kısmında bir yönlendirme tablosu kullanırken Flask rotaları her bir dekore edilmiş işleyicide bulunur.
  • Her iki işleyici de HTTP 307 dönüş koduyla POST isteğini korurken ana sayfaya ( / ) yönlendirerek işlevlerini tamamlar.

İndirme işleyici

İndirme işleyicisini güncelleme işlemi, yükleme işleyicisine benzer bir kalıp izler ancak incelenecek çok daha az kod vardır. Blobstore ve webapp işlevlerini Cloud Storage ve Flask eşdeğerleriyle değiştirin:

ÖNCE:

class ViewBlobHandler(blobstore_handlers.BlobstoreDownloadHandler):
    'view uploaded blob (GET) handler'
    def get(self, blob_key):
        self.send_blob(blob_key) if blobstore.get(blob_key) else self.error(404)

AFTER:

@app.route('/view/<path:fname>')
def view(fname):
    'view uploaded blob (GET) handler'
    blob = gcs_client.bucket(BUCKET).blob(fname)
    try:
        media = blob.download_as_bytes()
    except exceptions.NotFound:
        abort(404)
    return send_file(io.BytesIO(media), mimetype=blob.content_type)

Bu güncellemeyle ilgili notlar:

  • Flask, işleyici işlevlerini rotalarıyla süslerken webapp bunu en alttaki yönlendirme tablosunda yapar. Bu nedenle, Flask'ın () kalıp eşleştirme söz dizimi (('/view/([^/]+)?') ile Flask'ın ('/view/<path:fname>') kalıp eşleştirme söz dizimini tanıyın.
  • Yükleme işleyicisinde olduğu gibi, Blobstore işleyicileri tarafından soyutlanan işlevler için Cloud Storage tarafında biraz daha fazla çalışma yapılması gerekir. Bu çalışmalar, söz konusu dosyanın (blob) tanımlanması ve ikili programın açıkça indirilmesi ile Blobstore işleyicisinin tek send_blob() yöntem çağrısıdır.
  • Her iki durumda da, bir yapı bulunamazsa kullanıcıya HTTP 404 hatası döndürülür.

Ana işleyici

Ana uygulamada yapılan son değişiklikler ana işleyicide gerçekleşir. webapp2 HTTP fiil yöntemleri, işlevlerini birleştiren tek bir işlevle değiştirilir. MainHandler sınıfını root() işleviyle değiştirin ve webapp2 yönlendirme tablosunu aşağıda gösterildiği gibi kaldırın:

ÖNCE:

class MainHandler(BaseHandler):
    'main application (GET/POST) handler'
    def get(self):
        self.render_response('index.html',
                upload_url=blobstore.create_upload_url('/upload'))

    def post(self):
        visits = fetch_visits(10)
        self.render_response('index.html', visits=visits)

app = webapp2.WSGIApplication([
    ('/', MainHandler),
    ('/upload', UploadHandler),
    ('/view/([^/]+)?', ViewBlobHandler),
], debug=True)

AFTER:

@app.route('/', methods=['GET', 'POST'])
def root():
    'main application (GET/POST) handler'
    context = {}
    if request.method == 'GET':
        context['upload_url'] = url_for('upload')
    else:
        context['visits'] = fetch_visits(10)
    return render_template('index.html', **context)

Ayrı get() ve post() yöntemleri yerine, aslında root() içinde bir if-else ifadesidir. Ayrıca root() tek bir işlev olduğundan hem GET hem de POST için şablonu oluşturmak üzere yalnızca bir çağrı yapılır. Bu, webapp2'te mümkün değildir.

main.py için yapılan bu ikinci ve son değişiklik grubunun görsel bir temsilini aşağıda bulabilirsiniz:

5ec38818c32fec2.png

(isteğe bağlı) Geriye dönük uyumluluk "iyileştirmesi"

Yukarıda oluşturulan çözüm mükemmel bir şekilde çalışır ancak yalnızca sıfırdan başlıyorsanız ve Blobstore tarafından oluşturulan dosyalarınız yoksa. Uygulamayı, dosyaları BlobKey yerine dosya adına göre tanımlayacak şekilde güncellediğimiz için tamamlanan Modül 16 uygulaması, Blobstore dosyalarını olduğu gibi görüntüleyemez. Başka bir deyişle, bu taşıma işlemini gerçekleştirirken geriye dönük uyumsuz bir değişiklik yaptık. Şimdi, bu boşluğu doldurmaya çalışan main.py adlı aracın main-migrate.py adlı alternatif bir sürümünü (depoda bulunur) sunuyoruz.

Blobstore tarafından oluşturulan dosyaları destekleyen ilk "uzantı", BlobKeyProperty içeren bir veri modelidir (Cloud Storage tarafından oluşturulan dosyalar için StringProperty'e ek olarak):

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)
    file_blob = ndb.BlobKeyProperty()  # backwards-compatibility
    file_gcs  = ndb.StringProperty()

file_blob özelliği, Blobstore tarafından oluşturulan dosyaları tanımlamak için kullanılırken file_gcs, Cloud Storage dosyaları için kullanılır. Yeni ziyaretler oluştururken file_blob yerine file_gcs parametresinde açıkça bir değer depolayın. Böylece store_visit biraz farklı görünür:

ÖNCE:

def store_visit(remote_addr, user_agent, upload_key):
    'create new Visit entity in Datastore'
    with ds_client.context():
        Visit(visitor='{}: {}'.format(remote_addr, user_agent),
                file_blob=upload_key).put()

AFTER:

def store_visit(remote_addr, user_agent, upload_key):
    'create new Visit entity in Datastore'
    with ds_client.context():
        Visit(visitor='{}: {}'.format(remote_addr, user_agent),
                file_gcs=upload_key).put()

En son ziyaretleri getirirken verileri şablona göndermeden önce "normalleştirin":

ÖNCE:

@app.route('/', methods=['GET', 'POST'])
def root():
    'main application (GET/POST) handler'
    context = {}
    if request.method == 'GET':
        context['upload_url'] = url_for('upload')
    else:
        context['visits'] = fetch_visits(10)
    return render_template('index.html', **context)

AFTER:

@app.route('/', methods=['GET', 'POST'])
def root():
    'main application (GET/POST) handler'
    context = {}
    if request.method == 'GET':
        context['upload_url'] = url_for('upload')
    else:
        context['visits'] = etl_visits(fetch_visits(10))
    return render_template('index.html', **context)

Ardından, file_blob veya file_gcs (ya da her ikisinin de) mevcut olup olmadığını onaylayın. Kullanılabilir bir dosya varsa mevcut olanı seçin ve bu tanımlayıcıyı kullanın (Blobstore tarafından oluşturulan dosyalar için BlobKey veya Cloud Storage tarafından oluşturulan dosyalar için dosya adı). "Cloud Storage tarafından oluşturulan dosyalar" ifadesi, Cloud Storage istemci kitaplığı kullanılarak oluşturulan dosyaları ifade eder. Blobstore da Cloud Storage'a yazar ancak bu durumda bunlar Blobstore tarafından oluşturulan dosyalar olur.

Şimdi daha önemli bir soruya geçelim: Son kullanıcı için verileri normalleştirmek veya ETL (ayıklama, dönüştürme ve yükleme) amacıyla kullanılan bu etl_visits() işlevi nedir? Şöyle görünür:

def etl_visits(visits):
    return [{
            'visitor': v.visitor,
            'timestamp': v.timestamp,
            'file_blob': v.file_gcs if hasattr(v, 'file_gcs') \
                    and v.file_gcs else v.file_blob
            } for v in visits]

Muhtemelen beklediğiniz gibi görünüyordur: Kod, tüm ziyaretler arasında döngü oluşturur ve her ziyaret için ziyaretçi ve zaman damgası verilerini olduğu gibi alır, ardından file_gcs veya file_blob olup olmadığını kontrol eder ve varsa bunlardan birini (veya ikisi de yoksa None) seçer.

main.py ve main-migrate.py arasındaki farkları gösteren bir görseli aşağıda bulabilirsiniz:

718b05b2adadb2e1.png

Blobstore tarafından oluşturulan dosyalar olmadan sıfırdan başlıyorsanız main.py kullanın. Ancak geçiş yapıyorsanız ve hem Blobstore hem de Cloud Storage tarafından oluşturulan dosyaları desteklemek istiyorsanız kendi uygulamalarınız için geçiş planlamanıza yardımcı olacak senaryoları nasıl ele alacağınızı gösteren bir örnek için main-migrate.py adresine göz atın. Karmaşık taşıma işlemleri yaparken özel durumlar ortaya çıkabilir. Bu nedenle, bu örnekte gerçek verilerle gerçek uygulamaları modernize etmeye daha fazla önem verilmiştir.

6. Özet/Temizleme

Bu bölümde, uygulamayı dağıtarak, amaçlandığı gibi çalıştığını ve tüm yansıtılan çıkışlarda çalıştığını doğrulayarak bu codelab'i tamamlayacağız. Uygulama doğrulamasından sonra temizleme adımlarını uygulayın ve sonraki adımları değerlendirin.

Uygulamayı dağıtma ve doğrulama

Uygulamanızı yeniden dağıtmadan önce, kendi paketlediğiniz üçüncü taraf kitaplıklarını lib klasörüne almak için pip install -t lib -r requirements.txt komutunu çalıştırdığınızdan emin olun. Geriye dönük uyumlu çözümü çalıştırmak istiyorsanız önce main-migrate.py adlı dosyayı main.py olarak yeniden adlandırın. Şimdi gcloud app deploy uygulamasını çalıştırın ve uygulamanın Modül 15 uygulamasıyla aynı şekilde çalıştığını onaylayın. Form ekranı şu şekilde görünür:

f5b5f9f19d8ae978.png

En son ziyaretler sayfası şu şekilde görünür:

f5ac6b98ee8a34cb.png

App Engine Blobstore'u Cloud Storage ile, App Engine NDB'yi Cloud NDB ile ve webapp2'yi Flask ile değiştirdiğiniz bu codelab'i tamamladığınız için tebrikler. Kodunuz artık FINISH (Modül 16) klasöründeki kodla eşleşmelidir. Alternatif main-migrate.py de bu klasörde yer alır.

Python 3 "migration"

Bu uygulamayı Python 3'e taşımak için app.yaml dosyasının üst kısmındaki açıklama satırı yapılmış Python 3 runtime yönergesi yeterlidir. Kaynak kodun kendisi zaten Python 3 ile uyumlu olduğundan bu konuda herhangi bir değişiklik yapılması gerekmez. Bunu Python 3 uygulaması olarak dağıtmak için aşağıdaki adımları uygulayın:

  1. app.yaml dosyasının üst kısmındaki Python 3 runtime yönergesinin açıklama işaretini kaldırın.
  2. app.yaml dosyasındaki diğer tüm satırları silin.
  3. appengine_config.py dosyasını silin. (Python 3 çalışma zamanında kullanılmaz)
  4. Varsa lib klasörünü silin. (Python 3 çalışma zamanında gerekli değildir)

Temizleme

Genel

Şimdilik işiniz bittiyse faturalandırılmamak için App Engine uygulamanızı devre dışı bırakmanızı öneririz. Ancak daha fazla test veya deneme yapmak isterseniz App Engine platformunun ücretsiz kotası vardır. Bu kullanım katmanını aşmadığınız sürece sizden ücret alınmaz. Bu, işlem için geçerlidir ancak ilgili App Engine hizmetleri için de ücret alınabilir. Bu nedenle, daha fazla bilgi için fiyatlandırma sayfasını inceleyin. Bu taşıma işlemi diğer Cloud hizmetlerini içeriyorsa bunlar ayrı olarak faturalandırılır. Her iki durumda da, geçerliyse aşağıdaki "Bu codelab'e özel" bölümüne bakın.

App Engine gibi bir Google Cloud sunucusuz bilgi işlem platformuna dağıtım yapmanın küçük derleme ve depolama maliyetleri olduğunu belirtmek isteriz. Cloud Build'un, Cloud Storage gibi kendi ücretsiz kotası vardır. Bu resmin depolanması, kotanın bir kısmını kullanır. Ancak, ücretsiz katmanın sunulmadığı bir bölgede yaşıyor olabilirsiniz. Bu nedenle, olası maliyetleri en aza indirmek için depolama alanı kullanımınıza dikkat edin. İncelemeniz gereken belirli Cloud Storage "klasörleri" şunlardır:

  • console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/images
  • console.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com
  • Yukarıdaki depolama alanı bağlantıları, PROJECT_ID ve *LOC*asyonunuza bağlıdır. Örneğin, uygulamanız ABD'de barındırılıyorsa "us" olur.

Öte yandan, bu uygulamaya veya diğer ilgili taşıma codelab'lerine devam etmeyecekseniz ve her şeyi tamamen silmek istiyorsanız projenizi kapatın.

Bu codelab'e özel

Aşağıda listelenen hizmetler bu codelab'e özeldir. Daha fazla bilgi için her ürünün belgelerine bakın:

15. modülden 16. modüle geçiş yaptıysanız Blobstore'da verileriniz olmaya devam eder. Bu nedenle, yukarıda Blobstore'un fiyatlandırma bilgilerine yer verilmiştir.

Sonraki adımlar

Bu eğitimde ele alınanların yanı sıra, eski paket hizmetlerden geçiş yapmaya odaklanan diğer taşıma modülleri şunlardır:

  • 2. modül: App Engine ndb'den Cloud NDB'ye taşıma
  • 7-9. modüller: App Engine görev sırası push görevlerinden Cloud Tasks'e geçiş
  • 12-13. modüller: App Engine Memcache'ten Cloud Memorystore'a geçiş
  • 18 ve 19. modüller: App Engine görev sırasından (çekme görevleri) Cloud Pub/Sub'a geçiş

App Engine artık Google Cloud'daki tek sunucusuz platform değildir. Küçük veya sınırlı işlevselliğe sahip bir App Engine uygulamanız varsa ve bunu bağımsız bir mikro hizmete dönüştürmek istiyorsanız ya da monolitik bir uygulamayı birden çok yeniden kullanılabilir bileşene bölmek istiyorsanız Cloud Functions'a geçmeyi düşünebilirsiniz. Kapsayıcılaştırma, uygulama geliştirme iş akışınızın bir parçası haline geldiyse (özellikle de bir CI/CD [sürekli entegrasyon/sürekli teslim veya dağıtım] ardışık düzeninden oluşuyorsa) Cloud Run'a geçiş yapabilirsiniz. Bu senaryolar aşağıdaki modüllerde ele alınmaktadır:

  • App Engine'den Cloud Functions'a geçiş: 11. Modül'e bakın.
  • App Engine'den Cloud Run'a geçiş: Uygulamanızı Docker ile container mimarisine almak için 4. modüle, container'lar, Docker bilgisi veya Dockerfile olmadan yapmak için 5. modüle bakın.

Başka bir sunucusuz platforma geçiş yapmak isteğe bağlıdır. Herhangi bir değişiklik yapmadan önce uygulamalarınız ve kullanım alanlarınız için en iyi seçenekleri değerlendirmenizi öneririz.

Bir sonraki adımda hangi taşıma modülünü kullanmayı düşünürseniz düşünün, tüm Serverless Migration Station içeriklerine (codelab'ler, videolar, kaynak kodu [varsa]) açık kaynak deposundan erişebilirsiniz. Deponun README sayfasında, hangi taşıma işlemlerinin dikkate alınması gerektiği ve taşıma modüllerinin ilgili "sırası" hakkında da bilgi verilmektedir.

7. Ek kaynaklar

Codelab sorunları/geri bildirimleri

Bu codelab ile ilgili herhangi bir sorunla karşılaşırsanız lütfen bildirimde bulunmadan önce sorununuzu arayın. Yeni sorunları aramak ve oluşturmak için bağlantılar:

Veri taşımayla ilgili kaynaklar

Modül 15 (BAŞLANGIÇ) ve Modül 16 (BİTİŞ) için depo klasörlerinin bağlantılarını aşağıdaki tabloda bulabilirsiniz. Bu dosyalara, klonlayabileceğiniz veya ZIP dosyası olarak indirebileceğiniz tüm App Engine codelab taşıma işlemlerinin deposundan da erişebilirsiniz.

Codelab

Python 2

Python 3

15. Modül

code

Yok

Modül 16 (bu codelab)

code

(Python 2 ile aynı)

Online kaynaklar

Aşağıda, bu eğitimle alakalı olabilecek online kaynaklar verilmiştir:

App Engine Blobstore ve Cloud Storage

App Engine platformu

Diğer bulut bilgileri

Python

Videolar

Lisans

Bu çalışma, Creative Commons Attribution 2.0 Genel Amaçlı Lisans ile lisans altına alınmıştır.