1. Tổng quan
Loạt lớp học lập trình về Trạm di chuyển không máy chủ (hướng dẫn thực hành theo tiến độ riêng) và video có liên quan nhằm giúp các nhà phát triển Google Cloud không máy chủ không hiện đại hoá các ứng dụng của họ bằng cách hướng dẫn họ thực hiện một hoặc nhiều quá trình di chuyển, chủ yếu là ngừng sử dụng các dịch vụ cũ. Việc này giúp ứng dụng của bạn dễ di chuyển hơn, đồng thời mang đến cho bạn nhiều lựa chọn và độ linh hoạt hơn, cho phép bạn tích hợp và truy cập vào nhiều sản phẩm của Cloud hơn, đồng thời dễ dàng nâng cấp lên bản phát hành ngôn ngữ mới hơn. Mặc dù ban đầu tập trung vào những người dùng Cloud sớm nhất, chủ yếu là các nhà phát triển App Engine (môi trường tiêu chuẩn), nhưng loạt bài này đủ rộng để bao gồm các nền tảng không máy chủ khác như Cloud Functions và Cloud Run hoặc ở những nơi khác nếu có.
Lớp học lập trình này hướng dẫn bạn cách di chuyển từ App Engine Blobstore sang Cloud Storage. Ngoài ra còn có quá trình di chuyển ngầm định từ:
- Khung web
webapp2
thành Flask (được đề cập trong Mô-đun 1) - App Engine NDB sang Cloud NDB để truy cập Datastore (được đề cập trong Mô-đun 2)
- Python 2 đến 3 (ứng dụng được di chuyển tương thích với cả Python 2 &3)
Hãy tham khảo bất kỳ mô-đun di chuyển nào có liên quan để biết thêm thông tin từng bước.
Bạn sẽ tìm hiểu cách
- Thêm việc sử dụng API/thư viện App Engine Blobstore
- Lưu trữ nội dung người dùng tải lên dịch vụ Blobstore
- Chuẩn bị cho bước tiếp theo để di chuyển sang Cloud Storage
Bạn cần có
- Một dự án Google Cloud Platform có tài khoản thanh toán GCP đang hoạt động
- Kỹ năng Python cơ bản
- Kiến thức thực hành về các lệnh Linux phổ biến
- Kiến thức cơ bản về việc phát triển và triển khai ứng dụng App Engine
- Ứng dụng App Engine Mô-đun 15 đang hoạt động: hoàn thành Lớp học lập trình Mô-đun 15 (nên có) hoặc sao chép Ứng dụng Mô-đun 15 từ kho lưu trữ
Khảo sát
Bạn sẽ sử dụng hướng dẫn này như thế nào?
Bạn đánh giá thế nào về trải nghiệm sử dụng Python?
Bạn đánh giá thế nào về trải nghiệm sử dụng các dịch vụ của Google Cloud?
2. Thông tin khái quát
Lớp học lập trình này bắt đầu bằng ứng dụng mẫu trong Mô-đun 15 và trình bày cách di chuyển từ Blobstore (và NDB) sang Cloud Storage (và Cloud NDB). Quá trình di chuyển bao gồm việc thay thế các phần phụ thuộc trên các dịch vụ đi kèm cũ của App Engine, cho phép bạn di chuyển ứng dụng của mình sang một nền tảng đám mây không máy chủ khác hoặc nền tảng lưu trữ khác nếu muốn.
Quá trình di chuyển này đòi hỏi nhiều nỗ lực hơn một chút so với các quá trình di chuyển khác trong loạt hướng dẫn này. Blobstore có các phần phụ thuộc trên khung webapp ban đầu và đó là lý do ứng dụng mẫu sử dụng khung webapp2 thay vì Flask. Hướng dẫn này mô tả việc di chuyển sang Cloud Storage, Cloud NDB, Flask và Python 3.
Ứng dụng vẫn ghi lại "lượt truy cập" của người dùng cuối và hiển thị 10 cấu phần phần mềm gần đây nhất, nhưng lớp học lập trình trước đó (Mô-đun 15) đã thêm chức năng mới để phù hợp với việc sử dụng Blobstore: ứng dụng nhắc người dùng cuối tải một cấu phần phần mềm lên (một tệp) tương ứng với "lượt truy cập" của họ. Người dùng có thể làm như vậy hoặc chọn "bỏ qua" chọn không tham gia. Bất kể người dùng quyết định thế nào, trang tiếp theo đều hiển thị cùng một kết quả với các phiên bản trước đó của ứng dụng và cho thấy những lượt truy cập gần đây nhất. Một điểm khác biệt nữa là các lượt truy cập chứa cấu phần phần mềm tương ứng sẽ có một "chế độ xem" để hiển thị cấu phần phần mềm của lượt truy cập. Lớp học lập trình này sẽ triển khai quá trình di chuyển nêu trên mà vẫn giữ nguyên chức năng được mô tả.
3. Thiết lập/Chuẩn bị
Trước khi chuyển sang phần chính của hướng dẫn, hãy thiết lập dự án, lấy mã, sau đó triển khai ứng dụng cơ sở để biết rằng mình đã bắt đầu làm việc với mã nguồn.
1. Thiết lập dự án
Nếu đã triển khai ứng dụng Mô-đun 15, bạn nên sử dụng lại chính dự án (và mã) đó. Ngoài ra, bạn có thể tạo một dự án hoàn toàn mới hoặc sử dụng lại một dự án hiện có khác. Đảm bảo dự án này có một tài khoản thanh toán đang hoạt động và đã bật App Engine.
2. Tải ứng dụng mẫu cơ sở
Một trong những điều kiện tiên quyết của lớp học lập trình này là phải có một ứng dụng mẫu của Mô-đun 15 hoạt động được. Nếu chưa có, bạn có thể lấy trong Học phần 15 "BẮT ĐẦU" thư mục (đường liên kết bên dưới). Lớp học lập trình này sẽ hướng dẫn bạn qua từng bước, kết thúc bằng mã tương tự như trong Mô-đun 16 " hướng dẫn hoàn thiện" .
- START: Thư mục mô-đun 15 (Python 2)
- HOÀN TẤT: Thư mục mô-đun 16 (Python 2)
- Toàn bộ kho lưu trữ (để sao chép hoặc tải tệp ZIP xuống)
Thư mục của các tệp BẮT ĐẦU Mô-đun 15 sẽ có dạng như sau:
$ ls README.md app.yaml main-gcs.py main.py templates
Tệp main-gcs.py
là một phiên bản thay thế của main.py
trong Mô-đun 15, cho phép lựa chọn một bộ chứa trên Cloud Storage khác với giá trị mặc định của URL được chỉ định của một ứng dụng dựa trên mã của dự án: PROJECT_ID
.appspot.com
. Ngoài các kỹ thuật di chuyển tương tự, tệp này không đóng vai trò gì trong lớp học lập trình này (Mô-đun 16) cho tệp đó nếu muốn.
3. (Triển khai lại) ứng dụng cơ sở
Các bước chuẩn bị còn lại để thực hiện ngay:
- Làm quen lại bằng công cụ dòng lệnh
gcloud
- Triển khai lại ứng dụng mẫu bằng
gcloud app deploy
- Xác nhận rằng ứng dụng chạy trên App Engine mà không gặp vấn đề nào
Sau khi thực hiện thành công các bước đó và xác nhận rằng ứng dụng Mô-đun 15 của bạn hoạt động. Trang đầu tiên chào người dùng bằng một biểu mẫu nhắc họ tải tệp cấu phần phần mềm về việc truy cập lên cùng với lựa chọn "bỏ qua" để chọn không tham gia:
Sau khi người dùng tải một tệp lên hoặc bỏ qua, ứng dụng này sẽ hiển thị các thông tin quen thuộc như "lượt truy cập gần đây nhất" trang:
Các lượt truy cập giới thiệu cấu phần phần mềm sẽ có một "lượt xem" ở bên phải dấu thời gian truy cập để hiển thị (hoặc tải xuống) cấu phần phần mềm. Sau khi xác nhận chức năng của ứng dụng, bạn đã sẵn sàng di chuyển từ các dịch vụ cũ của App Engine (webapp2, NDB, Blobstore) sang các dịch vụ thay thế hiện đại (Flask, Cloud NDB, Cloud Storage).
4. Cập nhật tệp cấu hình
Ba tệp cấu hình được đưa vào sử dụng cho phiên bản cập nhật của ứng dụng. Các tác vụ bắt buộc bao gồm:
- Cập nhật các thư viện tích hợp sẵn bắt buộc của bên thứ ba trong
app.yaml
cũng như để cơ hội di chuyển sang Python 3 - Thêm
requirements.txt
để chỉ định tất cả thư viện bắt buộc chưa được tích hợp sẵn - Thêm
appengine_config.py
để ứng dụng hỗ trợ cả thư viện bên thứ ba tích hợp sẵn và không tích hợp
app.yaml
Chỉnh sửa tệp app.yaml
bằng cách cập nhật phần libraries
. Xoá jinja2
và thêm grpcio
, setuptools
và ssl
. Chọn phiên bản mới nhất có sẵn cho cả 3 thư viện. Ngoài ra, hãy thêm lệnh runtime
của Python 3, nhưng đã nhận xét. Khi bạn hoàn tất, nó sẽ có dạng như sau (nếu bạn chọn Python 3.9):
TRƯỚC KHI:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
libraries:
- name: jinja2
version: latest
SAU KHI:
#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
Thay đổi này chủ yếu xử lý các thư viện tích hợp sẵn Python 2 có trên các máy chủ App Engine (vì vậy, bạn không phải tự nhóm chúng). Chúng tôi đã xoá Jinja2 vì thành phần này đi kèm với Flask mà chúng tôi sẽ thêm vào reqs.txt. Bất cứ khi nào sử dụng các thư viện ứng dụng của Google Cloud, chẳng hạn như các thư viện dành cho Cloud NDB và Cloud Storage, các thư viện grpcio và công cụ thiết lập đều cần thiết. Cuối cùng, bản thân Cloud Storage yêu cầu thư viện SSL. Chỉ thị thời gian chạy được nhận xét ở trên cùng là dành cho thời điểm bạn đã sẵn sàng chuyển ứng dụng này sang Python 3. Chúng tôi sẽ đề cập đến chủ đề này ở cuối hướng dẫn này.
requirements.txt
Thêm tệp requirements.txt
, yêu cầu có khung Flask và thư viện ứng dụng Cloud NDB và Cloud Storage, không có thư viện nào tích hợp sẵn. Tạo tệp có nội dung sau:
flask
google-cloud-ndb
google-cloud-storage
Môi trường thời gian chạy Python 2 App Engine yêu cầu tự nhóm các thư viện của bên thứ ba không được tích hợp sẵn, vì vậy hãy thực thi lệnh sau để cài đặt các thư viện này vào thư mục lib:
pip install -t lib -r requirements.txt
Nếu bạn có cả Python 2 và 3 trên máy phát triển của mình, bạn có thể phải sử dụng lệnh pip2 để đảm bảo nhận được phiên bản Python 2 của các thư viện này. Sau khi nâng cấp lên Python 3, bạn không cần phải tự gói nữa.
appengine_config.py
Thêm tệp appengine_config.py
hỗ trợ các thư viện tích hợp sẵn của bên thứ ba và không tích hợp sẵn. Tạo tệp có nội dung sau:
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)
Các bước vừa hoàn thành sẽ tương tự hoặc giống với các bước nêu trong phần Cài đặt thư viện cho ứng dụng Python 2 trong tài liệu của App Engine, và cụ thể hơn là nội dung của appengine_config.py
phải khớp với nội dung trong Bước 5 ở đó.
Công việc trên tệp cấu hình đã hoàn tất, vì vậy, hãy chuyển sang ứng dụng.
5. Sửa đổi tệp ứng dụng
Nhập
Nhóm các thay đổi đầu tiên cho main.py
bao gồm hoán đổi tất cả những nội dung sẽ được thay thế. Sau đây là nội dung thay đổi:
webapp2
được thay thế bằng bình giữ nhiệt- Thay vì sử dụng Jinja2 trong
webapp2_extras
, hãy sử dụng Jinja2 đi kèm với Flask - Cloud NDB và Cloud Storage thay thế cho Blobstore và NDB của App Engine
- Các trình xử lý Blobstore trong
webapp
được thay thế bằng kết hợp mô-đun thư viện chuẩnio
, Flask và các tiện íchwerkzeug
- Theo mặc định, Blobstore ghi vào bộ chứa Cloud Storage được đặt tên theo URL của ứng dụng (
PROJECT_ID.appspot.com
). Vì chúng tôi đang chuyển sang thư viện ứng dụng Cloud Storage nêngoogle.auth
được dùng để lấy mã dự án chỉ định chính xác tên bộ chứa. (Bạn có thể thay đổi tên bộ chứa vì tên này không còn được cố định giá trị trong mã nữa.)
TRƯỚC KHI:
import webapp2
from webapp2_extras import jinja2
from google.appengine.ext import blobstore, ndb
from google.appengine.ext.webapp import blobstore_handlers
Triển khai các thay đổi trong danh sách trên bằng cách thay thế phần nhập hiện tại trong main.py
bằng đoạn mã dưới đây.
SAU KHI:
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
Khởi tạo và hỗ trợ Jinja2 không cần thiết
Khối mã tiếp theo cần thay thế là BaseHandler
chỉ định việc sử dụng Jinja2 qua webapp2_extras
. Điều này là không cần thiết vì Jinja2 đi kèm với Flask và là công cụ tạo mẫu mặc định của nó, vì vậy hãy loại bỏ nó.
Ở phía Mô-đun 16, hãy tạo thực thể cho các đối tượng mà chúng ta không có trong ứng dụng cũ. Trong đó có việc khởi chạy ứng dụng Flask và tạo các ứng dụng API cho Cloud NDB và Cloud Storage. Cuối cùng, chúng ta đặt tên bộ chứa Cloud Storage như mô tả ở trên trong phần nhập. Dưới đây là trước và sau khi triển khai những nội dung cập nhật này:
TRƯỚC KHI:
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))
SAU KHI:
app = Flask(__name__)
ds_client = ndb.Client()
gcs_client = storage.Client()
_, PROJECT_ID = google.auth.default()
BUCKET = '%s.appspot.com' % PROJECT_ID
Cập nhật quyền truy cập vào Datastore
Cloud NDB chủ yếu tương thích với App Engine NDB. Một điểm khác biệt đã được đề cập là cần có ứng dụng API. Một lý do khác là yêu cầu quyền truy cập vào Datastore phải được kiểm soát bởi trình quản lý ngữ cảnh Python của ứng dụng API. Về cơ bản, điều này có nghĩa là tất cả các lệnh gọi truy cập Datastore sử dụng thư viện ứng dụng Cloud NDB chỉ có thể xảy ra trong các khối with
Python.
Đó là một thay đổi; hai là Blobstore và các đối tượng của nó, ví dụ: Cloud Storage không hỗ trợ các BlobKey
, vì vậy, hãy thay đổi file_blob
thành ndb.StringProperty
. Dưới đây là lớp mô hình dữ liệu cũng như các hàm store_visit()
và fetch_visits()
được cập nhật để phản ánh những thay đổi này:
TRƯỚC KHI:
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)
SAU KHI:
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)
Dưới đây là hình ảnh minh hoạ những thay đổi đã được thực hiện từ trước đến nay:
Cập nhật trình xử lý
Trình xử lý tải lên
Trình xử lý trong webapp2
là các lớp khi đang là các hàm trong Flask. Thay vì sử dụng phương thức động từ HTTP, Flask sử dụng động từ này để trang trí hàm. Blobstore và các trình xử lý webapp
của Blobstore được thay thế bằng chức năng của Cloud Storage cũng như Flask và các tiện ích tương ứng:
TRƯỚC KHI:
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)
SAU KHI:
@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)
Một số lưu ý về nội dung cập nhật này:
- Thay vì
blob_id
, các cấu phần phần mềm tệp hiện được xác định theo tên tệp (fname
) nếu có vàNone
nếu không (người dùng chọn không tải tệp lên). - Các trình xử lý Blobstore đã loại bỏ quy trình tải lên từ người dùng, nhưng Cloud Storage thì không. Vì vậy, bạn có thể thấy mã mới được thêm để thiết lập đối tượng và vị trí (bộ chứa) cho tệp blob, cũng như lệnh gọi thực hiện việc tải lên thực tế. (
upload_from_file()
). webapp2
sử dụng một bảng định tuyến ở cuối tệp ứng dụng trong khi các tuyến của Flask được tìm thấy trong mỗi trình xử lý được trang trí.- Cả hai trình xử lý đều kết thúc chức năng của chúng bằng cách chuyển hướng đến trang chủ (
/
) trong khi vẫn duy trì yêu cầuPOST
bằng mã trả về HTTP 307.
Tải trình xử lý xuống
Việc cập nhật trình xử lý tải xuống sẽ tuân theo một mẫu tương tự như trình xử lý tải lên, chỉ khác là có ít mã hơn nhiều để xem. Thay thế chức năng Blobstore và webapp
bằng Cloud Storage và Flask tương đương:
TRƯỚC KHI:
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)
SAU KHI:
@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)
Lưu ý về nội dung cập nhật này:
- Xin nhắc lại, Flask trang trí các hàm của trình xử lý theo tuyến của chúng trong khi
webapp
thực hiện việc này trong bảng định tuyến ở dưới cùng, vì vậy, hãy nhận ra cú pháp so khớp mẫu của hàm sau('/view/([^/]+)?'
) so với của Flask ('/view/<path:fname>'
). - Tương tự như với trình xử lý tải lên, phía Cloud Storage cần thực hiện thêm một số thao tác để thực hiện các chức năng mà các trình xử lý Blobstore tóm tắt, cụ thể là xác định tệp (blob) đang được đề cập và tải xuống rõ ràng lệnh gọi phương thức
send_blob()
của tệp nhị phân so với trình xử lý Blobstore. - Trong cả hai trường hợp, lỗi HTTP 404 sẽ được trả về cho người dùng nếu không tìm thấy cấu phần phần mềm.
Trình xử lý chính
Những thay đổi cuối cùng đối với ứng dụng chính sẽ diễn ra trong trình xử lý chính. Các phương thức động từ HTTP webapp2
được thay thế bằng một hàm duy nhất kết hợp chức năng của các phương thức đó. Thay thế lớp MainHandler
bằng hàm root()
và xoá bảng định tuyến webapp2
như minh hoạ dưới đây:
TRƯỚC KHI:
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)
SAU KHI:
@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)
Thay vì phân tách các phương thức get()
và post()
, về cơ bản, chúng là một câu lệnh if-else
trong root()
. Ngoài ra, vì root()
là một hàm đơn nhất nên chỉ có một lệnh gọi để kết xuất mẫu cho cả GET
và POST
trong khi thực sự không thể thực hiện được việc này trong webapp2
.
Dưới đây là hình ảnh minh hoạ cho loạt thay đổi thứ hai và cũng là cuối cùng này đối với main.py
:
(không bắt buộc) Tính năng "nâng cao" khả năng tương thích ngược
Vì vậy, giải pháp được tạo ở trên hoạt động hoàn hảo... nhưng chỉ khi bạn bắt đầu từ đầu và chưa có tệp do Blobstore tạo. Vì chúng ta đã cập nhật ứng dụng để xác định tệp theo tên tệp thay vì BlobKey
, nên ứng dụng Mô-đun 16 đã hoàn thiện sẽ không thể xem các tệp Blobstore. Nói cách khác, chúng tôi đã thực hiện một thay đổi không tương thích ngược khi thực hiện quá trình di chuyển này. Hiện tại, chúng tôi giới thiệu một phiên bản thay thế của main.py
có tên là main-migrate.py
(có trong kho lưu trữ) nhằm thu hẹp khoảng cách này.
"Tiện ích" đầu tiên để hỗ trợ các tệp do Blobstore tạo là một mô hình dữ liệu có BlobKeyProperty
(ngoài StringProperty
cho các tệp do Cloud Storage tạo):
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()
Thuộc tính file_blob
sẽ dùng để xác định các tệp do Blobstore tạo, còn file_gcs
dành cho các tệp trên Cloud Storage. Bây giờ, khi tạo lượt truy cập mới, hãy lưu trữ rõ ràng một giá trị trong file_gcs
thay vì file_blob
, vì vậy store_visit sẽ hơi khác một chút:
TRƯỚC KHI:
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()
SAU KHI:
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()
Khi tìm nạp các lượt truy cập gần đây nhất, hãy "chuẩn hoá" dữ liệu trước khi gửi đến mẫu:
TRƯỚC KHI:
@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)
SAU KHI:
@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)
Tiếp theo, hãy xác nhận sự tồn tại của file_blob
hoặc file_gcs
(hoặc không có). Nếu có tệp, hãy chọn tệp hiện có và sử dụng giá trị nhận dạng đó (BlobKey
đối với tệp do Blobstore tạo hoặc tên tệp cho các tệp được tạo bằng Cloud Storage). Khi chúng tôi nói "Tệp do Cloud Storage tạo", ý chúng tôi là các tệp được tạo bằng thư viện ứng dụng Cloud Storage. Blobstore cũng ghi vào Cloud Storage, nhưng trong trường hợp này, đó sẽ là các tệp do Blobstore tạo.
Bây giờ, quan trọng hơn là hàm etl_visits()
này được dùng để chuẩn hoá hoặc ETL (trích xuất, biến đổi và tải) dữ liệu cho người dùng cuối là gì? Thông báo sẽ có dạng như sau:
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]
Kết quả này có thể giống như những gì bạn mong đợi: mã lặp lại qua tất cả các lượt truy cập và cho mỗi lượt truy cập, lấy nguyên văn dữ liệu khách truy cập và dấu thời gian, sau đó kiểm tra xem file_gcs
hoặc file_blob
có tồn tại không và nếu có, hãy chọn một trong số đó (hoặc None
nếu không có).
Dưới đây là hình minh hoạ sự khác biệt giữa main.py
và main-migrate.py
:
Nếu bạn bắt đầu từ đầu khi chưa có các tệp do Blobstore tạo, hãy sử dụng main.py
. Tuy nhiên, nếu bạn đang chuyển đổi và muốn các tệp được hỗ trợ do cả Blobstore và Cloud Storage tạo ra, hãy xem main-migrate.py
làm ví dụ về cách xử lý các tình huống như giúp bạn lên kế hoạch di chuyển ứng dụng của mình. Khi thực hiện các quá trình di chuyển phức tạp, các trường hợp đặc biệt có thể phát sinh, vì vậy, ví dụ này nhằm thể hiện mong muốn hiện đại hơn với việc hiện đại hoá các ứng dụng thực bằng dữ liệu thực.
6. Tóm tắt/Dọn dẹp
Phần này tóm tắt lớp học lập trình này bằng cách triển khai ứng dụng, xác minh rằng ứng dụng hoạt động như dự kiến và trong mọi đầu ra được phản ánh. Sau khi xác thực ứng dụng, hãy thực hiện mọi bước dọn dẹp và xem xét các bước tiếp theo.
Triển khai và xác minh ứng dụng
Trước khi triển khai lại ứng dụng, hãy nhớ chạy pip install -t lib -r requirements.txt
để tải các thư viện bên thứ ba tự nhóm đó vào thư mục lib. Nếu bạn muốn chạy giải pháp có khả năng tương thích ngược, trước tiên hãy đổi tên main-migrate.py
thành main.py
. Bây giờ, hãy chạy gcloud app deploy
và xác nhận rằng ứng dụng này hoạt động giống hệt với ứng dụng Mô-đun 15. Màn hình biểu mẫu có dạng như sau:
Trang về lượt truy cập gần đây nhất trông giống như sau:
Chúc mừng bạn đã hoàn thành lớp học lập trình này về việc thay thế App Engine Blobstore bằng Cloud Storage, App Engine NDB bằng Cloud NDB và webapp2
bằng Flask. Mã của bạn bây giờ sẽ khớp với nội dung trong thư mục chốt (HOÀN TẤT (Mô-đun 16)). main-migrate.py
thay thế cũng có trong thư mục đó.
"Di chuyển" Python 3
Chỉ lệnh runtime
Python 3 đã nhận xét ở đầu app.yaml
là tất cả những gì cần thiết để chuyển ứng dụng này sang Python 3. Bản thân mã nguồn đã tương thích với Python 3, vì vậy bạn không cần thay đổi gì. Để triển khai dưới dạng ứng dụng Python 3, hãy thực thi các bước sau:
- Huỷ nhận xét về lệnh
runtime
của Python 3 ở đầuapp.yaml
. - Xoá tất cả các dòng khác trong
app.yaml
. - Xoá tệp
appengine_config.py
. (không sử dụng trong thời gian chạy Python 3) - Xoá thư mục
lib
nếu thư mục này tồn tại. (không cần thiết với thời gian chạy Python 3)
Dọn dẹp
Giải pháp chung
Nếu bạn đã hoàn tất, chúng tôi khuyên bạn nên tắt ứng dụng App Engine để tránh phát sinh thanh toán. Tuy nhiên, nếu bạn muốn kiểm tra hoặc thử nghiệm thêm, nền tảng App Engine có hạn mức miễn phí, và bạn sẽ không bị tính phí, miễn là bạn không vượt quá cấp sử dụng đó. Đó là cho dịch vụ điện toán nhưng bạn cũng có thể bị tính phí cho các dịch vụ có liên quan của App Engine, vì vậy hãy xem trang giá của dịch vụ này để biết thêm thông tin. Nếu quá trình di chuyển này liên quan đến các dịch vụ khác trên Google Cloud, thì những dịch vụ đó sẽ được tính phí riêng. Trong cả hai trường hợp (nếu có), hãy xem phần "Dành riêng cho lớp học lập trình này" phần dưới đây.
Để công bố đầy đủ thông tin, việc triển khai cho một nền tảng điện toán không máy chủ của Google Cloud như App Engine sẽ làm phát sinh chi phí bản dựng và bộ nhớ thấp. Cloud Build cũng có hạn mức miễn phí riêng, tương tự như Cloud Storage. Việc lưu trữ hình ảnh đó sẽ sử dụng hết một phần hạn mức đó. Tuy nhiên, bạn có thể sống ở một khu vực không có bậc miễn phí như vậy, vì vậy hãy chú ý đến mức sử dụng bộ nhớ của bạn để giảm thiểu chi phí tiềm ẩn. "Thư mục" cụ thể trên Cloud Storage bạn nên xem xét, bao gồm:
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
- Các đường liên kết lưu trữ ở trên phụ thuộc vào
PROJECT_ID
và hoạt động *LOC
*của bạn, ví dụ: "us
" nếu ứng dụng của bạn được lưu trữ ở Hoa Kỳ.
Mặt khác, nếu bạn không định tiếp tục sử dụng ứng dụng này hoặc các lớp học lập trình di chuyển khác có liên quan và muốn xoá hoàn toàn mọi thứ, hãy ngừng dự án của bạn.
Dành riêng cho lớp học lập trình này
Các dịch vụ được liệt kê dưới đây là những dịch vụ dành riêng cho lớp học lập trình này. Hãy tham khảo tài liệu của từng sản phẩm để biết thêm thông tin:
- Dịch vụ Blobstore của App Engine thuộc Hạn mức và giới hạn dữ liệu được lưu trữ, vì vậy, hãy xem lại điều đó cũng như trang giá cho các dịch vụ theo gói cũ.
- Cloud Storage có bậc miễn phí cho các khu vực cụ thể; cũng có thể xem trang giá chung của ứng dụng này để biết thêm thông tin.
- Dịch vụ App Engine Datastore do Cloud Datastore (Cloud Firestore ở chế độ Datastore) cung cấp, cũng có một bậc miễn phí; hãy xem trang giá của YouTube để biết thêm thông tin."
Xin lưu ý rằng nếu đã di chuyển từ Mô-đun 15 sang Mô-đun 16, bạn vẫn sẽ có dữ liệu trong Blobstore. Do đó, chúng tôi đưa thông tin về giá của mô-đun này vào phần trên.
Các bước tiếp theo
Ngoài hướng dẫn này, bạn cũng cần cân nhắc những mô-đun di chuyển khác tập trung vào việc ngừng sử dụng các dịch vụ cũ theo gói:
- Mô-đun 2: di chuyển từ App Engine
ndb
sang Cloud NDB - Mô-đun 7-9: di chuyển từ Hàng đợi tác vụ của App Engine để đẩy các tác vụ sang Cloud Tasks
- Mô-đun 12-13: di chuyển từ App Engine Memcache sang Cloud Memorystore
- Mô-đun 18-19: di chuyển từ Hàng đợi tác vụ của App Engine (Tác vụ kéo) sang Cloud Pub/Sub
App Engine không còn là nền tảng không máy chủ duy nhất trên Google Cloud nữa. Nếu bạn có một ứng dụng App Engine nhỏ hoặc một ứng dụng có chức năng hạn chế và muốn biến ứng dụng đó thành một dịch vụ vi mô độc lập, hoặc bạn muốn chia một ứng dụng nguyên khối thành nhiều thành phần có thể sử dụng lại, thì đây là những lý do chính đáng để bạn cân nhắc chuyển sang Cloud Functions. Nếu việc tích hợp vùng chứa đã trở thành một phần trong quy trình phát triển ứng dụng, đặc biệt là khi quy trình đó bao gồm một quy trình CI/CD (tích hợp liên tục/phân phối hoặc triển khai liên tục), hãy cân nhắc chuyển sang Cloud Run. Những trường hợp này được đề cập trong các mô-đun sau:
- Di chuyển từ App Engine sang Cloud Functions: xem Học phần 11
- Di chuyển từ App Engine sang Cloud Run: xem Mô-đun 4 để vùng chứa ứng dụng của bạn bằng Docker, hoặc Mô-đun 5 để triển khai mà không cần vùng chứa, kiến thức về Docker hoặc
Dockerfile
Việc chuyển sang một nền tảng không máy chủ khác là không bắt buộc. Bạn nên cân nhắc các lựa chọn phù hợp nhất cho ứng dụng và trường hợp sử dụng của mình trước khi điều chỉnh bất cứ điều gì.
Bất kể bạn cân nhắc mô-đun di chuyển nào tiếp theo, bạn đều có thể truy cập vào tất cả nội dung của Trạm di chuyển không máy chủ (lớp học lập trình, video, mã nguồn [nếu có]) tại kho lưu trữ nguồn mở của chúng. README
của kho lưu trữ này cũng cung cấp hướng dẫn về những quá trình di chuyển cần xem xét và mọi "đơn đặt hàng" có liên quan Mô-đun di chuyển.
7. Tài nguyên khác
Vấn đề/ý kiến phản hồi về lớp học lập trình này
Nếu bạn gặp vấn đề với lớp học lập trình này, vui lòng tìm vấn đề của bạn trước khi gửi. Đường liên kết để tìm kiếm và báo cáo vấn đề mới:
Tài nguyên di chuyển
Bạn có thể tìm thấy các đường liên kết đến các thư mục repo cho Mô-đun 15 (START) và Mô-đun 16 (Finish) trong bảng bên dưới. Bạn cũng có thể truy cập vào các tệp này qua kho lưu trữ dành cho mọi quá trình di chuyển trong lớp học lập trình App Engine. Tại đây, bạn có thể sao chép hoặc tải tệp ZIP xuống.
Codelab | Python 2 | Python 3 |
Mô-đun 15 | Không có | |
Mô-đun 16 (lớp học lập trình này) | (tương tự như Python 2) |
Tài nguyên trực tuyến
Dưới đây là các tài nguyên trực tuyến có thể phù hợp với hướng dẫn này:
Blobstore và Cloud Storage của App Engine
- Dịch vụ App Engine Blobstore
- Di chuyển sang thư viện ứng dụng Cloud Storage
- Trang chủ của Cloud Storage
- Tài liệu về Cloud Storage
Nền tảng App Engine
- Tài liệu về App Engine
- Thời gian chạy của Python 2 App Engine (môi trường tiêu chuẩn)
- Sử dụng thư viện tích hợp sẵn App Engine trên Python 2 App Engine
- Thời gian chạy của Python 3 App Engine (môi trường tiêu chuẩn)
- Điểm khác biệt giữa Python 2 và 3 môi trường thời gian chạy của App Engine (môi trường tiêu chuẩn)
- Hướng dẫn di chuyển từ Python 2 sang 3 App Engine (môi trường chuẩn)
- Thông tin về giá và hạn mức của App Engine
- Ra mắt nền tảng App Engine thế hệ thứ hai (2018)
- So sánh đầu tiên và nền tảng thế hệ thứ hai
- Hỗ trợ dài hạn cho môi trường thời gian chạy cũ
- Kho lưu trữ mẫu di chuyển tài liệu
- Kho lưu trữ mẫu di chuyển do cộng đồng đóng góp
Thông tin khác về đám mây
- Python trên Google Cloud Platform
- Thư viện ứng dụng Google Cloud Python
- Google Cloud "Luôn miễn phí" cấp
- Google Cloud SDK (công cụ dòng lệnh
gcloud
) - Tất cả tài liệu của Google Cloud
Python
- Các hệ thống tạo mẫu Django và Jinja2
- Khung web
webapp2
- Tài liệu
webapp2
- Đường liên kết
webapp2_extras
- Tài liệu về Jinja2
webapp2_extras
- Khung web Flask
Video
- Trạm di chuyển không máy chủ
- Thám hiểm không máy chủ
- Đăng ký sử dụng Google Cloud Tech
- Đăng ký Google Developers
Giấy phép
Tác phẩm này được cấp phép theo Giấy phép chung Ghi nhận tác giả Creative Commons 2.0.