Hướng dẫn lập trình Flask – Phần 18: Triển khai ứng dụng với Heroku

flask_tutorial_1

Trong phần này, chúng ta sẽ tìm hiểu cách triển khai ứng dụng Myblog trên dịch vụ đám mây Heroku.

Để giúp cho bạn dễ theo dõi, sau đây là danh sách các bài viết trong loạt bài hướng dẫn này:

Bạn có thể truy cập mã nguồn cho phần này tại GitHub.

Trong Phần 17, chúng ta đã tìm hiểu cách triển khai ứng dụng Python theo cách “truyền thống” qua hai ví dụ với máy chủ sử dụng Linux. Nếu bạn không quen với việc quản lý các hệ thống Linux, đây là một công việc rất tốn công và có lẽ bạn muốn tìm cách khác dễ hơn.

Trong phần này, chúng ta sẽ đi theo một hướng hoàn toàn khác và sẽ sử dụng một dịch vụ đám mây (cloud) để thực hiện phần lớn các công tác quản trị hệ thống và nhờ đó bạn có nhiều thời gian hơn để tập trung vào việc phát triển ứng dụng.

Nhiều dịch vụ điện toán đám mây cung cấp nền tảng để thực thi ứng dụng. Tất cả những gì cần thiết để triển khai ứng dụng của bạn trên các nền tảng này không có gì khác ngoài bản thân của ứng dụng, bởi vì phần cứng, hệ điều hành, các trình thông dịch, cơ sở dữ liệu v.v. đã được quản lý bởi dịch vụ này. Loại dịch vụ này được biết đến dưới tên gọi Platform as a Service (Nền tảng như dịch vụ) hay là PaaS.

Điều này khó tin quá phải không? Nhưng lại có thật và chúng ta sẽ sớm thấy lợi ích của PaaS khi kết thúc phần này.

Để làm quen với PaaS, chúng ta sẽ thử triển khai ứng dụng trên một dịch vụ điện toán đám mây tương đối phổ biến và thân thiện với các ứng dụng Python là Heroku. Một lý do khác nữa để chúng ta chọn Heroku là nó có một lớp dịch vụ miễn phí và nhờ đó chúng ta có thể thử nghiệm việc triển khai ứng dụng mà không phải trả tiền.

Ứng dụng trên Heroku

Heroku là một trong những nhà cung cấp giải pháp PaaS đầu tiên. Ban đầu, nó cung cấp giải pháp cho các ứng dụng viết bằng Ruby và sau đó tiếp tục phát triển để hỗ trợ nhiều loại ứng dụng với các ngôn ngữ khác nhau như là Java, Node.js và dĩ nhiên là Python.

Việc triển khai ứng dụng trên Heroku đòi hỏi phải sử dụng git. Vì vậy ứng dụng cần triển khai phải được đưa vào một hệ thống quản lý mã nguồn sử dụng git. Heroku sẽ tìm một file gọi là Procfile trong thư mục gốc của ứng dụng và dựa trên các chỉ dẫn trong file này để khởi động ứng dụng. Đối với các ứng dụng Python, Heroku cũng cần có file requirements.txt để tìm và cài đặt các thành phần mà ứng dụng phụ thuộc vào đã được liệt kê trong file này. Sau khi ứng dụng được đưa vào server Heroku thông qua git, việc triển khai xem như hoàn tất và bạn chỉ cần đợi một vài giây để ứng dụng bắt đầu làm việc. Tât cả quá trình chỉ đơn giản như thế.

Các lớp dịch vụ khác nhau của Heroku cho phép bạn chọn khả năng tính toán và thời gian cho ứng dụng của bạn. Vì vậy, khi ứng dụng của bạn có nhiều người sử dụng hơn, bạn sẽ cần mua thêm các đơn vị tính toán – gọi là “dynos” theo thuật ngữ của Heroku – để tăng khả năng xử lý cho ứng dụng.

Bạn đã sẵn sàng để thử nghiệm Heroku chưa? Chúng ta hãy bắt đầu.

Tạo tài khoản Heroku

Trước khi bắt đầu làm việc với Heroku, bạn cần tạo tài khoản với dịch vụ này. Vì vậy, hãy vào trang chủ của Heroku và đăng ký một tài khoản miễn phí. Sau đó, dùng tài khoản này đăng nhập vào  Heroku và bạn sẽ thấy một bảng điều khiển có liệt kê tất cả các ứng dụng của bạn trên nền tảng này.

Cài đặt công cụ dòng lệnh của Heroku

Heroku có cung cấp một công cụ dòng lệnh gọi là Heroku CLI để tương tác với các dịch vụ do nó cung cấp. Bạn có thể sử dụng công cụ này trong Windows, Mac OS X và Linux. Bạn có thể tìm đọc các hướng dẫn cài đặt trong tài liệu trực tuyến của Heroku. Nếu bạn muốn tiến hành các bước tiếp theo, hãy tải về và làm theo các hướng dẫn để cài đặt công cụ này trên máy tính của bạn.

Sau khi cài đặt Heroku CLI, hãy dùng nó để đăng nhập vào tài khoản Heroku của bạn:

Heroku sẽ yêu cầu bạn nhập phím bất kỳ để mở trình duyệt và đăng nhập như sau:

Bạn sẽ cần phải nhập vào địa chỉ email và mật mã cho tài khoản của bạn khi đăng nhập, sau đó, bạn đóng trình duyệt và trở lại với Heroku CLI, bạn sẽ thấy thông báo đăng nhập thành công:

Thiết lập Git

Công cụ quản lý mã nguồn git là thành phần quan trọng nhất trong quá trình triển khai ứng dụng trên Heroku. Do đó nếu bạn chưa có git trên hệ thống của bạn thì bạn cần cài đặt nó. Nếu hệ điều hành bạn đang sử dụng không có sẵn các gói cần thiết để cài đặt git, bạn có thể tải chương trình cài đặt trực tiếp từ Web site của git.

Có nhiều lý do cho việc sử dụng git trong dự án. Và nếu bạn muốn triển khai ứng dụng trên Heroku, bạn lại có thêm một lý do nữa. Bởi vì để triển khai dự án trên Heroku, mã nguồn cho dự án của bạn phải nằm trong một repository (kho lưu trữ) của git. Nếu bạn muốn kiểm tra việc triển khai ứng dụng Myblog mà không có repository của riêng bạn, bạn có thể tạo ra một bản sao (clone) của mã nguồn từ GitHub:

Lệnh git checkout sẽ chọn một commit (xác nhận lưu trữ dữ liệu) của mã nguồn cho phần này.

Nếu bạn muốn sử dụng mã nguồn của bạn thay vì mã có sẵn như trên, bạn có thể chuyển mã trong dự án của bạn thành một repository của git với lệnh git init . tại thư mục gốc của ứng dụng (Lưu ý đừng bỏ qua dấu chấm theo sau từ khóa init trong lệnh bởi vì đây là thông tin để git biết cần phải tạo repository tại thư mục hiện hành).

Tạo ứng dụng Heroku

Để đăng ký một ứng dụng với Heroku, bạn cần dùng lệnh app:create từ thư mục gốc của ứng dụng với một tham số duy nhất là tên của ứng dụng:

Heroku bắt buộc mỗi ứng dụng phải có một tên duy nhất và không trùng lặp. Vì vậy, khi thử nghiệm, bạn phải dùng một tên khác thay vì flask-myblog-test bởi vì chúng ta đã dùng tên này cho ví dụ này.

Trong quá trình thực hiện lệnh này, Heroku sẽ in ra các URL đã được gán cho ứng dụng và repository tương ứng. Repository trên máy của bạn sẽ được thêm một kết nối từ xa (remote) gọi là heroku. Bạn có thể kiểm tra điều này với lệnh git remote:

Tùy theo cách bạn tạo ra repository trên máy của bạn, các dòng kết quả của lệnh trên có thể có thêm một kết nối từ xa nữa gọi là origin.

Hệ thống file ngắn hạn (Ephemeral File System)

Một trong những điểm khác biệt giữa Heroku và các dịch vụ khác là nó sử dụng hệ thống file ngắn hạn (ephemeral). Điều này có nghĩa là gì? Nó đồng nghĩa với việc Heroku có thể khởi động lại các máy chủ ảo có ứng dụng của bạn tại bất kỳ thời điểm nào để đưa chúng trở lại trạng thái ban đầu đồng thời xóa bỏ tất cả các file không nằm trong mã nguồn được tải lên khi khởi tạo ứng dụng. Bạn không thể triển khai các ứng dụng với giả định là các dữ liệu đã được ứng dụng của bạn lưu vào các file sẽ tồn tại lâu dài. Và trong thực tế, Heroku rất thường xuyên làm việc này.

Đặc tính này dẫn đến một vài rắc rối với ứng dụng của chúng ta khi triển khai trên Heroku như sau:

  • Cơ sở dữ liệu SQLite mà chúng ta đã sử dụng từ đầu ghi dữ liệu vào file.
  • Hệ thống nhật ký (log) mà ứng dụng đang dùng cũng cập nhật dữ liệu vào file
  • Việc chuyển ngữ cũng sử dụng các file để chứa các văn bản/thông điệp trong ứng dụng bằng các thứ tiếng khác nhau.

Chúng ta sẽ lần lượt tìm cách giải quyết các vấn đề này trong phần tiếp theo.

Làm việc với cơ sở dữ liệu Postgres của Heroku

Để xử lý vấn đề đầu tiên, chúng ta sẽ đổi sang một hệ thống cơ sở dữ liệu khác. Trong Phần 17, chúng ta đã sử dụng cơ sở dữ liệu MySQL khi triển khai ứng dụng trên Ubuntu. Heroku cung cấp sẵn một hệ cơ sở dữ liệu là Postgres, vì vậy chúng ta sẽ đổi sang hệ cơ sở dữ liệu này để giải quyết việc sử dụng file của SQLite. Điều này cũng cho thấy sự linh động của ứng dụng Flask khi chúng ta có thể chuyển đổi giữa các hệ cơ sở dữ liệu dữ liệu một cách dễ dàng.

Để khởi tạo cơ sở dữ liệu cho ứng dụng trên Heroku, chúng ta có thể sử dụng công cụ Heroku CLI. Ở đây, chúng ta sẽ tạo một cơ sở dữ liệu miễn phí:

URL của cơ sở dữ liệu này sẽ được lưu trong biến môi trường DATABASE_URL. Điều này rất tiện lợi vì ứng dụng của chúng ta cũng tìm URL của cơ sở dữ liệu qua biến môi trường này.

Ghi nhật ký ứng dụng vào stdout

Trong Heroku, nhật ký ứng dụng phải được gởi trực tiếp đến stdout. Tất cả dữ liệu từ nhật ký ứng dụng gởi đến kết xuất chuẩn (standard output hay là stdout) được lưu lại và có thể truy cập được khi sử dụng lệnh heroku logs. Vì vậy chúng ta sẽ thêm một biến cấu hình vào ứng dụng để chỉ định chúng ta muốn ghi nhật ký vào stdout hay vào file như trước đây:

config.py: Tùy chọn để ghi nhật ký ứng dụng vào stdout.

Sau đó trong hàm tạo ứng dụng, chúng ta có thể kiểm tra biến này để thiết lập cấu hình phù hợp cho nhật ký ứng dụng:

app/__init__.py: Ghi nhật ký vào stdout hoặc file.

Tiếp theo, chúng  ta cần thiết lập biến môi trường LOG_TO_STDOUT khi ứng dụng chạy trong Heroku (nhưng không sử dụng cho các cấu hình khác khi ứng dụng chạy trong các môi trường khác). Một lần nữa, chúng ta sẽ thực hiện công việc này với sự giúp đỡ của Heroku CLI:

Các file chuyển ngữ

Vấn đề cuối cùng của ứng dụng Myblog có liên quan đến hệ thống file là các file cho việc chuyển ngữ vì các file này không nằm trong mã nguồn ban đầu khi khởi tạo ứng dụng. Cách giải quyết trực tiếp nhất để bảo đảm các file này không bị hệ thống file của Heroku xóa đi là đưa chúng vào repository của git (như đối với các file mã nguồn), và nhờ đó, các file này sẽ trở thành thành phần ban đầu của ứng dụng khi triển khai trên Heroku.

Tuy nhiên, có một cách giải quyết tốt hơn là sử dụng lệnh flask translate compile khi khởi động ứng dụng trong Heroku. Nhờ vậy, mỗi khi server khởi động lại, các file này lại được tạo ra. Chúng ta sẽ đi theo hướng này vì chúng ta cũng sẽ cần thi hành một số lệnh khác trong quá trình khởi động ứng dụng như là lệnh chuyển đổi dữ liệu. Vì vậy, tạm thời chúng ta sẽ để vấn đề này sang một bên và trở lại khi chúng ta tạo ra Profile trong phần sau.

Cài đặt Elasticsearch

Chúng ta cũng có thể cài đặt Elasticsearch với Heroku. Tuy vậy, không như Postgres, Heroku không trực tiếp cung cấp dịch vụ này mà phải nhờ vào một đối tác khác. Tại thời điểm này, có ba nhà cung cấp khác nhau có hỗ trợ cho Elasticsearch trong Heroku.

Trước khi thiết lập Elasticsearch, bạn cần biết rằng Heroku yêu cầu bạn phải cung cấp số thẻ tín dụng trước khi cài đặt các phần mềm bổ sung (add-on) từ các đối tác khác, ngay cả khi bạn sử dụng lớp (tier) miễn phí. Nếu bạn không muốn dùng thẻ tín dụng với Heroku, bạn có thể bỏ qua phần này. Bạn vẫn có thể triển khai ứng dụng, chỉ có chức năng tìm kiếm không hoạt động mà thôi. Trong các tùy chọn Elasticsearch được sử dụng với Heroku, chúng ta sẽ sử dụng SearchBox. Đây là một dịch vụ bổ sung tốt và có cho phép sử dụng miễn phí. Để thêm SearchBox vào tài khoản của bạn, hãy đăng nhập vào Heroku và chạy lệnh sau đây:

Lệnh này sẽ triển khai dịch vụ Elasticsearch và lưu URL để kết nối vào dịch vụ này vào biến môi trường SEARCHBOX_URL trong ứng dụng của bạn. Một lần nữa, bạn cần lưu ý rằng lệnh này sẽ không hoạt động nếu bạn không cung cấp số thẻ tín dụng trong tài khoản Heroku của bạn.

Nếu bạn còn nhớ trong Phần 16, ứng dụng của chúng ta sẽ tìm địa chỉ kết nối với Elasticsearch từ biến môi trường ELASTICSEARCH_URL, vì vậy, chúng ta cần tạo ra biến môi trường này và gán cho nó URL để kết nối do SearchBox cung cấp:

Với các lệnh trên, chúng ta dùng Heroku để in ra giá trị của biến môi trường  SEARCHBOX_URL và sau đó tạo ra một biến môi trường mới gọi là ELASTICSEARCH_URL và gán giá trị này cho nó.

Cập nhật các thành phần hỗ trợ của ứng dụng

Heroku giả định là các thành phần hỗ trợ mà ứng dụng cần dùng sẽ nằm trong file requirements.txt. File này có cấu trúc và nội dung hoàn toàn giống file requirements.txt mà chúng ta tạo ra với lệnh pip freeze như trong Phần 15. Nhưng để ứng dụng có thể hoạt động được với Heroku, chúng ta cần tạo thêm hai gói hỗ trợ nữa vào file này.

Heroku không cung cấp phần mềm Web Server cho ứng dụng. Thay vào đó, nó giả định rằng ứng dụng sẽ sử dụng phần mềm Web server của riêng nó tại cổng có địa chỉ được cung cấp trong biến môi trường $PORT. Bởi vì phần mềm Web server có sẵn trong Flask không đủ đáp ứng cho nhu cầu sử dụng trên máy chủ chính thức, chúng ta lại sẽ dùng gunicorn. Đây cũng là phần mềm Web server được Heroku đề cử cho các ứng dụng Python.

Và vì ứng dụng cũng sẽ sử dụng cơ sở dữ liệu Postgres, chúng ta cần cài đặt gói psycopg2 để SQLAlchemy có thể kết nối và truy vấn dữ liệu từ Postgres.

Chúng ta sẽ thêm thông tin cho cả hai gói gunicornpsycopg2 vào file requirements.txt.

Tổng quát về Procfile

Procfile là tên gọi của file dùng để cung cấp các chỉ dẫn về cách thực thi ứng dụng trong Heroku. File này sẽ được đặt ở thư mục gốc của ứng dụng và có cấu trúc tương đối đơn giản. Mỗi dòng của file bao gồm tên của một tiến trình, dấu hai chấm và lệnh để bắt đầu thực hiện tiến trình đó. Hiện giờ, loại ứng dụng phổ biến nhất trên Heroku là các ứng dụng Web, vì vậy tên của tiến trình cho loại ứng dụng này là web. Sau đây là Procfile của Myblog:

Procfile: Procfile của Myblog trên Heroku

Ở đây, chúng ta định nghĩa lệnh để bắt đầu ứng dụng bao gồm ba lệnh tiếp nối nhau. Đầu tiên, chúng ta thực hiện lệnh chuyển đổi dữ liệu, sau đó đến lệnh chuyển ngữ, và cuối cùng là lệnh để chạy phần mềm Web server.

Bởi vì hai lệnh đầu tiên ở trên dựa vào lệnh flask, chúng ta cần thêm biến môi trường FLASK_APP:

Ngoài ra, ứng dụng cũng cần thêm một số biến môi trường khác như là tham số cấu hình cho email server hoặc khóa để dịch thuật trực tiếp. Các biến môi trường này cần được thiết lập thông qua lệnh heroku config:set.

Nếu để ý, bạn sẽ thấy lệnh gunicorn mà chúng ta dùng lần này đơn giản hơn so với khi triển khai ứng dụng trên Ubuntu. Lý do là vì phần mềm này được hỗ trợ tích hợp tốt hơn trong Heroku. Ví dụ như biến môi trường $PORT có sẵn theo mặc định, và thay vì dùng tùy chọn –w để thiết lập số worker, Heroku cho phép chúng ta dùng một biến gọi là WEB_CONCURRENCY vốn được gunicorn sử dụng khi tham số –w không được cung cấp. Điều này cho phép chúng ta có thể quản lý số lượng worker một cách linh động mà không cần phải thay đổi nội dung của Procfile.

Triển khai ứng dụng

Đến đây, chúng ta đã hoàn tất các bước chuẩn bị và sẵn sàng để thực hiện việc triển khai ứng dụng. Để tải ứng dụng vào máy chủ của Heroku, chúng ta cần dùng lệnh git push. Công việc này tương tự như khi bạn cần đưa các thay đổi trong mã nguồn được quản lý bởi git từ máy của bạn đến GitHub hoặc các server git từ xa khác.

Việc push mã nguồn từ máy của bạn đến ứng dụng trên máy chủ Heroku rất đơn giản nhưng cũng là phần thú vị nhất. Tất cả những gì chúng ta cần làm trong công đoạn này là dùng git để push mã nguồn của ứng dụng vào nhánh (branch) master của kho chứa mã nguồn git của Heroku. Nếu bạn đang sử dụng mã nguồn đi kèm theo bài viết này và theo đúng các hướng dẫn từ đầu đến thời điểm này, bạn cần tạo ra một nhánh mới và push nó về nhánh master tại server của Heroku như sau:

Còn nếu bạn đang sử dụng repository của riêng bạn thì nhiều khả năng là mã nguồn của bạn đang ở tại nhánh master, vì vậy bạn cần phải đảm bảo rằng các cập nhật trong mã nguồn của bạn đã được xác nhận và lưu (commit):

Và sau đó, bạn có thể dùng lệnh sau để bắt đầu quá trình triển khai:

Dù dùng cách nào trong hai cách trên, bạn sẽ thấy cùng kết quả tương tự như sau từ server Heroku:

Nhãn heroku mà chúng ta dùng trong lệnh git push là tên của hệ thống git từ xa được Heroku CLI tự động đưa vào khi chúng ta khởi tạo ứng dụng trên máy chủ Heroku. Tham số deploy:master có  nghĩa là chúng ta sẽ push mã nguồn từ nhánh deploy trong máy của bạn đến nhánh master trên máy chủ Heroku. Khi bạn làm việc với các dự án riêng của bạn, nhiều khả năng là bạn sẽ sử dụng lệnh git push heroku master để thực hiện quá trình push từ nhánh master trên máy của bạn. Do cách sắp đặt trong dự án này, chúng ta push một nhánh không phải là master từ máy của chúng ta, nhưng nhánh mà chúng ta cần push đến tại máy chủ Heroku luôn luôn phải là master theo quy ước của Heroku.

Và như vậy chúng ta đã xong. Ứng dụng đã được triển khai tại địa chỉ được in ra trong lệnh triển khai ở trên. Trong trường hợp này, địa chỉ ứng dụng là https://flask-myblog-test.herokuapp.com và chúng ta có thể truy cập ứng dụng qua địa chỉ này.

Nếu bạn muốn thấy nhật ký của ứng dụng, bạn có thể dùng lệnh heroku logs. Lệnh này rất hữu dụng trong trường hợp ứng dụng không khởi động được hay có lỗi vì các thông báo lỗi sẽ nằm trong nhật ký ứng dụng.

Cập nhật ứng dụng

Để triển khai các phiên bản mới hơn của ứng dụng, bạn chỉ cần thực hiện lại lệnh git push với mã nguồn mới. Việc này sẽ lặp lại quá trình triển khai, tạm ngưng hoạt động phiên bản cũ của ứng dụng và thay thế bằng mã nguồn mới. Trong quá trình này, các lệnh trong Procfile cũng sẽ được thi hành, và qua đó sẽ tiến hành cập nhật các mô hình dữ liệu cũng như chuyển ngữ.

Chúng ta sẽ tạm ngừng ở đây. Hẹn gặp bạn trong phần tiếp theo.

Leave a Reply

Your email address will not be published. Required fields are marked *