Panduan ini membahas cara melakukan migrasi dari Blobstore App Engine ke Cloud Storage.
Cloud Storage memiliki kesamaan dengan Blobstore App Engine di mana Anda dapat menggunakan Cloud Storage untuk menyajikan objek data besar (blob), seperti file video atau gambar, dan memungkinkan pengguna mengupload file data berukuran besar. Meskipun Blobstore App Engine hanya dapat diakses melalui layanan paket lama App Engine, Cloud Storage adalah produk mandiri Google Cloud yang diakses melalui Library Klien Cloud. Cloud Storage menawarkan solusi penyimpanan objek yang lebih modern pada aplikasi Anda dan memberi Anda fleksibilitas untuk bermigrasi ke Cloud Run atau platform hosting aplikasi Google Cloud lainnya di kemudian hari.
Untuk project Google Cloud yang dibuat setelah November 2016, Blobstore menggunakan bucket Cloud Storage di balik layar. Ini berarti bahwa saat Anda memigrasikan aplikasi ke Cloud Storage, semua objek dan izin yang ada di bucket Cloud Storage saat ini tetap tidak berubah. Anda juga dapat mulai mengakses bucket yang ada menggunakan Library Klien Cloud untuk Cloud Storage.
Perbedaan dan kesamaan utama
Cloud Storage tidak mencakup dependensi dan batasan Blobstore berikut:
- Blobstore API untuk Python 2 memiliki dependensi di aplikasi web.
- Blobstore API untuk Python 3 menggunakan class utilitas untuk menggunakan pengendali Blobstore.
- Untuk Blobstore, jumlah file maksimum yang dapat diupload ke Blobstore adalah 500. Tidak ada batasan jumlah objek yang dapat Anda buat di bucket Cloud Storage.
Cloud Storage tidak mendukung:
- Class pengendali Blobstore
- Objek Blobstore
Kesamaan Cloud Storage dan Blobstore App Engine:
- Mampu membaca dan menulis objek data besar di lingkungan runtime, serta menyimpan dan menyajikan objek data besar statis, seperti film, gambar, atau konten statis lainnya. Batas ukuran objek untuk Cloud Storage adalah 5 TiB.
- Memungkinkan Anda menyimpan objek di bucket Cloud Storage.
- Memiliki paket gratis.
Sebelum memulai
- Anda perlu meninjau serta memahami harga dan kuota Cloud Storage:
- Cloud Storage adalah layanan bayar sesuai penggunaan dan memiliki pricingnya sendiri untuk penyimpanan data berdasarkan kelas penyimpanan data Anda dan lokasi bucket Anda.
- Kuota Cloud Storage memiliki beberapa perbedaan dengan kuota dan batas Blobstore App Engine, yang dapat memengaruhi kuota permintaan App Engine Anda.
- Memiliki aplikasi App Engine Python 2 atau Python 3 yang sudah ada dan menggunakan Blobstore.
- Contoh dalam panduan ini menunjukkan aplikasi yang bermigrasi ke Cloud Storage menggunakan framework Flask. Perlu diperhatikan bahwa Anda dapat menggunakan framework web apa pun, termasuk tetap menggunakan
webapp2
, saat bermigrasi ke Cloud Storage.
Ringkasan
Secara umum, proses migrasi ke Cloud Storage dari Blobstore App Engine terdiri dari langkah-langkah berikut:
- Mengupdate file konfigurasi
- Mengupdate aplikasi Python:
- Mengupdate framework web
- Mengimpor dan melakukan inisialisasi Cloud Storage
- Mengupdate pengendali Blobstore
- Opsional: Mengupdate model data jika menggunakan Cloud NDB atau App Engine NDB
- Menguji dan men-deploy aplikasi
Mengupdate file konfigurasi
Sebelum mengubah kode aplikasi untuk beralih dari Blobstore ke Cloud Storage, update file konfigurasi Anda agar dapat menggunakan library Cloud Storage.
Update file
app.yaml
: Ikuti petunjuk untuk versi Python Anda:Python 2
Untuk aplikasi Python 2:
- Hapus bagian
handlers
dan dependensi aplikasi web yang tidak diperlukan di bagianlibraries
. - Jika Anda menggunakan Library Klien Cloud, tambahkan versi terbaru library
grpcio
dansetuptools
. - Tambahkan library
ssl
karena diperlukan oleh Cloud Storage.
Berikut adalah contoh file
app.yaml
dengan perubahan yang dibuat: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
Python 3
Untuk aplikasi Python 3, hapus semua baris kecuali untuk elemen
runtime
. Contoh:runtime: python310 # or another support version
Runtime Python 3 menginstal library secara otomatis, sehingga Anda tidak perlu menentukan library bawaan dari runtime Python 2 sebelumnya. Jika aplikasi Python 3 Anda menggunakan layanan paket lama lain saat bermigrasi ke Cloud Storage, biarkan file
app.yaml
apa adanya.- Hapus bagian
Update file
requirements.txt
: Ikuti petunjuk untuk versi python Anda:Python 2
Tambahkan Library Klien Cloud untuk Cloud Storage ke daftar dependensi dalam file
requirements.txt
.google-cloud-storage
Kemudian, jalankan
pip install -t lib -r requirements.txt
untuk memperbarui daftar library yang tersedia untuk aplikasi Anda.Python 3
Tambahkan Library Klien Cloud untuk Cloud Storage ke daftar dependensi dalam file
requirements.txt
.google-cloud-storage
App Engine otomatis menginstal dependensi ini selama deployment aplikasi di runtime Python 3, jadi hapus folder
lib
jika ada.Untuk aplikasi Python 2, jika aplikasi Anda menggunakan library bawaan atau yang disalin, Anda harus menentukan jalur tersebut dalam file
appengine_config.py
: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)
Mengupdate aplikasi Python
Setelah memodifikasi file konfigurasi, update aplikasi Python Anda.
Mengupdate framework web Python 2
Untuk aplikasi Python 2 yang menggunakan framework webapp2
, sebaiknya lakukan migrasi dari framework webapp2
yang sudah tidak berlaku. Lihat Jadwal dukungan runtime untuk mengetahui tanggal akhir dukungan Python 2.
Anda dapat bermigrasi ke framework web lain seperti Flask, Django, atau WSGI. Karena Cloud Storage tidak menyertakan dependensi di webapp2
dan pengendali Blobstore tidak didukung, Anda dapat menghapus atau mengganti library lain yang terkait dengan aplikasi web.
Jika Anda memilih untuk terus menggunakan webapp2
, perhatikan bahwa contoh dalam panduan ini menggunakan Cloud Storage dengan Flask.
Jika berencana menggunakan layanan Google Cloud selain Cloud Storage, atau untuk mendapatkan akses ke versi runtime terbaru, sebaiknya upgrade aplikasi Anda ke runtime Python 3. Untuk informasi selengkapnya, lihat Ringkasan migrasi Python 2 ke Python 3.
Mengimpor dan melakukan inisialisasi Cloud Storage
Ubah file aplikasi Anda dengan memperbarui baris impor dan inisialisasi:
Hapus pernyataan impor Blobstore, seperti berikut:
import webapp2 from google.appengine.ext import blobstore from google.appengine.ext.webapp import blobstore_handlers
Tambahkan pernyataan impor untuk Cloud Storage dan library Autentikasi Google, seperti berikut:
import io from flask import (Flask, abort, redirect, render_template, request, send_file, url_for) from google.cloud import storage import google.auth
Library Autentikasi Google diperlukan untuk mendapatkan project ID yang sama dengan yang digunakan di Blobstore untuk Cloud Storage. Impor library lain seperti Cloud NBD jika berlaku untuk aplikasi Anda.
Buat klien baru untuk Cloud Storage dan tentukan bucket yang digunakan di Blobstore. Contoh:
gcs_client = storage.Client() _, PROJECT_ID = google.auth.default() BUCKET = '%s.appspot.com' % PROJECT_ID
Untuk project Google Cloud setelah November 2016, Blobstore menulis ke bucket Cloud Storage yang diberi nama berdasarkan URL aplikasi Anda dan mengikuti format
PROJECT_ID.appspot.com
. Anda menggunakan autentikasi Google untuk mendapatkan project ID guna menentukan bucket Cloud Storage yang digunakan untuk menyimpan blob di Blobstore.
Mengupdate pengendali Blobstore
Karena Cloud Storage tidak mendukung pengendali upload dan download Blobstore, Anda harus menggunakan kombinasi fungsi Cloud Storage, modul library standar io
, framework web, dan utilitas Python untuk mengupload serta mendownload objek (blob) di Cloud Storage.
Berikut cara mengupdate pengendali Blobstore menggunakan Flask sebagai contoh framework web:
Ganti class pengendali upload Blobstore Anda dengan fungsi upload di Flask. Ikuti petunjuk untuk versi Python Anda:
Python 2
Pengendali Blobstore di Python 2 adalah class
webapp2
seperti yang ditunjukkan dalam contoh Blobstore berikut: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) ... app = webapp2.WSGIApplication([ ('/', MainHandler), ('/upload', UploadHandler), ('/view/([^/]+)?', ViewBlobHandler), ], debug=True)
Untuk menggunakan Cloud Storage:
- Ganti class upload Webapp dengan fungsi upload Flask.
- Ganti pengendali upload dan pemilihan rute dengan metode
POST
Flask yang dilengkapi dengan pemilihan rute.
Contoh kode yang diupdate:
@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)
Dalam contoh kode Cloud Storage yang diupdate, aplikasi sekarang mengidentifikasi artefak objek berdasarkan nama objeknya (
fname
) alih-alihblob_id
. Pemilihan rute juga terjadi di bagian bawah file aplikasi.Untuk mendapatkan objek yang diupload, metode
get_uploads()
Blobstore akan diganti dengan metoderequest.files.get()
Flask. Di Flask, Anda dapat menggunakan metodesecure_filename()
untuk mendapatkan nama tanpa karakter jalur, seperti/
, untuk file, dan mengidentifikasi objek menggunakangcs_client.bucket(BUCKET).blob(fname)
untuk menentukan nama bucket dan nama objek.Panggilan
upload_from_file()
Cloud Storage menjalankan upload seperti yang ditunjukkan pada contoh yang diupdate.Python 3
Class pengendali upload di Blobstore untuk Python 3 adalah class utilitas dan memerlukan penggunaan kamus
environ
WSGI sebagai parameter input, seperti ditunjukkan dalam Blobstore berikut contoh:class UploadHandler(blobstore.BlobstoreUploadHandler): 'Upload blob (POST) handler' def post(self): uploads = self.get_uploads(request.environ) if uploads: blob_id = uploads[0].key() store_visit(request.remote_addr, request.user_agent, blob_id) return redirect('/', code=307) ... @app.route('/upload', methods=['POST']) def upload(): """Upload handler called by blobstore when a blob is uploaded in the test.""" return UploadHandler().post()
Untuk menggunakan Cloud Storage, ganti metode
get_uploads(request.environ)
Blobstore dengan metoderequest.files.get()
Flask.Contoh kode yang diupdate:
@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)
Dalam contoh kode Cloud Storage yang diupdate, aplikasi sekarang mengidentifikasi artefak objek berdasarkan nama objeknya (
fname
) alih-alihblob_id
. Pemilihan rute juga terjadi di bagian bawah file aplikasi.Untuk mendapatkan objek yang diupload, metode
get_uploads()
Blobstore akan diganti dengan metoderequest.files.get()
Flask. Di Flask, Anda dapat menggunakan metodesecure_filename()
untuk mendapatkan nama tanpa karakter jalur, seperti/
, untuk file, dan mengidentifikasi objek menggunakangcs_client.bucket(BUCKET).blob(fname)
untuk menentukan nama bucket dan nama objek.Metode
upload_from_file()
Cloud Storage melakukan upload seperti yang ditunjukkan pada contoh yang diupdate.Ganti class pengendali Download Blobstore Anda dengan fungsi download di Flask. Ikuti petunjuk untuk versi Python Anda:
Python 2
Contoh pengendali download berikut menunjukkan penggunaan class
BlobstoreDownloadHandler
, yang menggunakan webapp2: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) ... app = webapp2.WSGIApplication([ ('/', MainHandler), ('/upload', UploadHandler), ('/view/([^/]+)?', ViewBlobHandler), ], debug=True)
Untuk menggunakan Cloud Storage:
- Perbarui metode
send_blob()
Blobstore untuk menggunakan metodedownload_as_bytes()
Cloud Storage. - Ubah pemilihan rute dari webapp2 ke Flask.
Contoh kode yang diupdate:
@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)
Dalam contoh kode Cloud Storage yang diupdate, Flask melengkapi rute pada fungsi Flask dan mengidentifikasi objek menggunakan
'/view/<path:fname>'
. Cloud Storage mengidentifikasi objekblob
berdasarkan nama objek dan nama bucket, serta menggunakan metodedownload_as_bytes()
untuk mendownload objek dalam ukuran byte, alih-alih menggunakan metodesend_blob
dari Blobstore. Jika artefak tidak ditemukan, aplikasi akan menampilkan error404
HTTP.Python 3
Seperti pengendali upload, class pengendali download di Blobstore untuk Python 3 adalah class utilitas dan memerlukan penggunaan kamus
environ
WSGI sebagai parameter input, seperti ditunjukkan dalam contoh Blobstore berikut:class ViewBlobHandler(blobstore.BlobstoreDownloadHandler): 'view uploaded blob (GET) handler' def get(self, blob_key): if not blobstore.get(blob_key): return "Photo key not found", 404 else: headers = self.send_blob(request.environ, blob_key) # Prevent Flask from setting a default content-type. # GAE sets it to a guessed type if the header is not set. headers['Content-Type'] = None return '', headers ... @app.route('/view/<blob_key>') def view_photo(blob_key): """View photo given a key.""" return ViewBlobHandler().get(blob_key)
Untuk menggunakan Cloud Storage, ganti
send_blob(request.environ, blob_key)
Blobstore dengan metodeblob.download_as_bytes()
Cloud Storage.Contoh kode yang diupdate:
@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)
Dalam contoh kode Cloud Storage yang diupdate,
blob_key
diganti denganfname
, dan Flask mengidentifikasi objek menggunakan URL'/view/<path:fname>'
. Metodegcs_client.bucket(BUCKET).blob(fname)
digunakan untuk menemukan nama file dan nama bucket. Metodedownload_as_bytes()
Cloud Storage mendownload objek dalam ukuran byte, alih-alih menggunakan metodesend_blob()
dari Blobstore.- Perbarui metode
Jika aplikasi Anda menggunakan pengendali utama, ganti class
MainHandler
dengan fungsiroot()
di Flask. Ikuti petunjuk untuk versi Python Anda:Python 2
Berikut adalah contoh penggunaan class
MainHandler
Blobstore: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)
Untuk menggunakan Cloud Storage:
- Hapus class
MainHandler(BaseHandler)
, karena Flask menangani pemilihan rute untuk Anda. - Sederhanakan kode Blobstore dengan Flask.
- Hapus pemilihan rute aplikasi web di bagian akhir.
Contoh kode yang diupdate:
@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)
Python 3
Jika menggunakan Flask, Anda tidak akan memiliki class
MainHandler
, tetapi fungsi root Flask Anda perlu diperbarui jika blobstore digunakan. Contoh berikut menggunakan fungsiblobstore.create_upload_url('/upload')
:@app.route('/', methods=['GET', 'POST']) def root(): 'main application (GET/POST) handler' context = {} if request.method == 'GET': context['upload_url'] = blobstore.create_upload_url('/upload') else: context['visits'] = fetch_visits(10) return render_template('index.html', **context)
Untuk menggunakan Cloud Storage, ganti fungsi
blobstore.create_upload_url('/upload')
dengan metodeurl_for()
Flask guna mendapatkan URL untuk fungsiupload()
.Contoh kode yang diupdate:
@app.route('/', methods=['GET', 'POST']) def root(): 'main application (GET/POST) handler' context = {} if request.method == 'GET': context['upload_url'] = url_for('upload') # Updated to use url_for else: context['visits'] = fetch_visits(10) return render_template('index.html', **context)
- Hapus class
Menguji dan men-deploy aplikasi
Server pengembangan lokal dapat digunakan untuk menguji apakah aplikasi Anda berjalan, tetapi tidak akan dapat menguji Cloud Storage sampai Anda men-deploy versi baru karena semua permintaan Cloud Storage harus dikirim melalui internet ke server bucket Cloud Storage sebenarnya. Baca artikel Menguji dan men-deploy aplikasi Anda untuk cara menjalankan aplikasi secara lokal. Kemudian, deploy versi baru untuk mengonfirmasi bahwa aplikasi terlihat sama seperti sebelumnya.
Aplikasi yang menggunakan App Engine NDB atau Cloud NDB
Anda harus memperbarui model data Datastore jika aplikasi Anda menggunakan App Engine NDB atau Cloud NDB untuk menyertakan properti terkait Blobstore.
Mengupdate model data
Karena properti BlobKey
dari NDB tidak didukung oleh Cloud Storage, Anda perlu mengubah baris yang terkait dengan Blobstore agar dapat menggunakan padanan bawaan dari NDB, framework web, atau di tempat lain.
Untuk mengupdate model data Anda:
Temukan baris yang menggunakan
BlobKey
dalam model data, seperti berikut: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()
Ganti
ndb.BlobKeyProperty()
denganndb.StringProperty()
: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() # Modified from ndb.BlobKeyProperty()
Jika Anda juga melakukan upgrade dari App Engine NDB ke Cloud NDB selama migrasi, lihat panduan migrasi Cloud NDB untuk panduan tentang cara memfaktorkan ulang kode NDB untuk menggunakan pengelola konteks Python.
Kompatibilitas mundur untuk model data Datastore
Di bagian sebelumnya, mengganti ndb.BlobKeyProperty
dengan ndb.StringProperty
akan membuat aplikasi tidak kompatibel dengan versi sebelumnya, yang berarti aplikasi tidak akan dapat memproses entri lama yang dibuat oleh Blobstore. Jika Anda perlu mempertahankan data lama, buat kolom tambahan untuk entri Cloud Storage baru, alih-alih mengupdate kolom ndb.BlobKeyProperty
, dan buat fungsi untuk menormalisasi data.
Dari contoh di bagian sebelumnya, buat perubahan berikut:
Buat dua kolom properti terpisah saat menentukan model data Anda. Gunakan properti
file_blob
untuk mengidentifikasi objek yang dibuat Blobstore dan propertifile_gcs
untuk mengidentifikasi objek yang dibuat Cloud Storage: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()
Cari baris yang merujuk kunjungan baru, seperti berikut:
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()
Ubah kode Anda sehingga
file_gcs
digunakan untuk entri terbaru. Contoh: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() # change file_blob to file_gcs for new requests
Buat fungsi baru untuk menormalisasi data. Contoh berikut menunjukkan penggunaan ekstraksi, transformasi, dan pemuatan (ETL) untuk melakukan loop melalui semua kunjungan, serta mengambil data pengunjung dan stempel waktu untuk memeriksa apakah
file_gcs
ataufile_gcs
ada: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]
Cari baris yang merujuk ke fungsi
fetch_visits()
:@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)
Gabungkan
fetch_visits()
di dalam fungsietl_visits()
, misalnya:@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)) # etl_visits wraps around fetch_visits return render_template('index.html', **context)
Contoh
- Untuk mengetahui contoh cara memigrasikan aplikasi Python 2 ke Cloud Storage, bandingkan contoh kode Blobstore untuk Python 2 dan contoh kode Cloud Storage di GitHub.
- Untuk melihat contoh cara memigrasikan aplikasi Python 3 ke Cloud Storage, bandingkan contoh kode Blobstore untuk Python 3 dan contoh kode Cloud Storage di GitHub.
Langkah selanjutnya
- Untuk tutorial praktik, lihat Bermigrasi dari Blobstore App Engine ke codelab Cloud Storage untuk Python.
- Pelajari cara menyimpan dan memperbaiki file statis dari Cloud Storage.
- Lihat dokumentasi Cloud Storage untuk detail selengkapnya.