Docker là một ứng dụng mã nguồn mở cho phép quản trị viên tạo, quản lý, triển khai và nhân rộng các ứng dụng bằng cách sử dụng vùng chứa. Vùng chứa có thể được coi là một gói chứa các phụ thuộc mà ứng dụng yêu cầu để chạy ở cấp hệ điều hành. Điều này có nghĩa là mỗi ứng dụng được triển khai bằng Docker sống trong một môi trường riêng và các yêu cầu của nó được xử lý riêng biệt.
Flask là một web micro-framework được xây dựng trên Python. Nó được gọi là micro-framework vì nó không yêu cầu các công cụ hoặc plug-ins cụ thể để chạy. Flask framework nhẹ và linh hoạt, nhưng có cấu trúc cao, khiến nó trở nên đặc biệt phổ biến đối với các ứng dụng web nhỏ được viết bằng Python.
Triển khai ứng dụng Flask với Docker sẽ cho phép bạn sao chép ứng dụng trên các máy chủ khác nhau với cấu hình lại tối thiểu.
Trong hướng dẫn này, bạn sẽ tạo một ứng dụng Flask và triển khai nó với Docker. Hướng dẫn này cũng sẽ trình bày cách cập nhật ứng dụng sau khi triển khai.
Để làm theo hướng dẫn này, bạn sẽ cần những thứ sau:
Để bắt đầu, bạn sẽ tạo một cấu trúc thư mục chứa ứng dụng Flask của bạn. Hướng dẫn này sẽ tạo một thư mục có tên là TestApp
trong /var/www
, nhưng bạn có thể sửa đổi lệnh để đặt tên cho nó bất cứ thứ gì bạn muốn.
- sudo mkdir /var/www/TestApp
Di chuyển đến thư mục TestApp
mới được tạo:
- cd /var/www/TestApp
Tiếp theo, tạo cấu trúc thư mục cơ sở cho ứng dụng Flask:
- sudo mkdir -p app/static app/templates
Cờ -p
chỉ ra rằng mkdir
sẽ tạo một thư mục và tất cả các thư mục mẹ không tồn tại. Trong trường hợp này, mkdir
sẽ tạo thư mục mẹ app
trong quá trình tạo thư mục static
và thư mục templates
.
Thư mục app
sẽ chứa tất cả các tệp liên quan đến ứng dụng Flask như các dạng xem và bản thiết kế của nó. Lượt xem là mã bạn viết để phản hồi các yêu cầu đối với ứng dụng của bạn. Bản thiết kế tạo ra các thành phần ứng dụng và hỗ trợ các mẫu chung trong một ứng dụng hoặc trên nhiều ứng dụng.
Thư mục static
là nơi chứa các nội dung như hình ảnh, CSS và các tệp JavaScript. Thư mục templates
là nơi bạn sẽ đặt các mẫu HTML cho dự án của mình.
Bây giờ cấu trúc thư mục cơ sở đã hoàn tất, bạn cần tạo các tệp cần thiết để chạy ứng dụng Flask. Đầu tiên, tạo tệp __init__.py
bên trong thư mục app
bằng nano hoặc trình soạn thảo văn bản mà bạn chọn. Tệp này cho trình thông dịch Python biết rằng thư mục app
là một gói và phải được xử lý như vậy.
Chạy lệnh sau để tạo tệp:
- sudo nano app/__init__.py
Các gói trong Python cho phép bạn nhóm các mô-đun thành namespaces hoặc hierarchies (cấu trúc phân cấp hợp lý). Cách tiếp cận này cho phép mã được chia thành các khối riêng lẻ và có thể quản lý để thực hiện các chức năng cụ thể.
Tiếp theo, bạn sẽ thêm mã vào __init__.py
sẽ tạo một phiên bản Flask và nhập logic từ tệp views.py
, mà bạn sẽ tạo sau khi lưu tệp này. Thêm mã sau vào tệp mới của bạn:
from flask import Flask
app = Flask(__name__)
from app import views
Sau khi bạn đã thêm mã đó, hãy lưu và đóng tệp. Bạn có thể lưu và đóng tệp bằng cách nhấn Ctrl + X
, sau đó nhấn Y
và Enter
khi được nhắc.
Với tệp _init__.py
được tạo, bạn đã sẵn sàng tạo tệp views.py
trong thư mục app
của mình. Tệp này sẽ chứa hầu hết logic ứng dụng của bạn.
- sudo nano app/views.py
Tiếp theo, thêm mã vào tệp views.py
của bạn. Mã này sẽ trả lại chuỗi hello world!
cho những người dùng truy cập trang web của bạn:
from app import app
@app.route('/')
def home():
return "hello world!"
Dòng @app.route
phía trên hàm được gọi là decorator. Decorator là một quy ước ngôn ngữ Python được sử dụng rộng rãi bởi Flask; mục đích của chúng là sửa đổi các chức năng ngay sau chúng. Trong trường hợp này, decorator cho Flask biết URL nào sẽ kích hoạt hàm home ()
. Văn bản hello world
do chức năng home
trả về sẽ được hiển thị cho người dùng trên trình duyệt.
Với tệp views.py
đã có, bạn đã sẵn sàng tạo tệp uwsgi.ini
. Tệp này sẽ chứa các cấu hình uWSGI cho ứng dụng của chúng ta. uWSGI là một tùy chọn triển khai cho Nginx, vừa là một giao thức vừa là một máy chủ ứng dụng; máy chủ ứng dụng có thể phục vụ các giao thức uWSGI, FastCGI và HTTP.
Để tạo tệp này, hãy chạy lệnh sau:
- sudo nano uwsgi.ini
Tiếp theo, thêm nội dung sau vào tệp của bạn để thiết lập cấu hình máy chủ uWSGI:
[uwsgi]
module = main
callable = app
master = true
Mã này xác định mô-đun mà ứng dụng Flask sẽ được phục vụ từ đó. Trong trường hợp này, đây là tệp main.py
, được tham chiếu ở đây là tệp main
. Tùy chọn callable
hướng dẫn uWSGI sử dụng phiên bản app
được xuất bởi ứng dụng chính. Tùy chọn master
cho phép ứng dụng của bạn tiếp tục chạy, do đó có rất ít thời gian chết ngay cả khi tải lại toàn bộ ứng dụng.
Tiếp theo, tạo tệp main.py
, là điểm vào ứng dụng. Điểm đầu vào hướng dẫn uWSGI cách tương tác với ứng dụng.
- sudo nano main.py
Tiếp theo, sao chép và dán phần sau vào tệp. Thao tác này nhập phiên bản Flask có tên app
từ gói ứng dụng đã được tạo trước đó.
from app import app
Cuối cùng, tạo một tệp tin request.txt
để chỉ định các phần phụ thuộc mà trình quản lý gói pip
sẽ cài đặt cho việc triển khai Docker của bạn:
- sudo nano requirements.txt
Thêm dòng sau để thêm Flask làm phụ thuộc:
Flask>=2.0.2
Điều này chỉ định phiên bản Flask sẽ được cài đặt. Tại thời điểm viết hướng dẫn này, 2.0.2 là phiên bản Flask mới nhất và việc chỉ định > = 2.0.2
sẽ đảm bảo bạn nhận được phiên bản 2.0.2 hoặc mới hơn. Vì bạn đang tạo một ứng dụng thử nghiệm cơ bản trong hướng dẫn này, nên cú pháp có thể không lỗi thời do các bản cập nhật trong tương lai cho Flask, nhưng nếu bạn muốn an toàn và vẫn nhận được các bản cập nhật nhỏ, bạn có thể chỉ định rằng bạn không muốn cài đặt phiên bản chính trong tương lai bằng cách chỉ định một cái gì đó như Flask>=2.0.2,<3.0
. Bạn có thể kiểm tra các bản cập nhật tại trang web chính thức cho Flask hoặc trên landing page của Python Package Index cho thư viện Flask.
Lưu và đóng tập tin. Bạn đã thiết lập thành công ứng dụng Flask của mình và sẵn sàng thiết lập Docker.
Trong bước này, bạn sẽ tạo hai tệp, Dockerfile
và start.sh
, để tạo triển khai Docker của bạn. Dockerfile
là một tài liệu văn bản chứa các lệnh được sử dụng để lắp ráp hình ảnh. Tệp start.sh
là một shell script sẽ xây dựng một hình ảnh và tạo một vùng chứa từ Dockerfile
.
Đầu tiên, tạo Dockerfile
.
- sudo nano Dockerfile
Tiếp theo, thêm cấu hình mong muốn của bạn vào Dockerfile
. Các lệnh này chỉ định cách hình ảnh sẽ được xây dựng và những yêu cầu bổ sung nào sẽ được đưa vào.
FROM tiangolo/uwsgi-nginx-flask:python3.8-alpine
RUN apk --update add bash nano
ENV STATIC_URL /static
ENV STATIC_PATH /var/www/app/static
COPY ./requirements.txt /var/www/requirements.txt
RUN pip install -r /var/www/requirements.txt
Trong ví dụ này, Docker image sẽ được tạo từ một hình ảnh hiện có, tiangolo/uwsgi-nginx-flask
, mà bạn có thể tìm thấy trên DockerHub. Docker image cụ thể này là một lựa chọn tốt so với những hình ảnh khác vì nó hỗ trợ nhiều phiên bản Python và OS images.
Hai dòng đầu tiên chỉ định image gốc mà bạn sẽ sử dụng để chạy ứng dụng và cài đặt bộ xử lý lệnh bash và trình soạn thảo văn bản nano
. Nó cũng cài đặt ứng dụng khách git
để kéo và đẩy sang các dịch vụ lưu trữ kiểm soát phiên bản như GitHub, GitLab và Bitbucket. ENV STATIC_URL /static
là một biến môi trường dành riêng cho Docker image này. Nó xác định thư mục static nơi tất cả nội dung như hình ảnh, tệp CSS và tệp JavaScript được phục vụ từ đó.
Hai dòng cuối cùng sẽ sao chép tệp requirements.txt
vào vùng chứa để có thể thực thi tệp này, sau đó phân tích cú pháp tệp requirements.txt
để cài đặt các phần phụ thuộc đã chỉ định.
Lưu và đóng tệp sau khi thêm cấu hình của bạn.
Với Dockerfile
của bạn tại chỗ, bạn gần như đã sẵn sàng để viết start.sh
script sẽ xây dựng Docker container. Trước khi viết start.sh
script, hãy đảm bảo rằng bạn có một cổng mở để sử dụng trong cấu hình. Để kiểm tra xem một cổng có trống hay không, hãy chạy lệnh sau:
- sudo nc localhost 56733 < /dev/null; echo $?
Nếu đầu ra của lệnh trên là 1
, thì cổng là miễn phí và có thể sử dụng được. Nếu không, bạn sẽ cần chọn một cổng khác để sử dụng trong tệp cấu hình start.sh
của mình.
Khi bạn đã tìm thấy một cổng mở để sử dụng, hãy tạo start.sh
script:
sudo nano start.sh
start.sh
script là một shell script xây dựng hình ảnh từ Dockerfile
và tạo vùng chứa từ kết quả Docker image. Thêm cấu hình của bạn vào tệp mới:
#!/bin/bash
app="docker.test"
docker build -t ${app} .
docker run -d -p 56733:80 \
--name=${app} \
-v $PWD:/app ${app}
Dòng đầu tiên được gọi là shebang. Nó chỉ định rằng đây là tệp bash và sẽ được thực thi dưới dạng lệnh. Dòng tiếp theo chỉ định tên bạn muốn đặt cho hình ảnh và vùng chứa, và lưu dưới dạng một biến có tên app
. Dòng tiếp theo hướng dẫn Docker xây dựng một hình ảnh từ Dockerfile
của bạn nằm trong thư mục hiện tại. Điều này sẽ tạo ra một hình ảnh được gọi là docker.test
trong ví dụ này.
Ba dòng cuối cùng tạo một vùng chứa mới có tên docker.test
được hiển thị tại cổng 56733
. Cuối cùng, nó liên kết thư mục hiện tại với thư mục /var/www
của vùng chứa.
Bạn sử dụng cờ -d
để bắt đầu vùng chứa ở chế độ daemon hoặc background process. Bạn bao gồm cờ -p
để liên kết một cổng trên máy chủ với một cổng cụ thể trên Docker container. Trong trường hợp này, bạn đang liên kết cổng 56733
với cổng 80
trên Docker container. Cờ -v
chỉ định một ổ đĩa Docker để gắn vào container và trong trường hợp này, bạn đang gắn toàn bộ thư mục dự án vào thư mục /var/www
trên Docker container.
Lưu và đóng tệp sau khi thêm cấu hình của bạn.
Thực thi tập lệnh start.sh
để tạo Docker image và xây dựng vùng chứa từ hình ảnh kết quả:
- sudo bash start.sh
Khi tập lệnh chạy xong, hãy sử dụng lệnh sau để liệt kê tất cả các vùng chứa đang chạy:
- sudo docker ps
Bạn sẽ nhận được đầu ra hiển thị các vùng chứa:
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
58b05508f4dd docker.test "/entrypoint.sh /sta…" 12 seconds ago Up 3 seconds 443/tcp, 0.0.0.0:56733->80/tcp docker.test
Bạn sẽ thấy rằng bộ chứa docker.test
đang chạy. Bây giờ nó đang chạy, hãy truy cập địa chỉ IP tại cổng được chỉ định trong trình duyệt của bạn: http://ip-address:56733
Bạn sẽ thấy một trang tương tự như sau:
Ở bước này, bạn đã triển khai thành công ứng dụng Flask của mình trên Docker. Tiếp theo, bạn sẽ sử dụng các mẫu để hiển thị nội dung cho người dùng.
Mẫu là các tệp hiển thị nội dung tĩnh và động cho người dùng truy cập ứng dụng của bạn. Trong bước này, bạn sẽ tạo một mẫu HTML để tạo trang chủ cho ứng dụng.
Bắt đầu bằng cách tạo tệp home.html
trong thư mục app/templates
:
- sudo nano app/templates/home.html
Thêm mã cho mẫu của bạn. Mã này sẽ tạo một trang HTML5 chứa tiêu đề và một số văn bản.
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Welcome home</title>
</head>
<body>
<h1>Home Page</h1>
<p>This is the home page of our application.</p>
</body>
</html>
Lưu và đóng tệp sau khi bạn đã thêm mẫu của mình.
Tiếp theo, sửa đổi tệp app/views.py
để phục vụ tệp mới được tạo:
- sudo nano app/views.py
Trước tiên, hãy thêm dòng dưới đây vào đầu tệp của bạn để nhập phương thức render_template
từ Flask. Phương pháp này phân tích cú pháp tệp HTML để hiển thị trang web cho người dùng.
from flask import render_template
...
Ở cuối tệp, bạn cũng sẽ thêm một route mới để hiển thị tệp mẫu. Mã này chỉ định rằng người dùng được cung cấp nội dung của tệp home.html
bất cứ khi nào họ truy cập /template
route trên ứng dụng của bạn.
...
@app.route('/template')
def template():
return render_template('home.html')
Tệp app/views.py
được cập nhật sẽ trông như thế này:
from flask import render_template
from app import app
@app.route('/')
def home():
return "Hello world!"
@app.route('/template')
def template():
return render_template('home.html')
Lưu và đóng tệp khi hoàn tất.
Để những thay đổi này có hiệu lực, bạn cần dừng và khởi động lại bộ chứa Docker. Chạy lệnh sau để xây dựng lại vùng chứa:
- sudo docker stop docker.test && sudo docker start docker.test
Truy cập ứng dụng của bạn tại http://your-ip-address:56733/template
để xem mẫu mới đang được phân phát.
Trong phần này, bạn đã tạo tệp mẫu Docker để phục vụ khách truy cập trên ứng dụng của mình. Trong bước tiếp theo, bạn sẽ thấy những thay đổi bạn thực hiện đối với ứng dụng của mình có thể có hiệu lực như thế nào mà không cần phải khởi động lại bộ chứa Docker.
Đôi khi, bạn sẽ cần thực hiện các thay đổi đối với ứng dụng, cho dù đó là cài đặt các yêu cầu mới, cập nhật vùng chứa Docker hay các thay đổi logic và HTML. Trong phần này, bạn sẽ cấu hình touch-reload
để thực hiện những thay đổi này mà không cần khởi động lại bộ chứa Docker.
Tính năng tự động tải lại của Python theo dõi toàn bộ hệ thống tệp để tìm các thay đổi và làm mới ứng dụng khi phát hiện thấy thay đổi. Tự động tải lại (Autoreloading) không được khuyến khích trong sản xuất vì nó có thể sử dụng nhiều tài nguyên rất nhanh. Trong bước này, bạn sẽ sử dụng tính năng touch-reload
để theo dõi các thay đổi đối với một tệp cụ thể và tải lại khi tệp được cập nhật hoặc thay thế.
Để thực hiện điều này, hãy bắt đầu bằng cách mở tệp uwsgi.ini
của bạn:
- sudo nano uwsgi.ini
Tiếp theo, thêm dòng được đánh dấu vào cuối tệp:
module = main
callable = app
master = true
touch-reload = /app/uwsgi.ini
Điều này chỉ định một tệp sẽ được sửa đổi để kích hoạt tải lại toàn bộ ứng dụng. Khi bạn đã thực hiện các thay đổi, hãy lưu và đóng tệp.
Để chứng minh điều này, hãy thực hiện một thay đổi nhỏ đối với ứng dụng của bạn. Bắt đầu bằng cách mở tệp app/views.py
của bạn:
- sudo nano app/views.py
Thay thế chuỗi được trả về bởi hàm home
:
from flask import render_template
from app import app
@app.route('/')
def home():
return "<b>There has been a change</b>"
@app.route('/template')
def template():
return render_template('home.html')
Lưu và đóng tệp sau khi bạn thực hiện thay đổi.
Tiếp theo, nếu bạn mở trang chủ của ứng dụng tại http://ip-address:56733
, bạn sẽ nhận thấy rằng các thay đổi không được phản ánh. Điều này là do điều kiện để tải lại là thay đổi đối với tệp uwsgi.ini
. Để tải lại ứng dụng, hãy sử dụng touch
để kích hoạt điều kiện:
- sudo touch uwsgi.ini
Tải lại trang chủ ứng dụng trong trình duyệt của bạn. Bạn sẽ thấy rằng ứng dụng đã kết hợp các thay đổi:
Trong bước này, bạn thiết lập điều kiện touch-reload
để cập nhật ứng dụng của mình sau khi thực hiện các thay đổi.
Trong hướng dẫn này, bạn đã tạo và triển khai ứng dụng Flask cho bộ chứa Docker. Bạn cũng đã thiết lập cấu hình touch-reload
để làm mới ứng dụng của mình mà không cần khởi động lại bộ chứa.
Với ứng dụng mới của bạn trên Docker, giờ đây bạn có thể dễ dàng mở rộng quy mô. Để tìm hiểu thêm về cách sử dụng Docker, hãy xem tài liệu chính thức của họ.