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

1. Genel Bakış

Serverless Migration Station serisi codelab'ler (kendi hızınızda ilerleyebileceğiniz, uygulamalı eğitimler) ve ilgili videolar, Google Cloud sunucusuz geliştiricilerin öncelikle eski hizmetlerden uzaklaşarak bir veya daha fazla taşıma işlemi yapmalarına rehberlik ederek uygulamalarını modernleştirmelerine yardımcı olmayı amaçlar. Bu sayede uygulamalarınız daha taşınabilir hale gelir, daha fazla seçenek ve esneklik elde edersiniz. Böylece daha geniş bir Cloud ürün yelpazesiyle entegrasyon yapabilir, bu ürünlere erişebilir ve yeni dil sürümlerine daha kolay yükseltebilirsiniz. Başlangıçta öncelikle App Engine (standart ortam) geliştiricileri olmak üzere en eski Cloud kullanıcılarına odaklanılsa da bu seri, Cloud Functions ve Cloud Run gibi diğer sunucusuz platformları veya uygun olduğu durumlarda başka platformları da kapsayacak kadar geniştir.

Bu codelab'de App Engine Blobstore'dan Cloud Storage'a nasıl geçeceğiniz açıklanmaktadır. Aşağıdaki kaynaklardan da örtülü taşıma işlemleri yapılabilir:

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

Bu demoda aşağıdaki işlemleri yapmayı öğreneceksiniz:

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

Gerekenler

Anket

Bu eğitimi nasıl kullanacaksınız?

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

Python ile ilgili deneyiminizi nasıl değerlendirirsiniz?

Yeni başlayan Orta düzey Uzman

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

Başlangıç Orta İleri

2. Arka plan

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

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

Uygulama, son kullanıcı "ziyaretlerini" kaydetmeye ve en son on tanesini göstermeye devam ediyor ancak önceki (15. Modül) codelab'de Blobstore kullanımına uygun yeni işlevler eklenmişti: Uygulama, son kullanıcılardan "ziyaretlerine" karşılık gelen bir yapıyı (dosya) yüklemelerini istiyor. Kullanıcılar bu işlemi yapabilir veya devre dışı bırakmak için "atla"yı seçebilir. Kullanıcının kararı ne olursa olsun, sonraki sayfada bu uygulamanın önceki sürümleriyle aynı çıktı oluşturulur ve en son ziyaretler gösterilir. Bir diğer nokta ise ilgili yapay nesneleri içeren ziyaretlerde, ziyaretin yapay nesnesini görüntülemek için "görüntüle" bağlantısının bulunmasıdır. Bu codelab, daha önce bahsedilen taşıma işlemlerini açıklanan işlevselliği koruyarak uygular.

3. Kurulum/Ön Hazırlık

Eğitimin ana bölümüne geçmeden önce projemizi oluşturalım, kodu alalım ve temel uygulamayı dağıtalım. Böylece, çalışır durumda olan bir kodla başladığımızı biliriz.

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ına sahip olduğundan ve App Engine'in etkinleştirildiğinden emin olun.

2. Temel örnek uygulamayı edinme

Bu codelab'in ön koşullarından biri, çalışan bir 15. Modül örnek uygulamasına sahip olmaktır. Bu uygulamaya sahip değilseniz 15. Modül "BAŞLANGIÇ" klasöründen (aşağıdaki bağlantı) edinebilirsiniz. Bu codelab, sizi her adımda yönlendirir ve 16. modüldeki "FINISH" klasöründekine benzer bir kodla sonuçlanır.

15. Modül 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ı, 15. modüldeki main.py dosyasının alternatif bir sürümüdür. Bu sürüm, projenin kimliğine (PROJECT_ID.appspot.com) göre bir uygulamanın varsayılan olarak atanan URL'sinden farklı bir Cloud Storage paketi seçilmesine olanak tanır. Bu dosya, bu (16. Modül) codelab'de hiçbir rol oynamaz. Ancak istenirse benzer taşıma teknikleri bu dosyaya uygulanabilir.

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

Şimdi yapmanız gereken kalan ön hazırlık adımları:

  1. gcloud komut satırı aracı hakkında bilgi edinin
  2. Örnek uygulamayı gcloud app deploy ile yeniden dağıtın.
  3. Uygulamanın App Engine'de sorunsuz çalıştığını onaylayın.

Bu adımları başarıyla uygulayıp 15. Modül uygulamanızın çalıştığını onayladıktan sonra. İlk sayfada, kullanıcıları bir formla karşılıyoruz. Bu formda, yüklemek için bir ziyaret yapıtı dosyası isteniyor ve devre dışı bırakma seçeneği olarak "atla" düğmesi sunuluyor:

f5b5f9f19d8ae978.png

Kullanıcılar bir dosyayı yükledikten veya atladıktan sonra uygulama, "en son ziyaretler" sayfasını gösterir:

f5ac6b98ee8a34cb.png

Bir yapıtın yer aldığı ziyaretlerde, yapıtı görüntülemek (veya indirmek) için ziyaretin zaman damgasının sağında "görüntüle" bağlantısı bulunur. Uygulamanın işlevselliğini onayladıktan sonra App Engine eski hizmetlerinden (webapp2, NDB, Blobstore) güncel 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ünde üç yapılandırma dosyası kullanılır. Yapılması gereken işlemler şunlardır:

  1. app.yaml'daki gerekli yerleşik üçüncü taraf kitaplıklarını güncelleyin ve Python 3'e geçiş için kapıyı açık bırakı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

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

ÖNCESİ:

runtime: python27
threadsafe: yes
api_version: 1

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

libraries:
- name: jinja2
  version: latest

SONRASI:

#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 öncelikle App Engine sunucularında kullanılabilen Python 2 yerleşik kitaplıklarıyla ilgilidir (bu nedenle bunları kendiniz paketlemeniz gerekmez). Jinja2'yi kaldırdık. Çünkü bu kitaplık, 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 için ssl kitaplığı gerekir. En üstteki yorum satırı haline getirilmiş çalışma zamanı yönergesi, bu uygulamayı Python 3'e taşımaya hazır olduğunuzda kullanılmak içindir. Bu konuyu eğitimin sonunda ele alacağız.

requirements.txt

Flask çerçevesi, Cloud NDB ve Cloud Storage istemci kitaplıklarını gerektiren bir requirements.txt dosyası ekleyin. Bu kitaplıkların hiçbiri yerleşik değildir. Aşağıdaki içeriğe sahip dosyayı oluşturun:

flask
google-cloud-ndb
google-cloud-storage

Python 2 App Engine çalışma zamanı, yerleşik olmayan üçüncü taraf kitaplıkların kendiliğinden 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 3 varsa bu kitaplıkların Python 2 sürümlerini aldığınızdan emin olmak için pip2 komutunu kullanmanız gerekebilir. Python 3'e yükselttikten sonra artık kendiniz paket 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. Aşağıdaki içeriğe sahip dosyayı 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 dokümanlarının Python 2 uygulamaları için kitaplık yükleme bölümünde listelenen adımlara benzer veya aynı olmalıdır. Daha spesifik olarak, appengine_config.py içeriği, oradaki 5. adımda yer alan içerikle eşleşmelidir.

Yapılandırma dosyalarıyla ilgili çalışmalar tamamlandı. Şimdi uygulamaya geçelim.

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

İçe aktarılanlar

main.py ile ilgili ilk değişiklik grubunda, değiştirilen tüm öğeler çıkarılır. Değişiklikler şu şekildedir:

  1. webapp2 yerine Flask kullanılıyor
  2. webapp2_extras konumundaki Jinja2'yi kullanmak yerine Flask ile birlikte gelen Jinja2'yi kullanın.
  3. App Engine Blobstore ve NDB, Cloud NDB ve Cloud Storage ile değiştirildi
  4. webapp içindeki Blobstore işleyicilerinin yerini io standart kitaplık modülü, Flask ve werkzeug yardımcı programlarının birleşimi almıştır.
  5. Blobstore, varsayılan olarak uygulamanızın URL'siyle (PROJECT_ID.appspot.com) aynı adı taşıyan bir Cloud Storage paketine yazar. Cloud Storage istemci kitaplığına taşıdığımız için google.auth, tam olarak aynı paket adını belirtmek üzere proje kimliğini almak için kullanılır. (Paket adı artık sabit kodlanmadığı için değiştirilebilir.)

ÖNCESİ:

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

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

SONRASI:

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, BaseHandler ile webapp2_extras arasındaki Jinja2 kullanımını belirten koddur. Jinja2, Flask ile birlikte geldiği ve varsayılan şablon oluşturma motoru olduğu için bu gereksizdir. Bu nedenle kaldırın.

16. modül tarafında, eski uygulamada bulunmayan nesneleri örneklendirin. Bu işlem, Flask uygulamasını ilk kullanıma hazırlamayı ve Cloud NDB ile Cloud Storage için API istemcileri oluşturmayı içerir. Son olarak, yukarıda içe aktarma bölümünde açıklandığı gibi Cloud Storage paketi adını bir araya getiririz. Bu güncellemeler uygulanmadan önce ve uygulandıktan sonraki görünüm:

ÖNCESİ:

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))

SONRASI:

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

Veri deposu erişimini güncelleme

Cloud NDB, App Engine NDB ile büyük ölçüde uyumludur. Daha önce ele alınan bir fark, API istemcisi gerekliliğidir. Diğer bir fark ise ikincisinin, Datastore erişiminin API istemcisinin Python bağlam yöneticisi tarafından kontrol edilmesini gerektirmesidir. Bu, Cloud NDB istemci kitaplığı kullanılarak yapılan 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 biri; diğeri ise Blobstore ve nesnelerinin (ör.BlobKey) Cloud Storage tarafından desteklenmemesidir. Bu nedenle, file_blob öğesini ndb.StringProperty olarak değiştirin. Aşağıda, bu değişiklikleri yansıtan veri modeli sınıfı ve güncellenmiş store_visit() ve fetch_visits() işlevleri verilmiştir:

ÖNCESİ:

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)

SONRASI:

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)

Şu ana kadar yapılan değişikliklerin görsel gösterimi aşağıda verilmiştir:

a8f74ca392275822.png

İşleyicileri güncelleme

Yükleme işleyicisi

webapp2'daki işleyiciler sınıflardır. Flask'te ise 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:

ÖNCESİ:

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)

SONRASI:

@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 yapıtları artık blob_id yerine, varsa dosya adıyla (fname), yoksa None ile (kullanıcı dosya yüklemeyi devre dışı bıraktı) tanımlanır.
  • Blobstore işleyicileri, yükleme sürecini kullanıcılarından soyutlaştırıyordu ancak Cloud Storage'da bu durum geçerli değildir. 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 süslenmiş işleyicide bulunur.
  • Her iki işleyici de POST isteğini HTTP 307 dönüş koduyla koruyarak ana sayfaya ( / ) yönlendirme yaparak işlevlerini tamamlar.

İndirme işleyicisi

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

ÖNCESİ:

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)

SONRASI:

@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üncelleme ile ilgili notlar:

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

Ana işleyici

Ana uygulamadaki son değişiklikler ana işleyicide gerçekleşir. webapp2 HTTP fiil yöntemlerinin yerini, işlevlerini birleştiren tek bir işlev alıyor. MainHandler sınıfını root() işleviyle değiştirin ve webapp2 yönlendirme tablosunu aşağıdaki gibi kaldırın:

ÖNCESİ:

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)

SONRASI:

@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, root() içinde if-else ifadesi kullanılır. Ayrıca, root() tek bir işlev olduğundan GET ve POST için şablonu oluşturmak üzere yalnızca bir çağrı yapılır. Bu, webapp2'de mümkün değildir.

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

5ec38818c32fec2.png

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

Bu nedenle, 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 tamamlanmış 16. Modül uygulaması, Blobstore dosyalarını olduğu gibi görüntüleyemez. Başka bir deyişle, bu taşıma işlemini gerçekleştirerek eski sürümlerle uyumsuz bir değişiklik yaptık. Şimdi bu açığı kapatmaya çalışan main.py adlı bir alternatif sürüm sunuyoruz (depoda bulunur).main-migrate.py

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

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. Artık yeni ziyaretler oluştururken file_blob yerine file_gcs içinde açıkça bir değer depoladığınız için store_visit biraz farklı görünüyor:

ÖNCESİ:

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()

SONRASI:

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 ziyaretler getirilirken veriler şablona gönderilmeden önce "normalleştirilir":

ÖNCESİ:

@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)

SONRASI:

@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'nin (ya da ikisinin de) varlığını onaylayın. Kullanılabilir bir dosya varsa mevcut olanı seçin ve bu tanımlayıcıyı kullanın (Blobstore'da oluşturulan dosyalar için BlobKey veya Cloud Storage'da oluşturulan dosyalar için dosya adı). "Cloud Storage'da oluşturulan dosyalar" ifadesiyle, Cloud Storage istemci kitaplığı kullanılarak oluşturulan dosyaları kastediyoruz. Blobstore da Cloud Storage'a yazar ancak bu durumda Blobstore tarafından oluşturulan dosyalar söz konusudur.

Daha da önemlisi, son kullanıcı için verileri normalleştirmek veya ETL (ayıklama, dönüştürme ve yükleme) yapmak için 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'nin mevcut olup olmadığını kontrol eder ve varsa bunlardan birini (veya ikisi de yoksa None) seçer.

main.py ile 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 destekleyici dosyaları istiyorsanız kendi uygulamalarınız için geçişleri planlamanıza yardımcı olmak üzere bu tür senaryolarla nasıl başa çıkılacağına dair bir örnek olarak main-migrate.py'a göz atın. Karmaşık geçişler yapılırken özel durumların ortaya çıkması muhtemeldir. Bu nedenle, bu örnek gerçek verilerle gerçek uygulamaları modernleştirme konusunda daha fazla bilgi vermeyi amaçlamaktadır.

6. Özet/Temizleme

Bu bölümde, uygulamayı dağıtarak, amaçlandığı gibi çalıştığını ve yansıtılan tüm çıktılarda çalıştığını doğrulayarak bu codelab'i tamamlıyoruz. Uygulama doğrulandıktan sonra temizleme adımlarını uygulayın ve sonraki adımları göz önünde bulundurun.

Uygulamayı dağıtma ve doğrulama

Uygulamanızı yeniden dağıtmadan önce, bu kendi kendine paketlenmiş üçü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 dosyasını main.py olarak yeniden adlandırın. Şimdi gcloud app deploy uygulamasını çalıştırın ve uygulamanın 15. Modül uygulamasının aynısı olduğunu doğrulayı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, App Engine NDB'yi Cloud NDB ve webapp2'ı Flask ile değiştirme codelab'ini tamamladığınız için tebrik ederiz. Kodunuz artık FINISH (Module 16) klasöründeki kodla eşleşmelidir. Alternatif main-migrate.py de bu klasörde bulunuyor.

Python 3'e "geçiş"

Bu uygulamayı Python 3'e taşımak için app.yaml dosyasının en üstündeki yorum satırı haline getirilmiş Python 3 runtime yönergesi yeterlidir. Kaynak kodun kendisi zaten Python 3 ile uyumlu olduğundan 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 yorum işaretini kaldırın.
  2. app.yaml içindeki 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 gereksizdir)

Temizleme

Genel

Şimdilik işiniz bittiyse faturalandırmayı önlemek için App Engine uygulamanızı devre dışı bırakmanızı öneririz. Ancak biraz daha test veya deneme yapmak isterseniz App Engine platformunda ücretsiz kota bulunur. Bu nedenle, 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. Daha fazla bilgi için fiyatlandırma sayfasını inceleyin. Bu taşıma işlemine başka Cloud hizmetleri de dahilse bunlar ayrı olarak faturalandırılır. Her iki durumda da varsa aşağıdaki "Bu codelab'e özel" bölümüne bakın.

Tam açıklama yapmak gerekirse App Engine gibi bir Google Cloud sunucusuz bilgi işlem platformuna dağıtım yapıldığında küçük derleme ve depolama maliyetleri oluşur. Cloud Build ve Cloud Storage'ın kendi ücretsiz kotaları vardır. Bu görüntünün depolanması, kotanın bir kısmını kullanır. Ancak, böyle bir ücretsiz katmanın olmadığı 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 bağlantıları, PROJECT_ID ve *LOC*ınıza bağlıdır. Örneğin, uygulamanız ABD'de barındırılıyorsa "us" olur.

Öte yandan, bu uygulamaya veya ilgili diğer 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çtiyseniz Blobstore'da verileriniz olmaya devam eder. Bu nedenle, fiyatlandırma bilgilerini yukarıda paylaştık.

Sonraki adımlar

Bu eğitimin yanı sıra eski paketlenmiş hizmetlerden geçişe odaklanan diğer taşıma modüllerini de inceleyebilirsiniz:

  • 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-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ğil. Küçük bir App Engine uygulamanız veya sınırlı işlevselliğe sahip bir uygulamanız varsa ve bunu bağımsız bir mikro hizmete dönüştürmek istiyorsanız ya da tek bir uygulamayı birden fazla yeniden kullanılabilir bileşene ayırmak istiyorsanız Cloud Functions'a geçmeyi düşünebilirsiniz. Container mimarisine alma, özellikle CI/CD (sürekli entegrasyon/sürekli teslim veya dağıtım) ardışık düzeninden oluşuyorsa uygulama geliştirme iş akışınızın bir parçası haline geldiyse Cloud Run'a geçmeyi düşünebilirsiniz. Bu senaryolar aşağıdaki modüllerde ele alınır:

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

Başka bir sunucusuz platforma geçmek 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 göz önünde bulundurmanızı öneririz.

Bir sonraki geçiş modülünüz hangisi olursa olsun, tüm Serverless Migration Station içeriklerine (codelab'ler, videolar, kaynak kodu [varsa]) açık kaynaklı depodan erişebilirsiniz. Depodaki README, hangi taşımaların dikkate alınması gerektiği ve ilgili "sıra" hakkında da rehberlik sağlar.

7. Ek kaynaklar

Codelab ile ilgili sorunlar/geri bildirimler

Bu codelab ile ilgili sorun bulursanız lütfen göndermeden önce sorununuzu arayın. Arama yapma ve yeni sorunlar oluşturma bağlantıları:

Taşıma kaynakları

15. Modül (BAŞLANGIÇ) ve 16. Modül (BİTİŞ) ile ilgili depo klasörlerinin bağlantılarını aşağıdaki tabloda bulabilirsiniz. Bu dokümanlara, tüm App Engine codelab'lerinin taşındığı depodan da erişebilirsiniz. Bu depoyu klonlayabilir veya ZIP dosyası olarak indirebilirsiniz.

Codelab

Python 2

Python 3

Modül 15

code

Yok

Modül 16 (bu codelab)

code

(Python 2 ile aynı)

Online kaynaklar

Bu eğitimle ilgili olabilecek online kaynakları aşağıda bulabilirsiniz:

App Engine Blobstore ve Cloud Storage

App Engine platformu

Diğer Cloud bilgileri

Python

Videolar

Lisans

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