Thứ sáu, 11/10/2019 | 00:00 GMT+7

Cách thiết lập Flask với MongoDB và Docker

Việc phát triển các ứng dụng web có thể trở nên phức tạp và tốn thời gian khi xây dựng và duy trì một số công nghệ khác nhau. Xem xét các tùy chọn trọng lượng nhẹ hơn được thiết kế để giảm độ phức tạp và thời gian production cho ứng dụng của bạn có thể dẫn đến một giải pháp linh hoạt hơn và có thể mở rộng.

Là một khuôn khổ web vi mô được xây dựng trên Python , Flask cung cấp một cách có thể mở rộng cho các nhà phát triển để phát triển ứng dụng của họ thông qua các phần mở rộng có thể được tích hợp vào các dự án. Để tiếp tục khả năng mở rộng của ngăn xếp công nghệ của nhà phát triển, MongoDB là database NoSQL được thiết kế để mở rộng quy mô và hoạt động với những thay đổi thường xuyên. Các nhà phát triển có thể sử dụng Docker để đơn giản hóa quá trình đóng gói và triển khai ứng dụng của họ.

Docker Compose đã đơn giản hóa hơn nữa môi trường phát triển bằng cách cho phép bạn xác định cơ sở hạ tầng của bạn , bao gồm các dịch vụ ứng dụng, dung lượng mạng và các liên kết mount , trong một file duy nhất. Sử dụng Docker Compose giúp dễ sử dụng hơn khi chạy nhiều lệnh docker container run . Nó cho phép bạn xác định tất cả các dịch vụ của bạn trong một file Soạn duy nhất và với một lệnh duy nhất, bạn tạo và khởi động tất cả các dịch vụ từ cấu hình của bạn . Điều này đảm bảo có kiểm soát version trong toàn bộ cơ sở hạ tầng containers của bạn. Docker Compose sử dụng tên dự án để cách ly các môi trường với nhau, điều này cho phép bạn chạy nhiều môi trường trên một server duy nhất.

Trong hướng dẫn này, bạn sẽ xây dựng, đóng gói và chạy ứng dụng web việc cần làm của bạn với Flask, Nginx và MongoDB bên trong vùng chứa Docker. Bạn sẽ xác định toàn bộ cấu hình trong file docker-compose.yml , cùng với các file cấu hình cho Python, MongoDB và Nginx. Flask yêu cầu một web server để phục vụ các yêu cầu HTTP, vì vậy bạn cũng sẽ sử dụng Gunicorn , một Server Python WSGI HTTP, để phục vụ ứng dụng. Nginx hoạt động như một server Reverse Proxy chuyển tiếp các yêu cầu tới Gunicorn để xử lý.

Yêu cầu

Để làm theo hướng dẫn này, bạn cần cài server  linux trước sau đó theo các hướng dẫn sau.


Bước 1 - Viết cấu hình trong Docker Compose

Việc xây dựng các ứng dụng của bạn trên Docker cho phép bạn dễ dàng version cơ sở hạ tầng tùy thuộc vào các thay đổi cấu hình bạn thực hiện trong Docker Compose. Cơ sở hạ tầng có thể được xác định trong một file duy nhất và được xây dựng bằng một lệnh duy nhất. Trong bước này, bạn sẽ cài đặt file docker-compose.yml để chạy ứng dụng Flask của bạn .

Tệp docker-compose.yml cho phép bạn xác định cơ sở hạ tầng ứng dụng của bạn dưới dạng các dịch vụ riêng lẻ. Các dịch vụ có thể được kết nối với nhau và mỗi dịch vụ có thể có một ổ đĩa được đính kèm để lưu trữ liên tục. Các tập được lưu trữ trong một phần của hệ thống file server do Docker quản lý ( /var/lib/docker/volumes/ trên Linux).

Các tập là cách tốt nhất để duy trì dữ liệu trong Docker, vì dữ liệu trong các tập có thể được xuất hoặc chia sẻ với các ứng dụng khác.Để biết thêm thông tin về chia sẻ dữ liệu trong Docker, bạn có thể tham khảo Cách chia sẻ dữ liệu giữa Docker Container và Host .

Để bắt đầu, hãy tạo một folder cho ứng dụng trong folder chính trên server của bạn:

  • mkdir flaskapp

Di chuyển vào folder mới tạo:

  • cd flaskapp

Tiếp theo, tạo file docker-compose.yml :

  • nano docker-compose.yml

Tệp docker-compose.yml bắt đầu bằng số version xác định phiên bản file Docker Compose . Docker Compose file version 3 nhắm đến Docker Engine version 1.13.0+ , đây là yêu cầu cho cài đặt này. Bạn cũng sẽ thêm thẻ services mà bạn sẽ xác định trong bước tiếp theo:

docker-compos.yml
version: '3' services: 

Đến đây bạn sẽ xác định flask là dịch vụ đầu tiên trong file docker-compose.yml . Thêm mã sau để xác định dịch vụ Flask:

docker-compos.yml
. . .   flask:     build:       context: app       dockerfile: Dockerfile     container_name: flask     image: digitalocean.com/flask-python:3.6     restart: unless-stopped     environment:       APP_ENV: "prod"       APP_DEBUG: "False"       APP_PORT: 5000       MONGODB_DATABASE: flaskdb       MONGODB_USERNAME: flaskuser       MONGODB_PASSWORD: your_mongodb_password       MONGODB_HOSTNAME: mongodb     volumes:       - appdata:/var/www     depends_on:       - mongodb     networks:       - frontend       - backend 

Thuộc tính bản build xác định context của bản dựng. Trong trường hợp này, folder app sẽ chứa Dockerfile .

Bạn sử dụng thuộc tính container_name để xác định tên cho mỗi containers . Thuộc tính image chỉ định tên hình ảnh và Docker image sẽ được gắn thẻ là gì. Thuộc tính restart xác định cách containers sẽ được khởi động lại — trong trường hợp của bạn, nó là unless-stopped . Điều này nghĩa là các containers của bạn sẽ chỉ bị dừng khi Docker Engine bị dừng / khởi động lại hoặc khi bạn dừng các containers một cách rõ ràng. Lợi ích của việc sử dụng thuộc tính unless-stopped là các containers sẽ tự động khởi động sau khi Công cụ Docker được khởi động lại hoặc bất kỳ lỗi nào xảy ra.

Thuộc tính environment chứa các biến môi trường được chuyển đến containers . Bạn cần cung cấp password an toàn cho biến môi trường MONGODB_PASSWORD . Thuộc tính volumes xác định dung lượng dịch vụ đang sử dụng. Trong trường hợp của bạn, volume appdata được gắn bên trong containers tại folder /var/www . depends_on tính depends_on xác định một dịch vụ mà Flask phụ thuộc vào để hoạt động bình thường. Trong trường hợp này, dịch vụ flask sẽ phụ thuộc vào mongodb vì dịch vụ mongodb hoạt động như database cho ứng dụng của bạn. depends_on đảm bảo dịch vụ flask chỉ chạy nếu dịch vụ mongodb đang chạy.

Thuộc tính networks chỉ định frontendbackend là các mạng mà dịch vụ flask sẽ có quyền truy cập.

Với dịch vụ flask được xác định, bạn đã sẵn sàng thêm cấu hình MongoDB vào file . Trong ví dụ này, bạn sẽ sử dụng hình ảnh mongo version 4.0.8 chính thức. Thêm mã sau vào file docker-compose.yml của bạn sau flask service :

docker-compos.yml
. . .   mongodb:     image: mongo:4.0.8     container_name: mongodb     restart: unless-stopped     command: mongod --auth     environment:       MONGO_INITDB_ROOT_USERNAME: mongodbuser       MONGO_INITDB_ROOT_PASSWORD: your_mongodb_root_password       MONGO_INITDB_DATABASE: flaskdb       MONGODB_DATA_DIR: /data/db       MONDODB_LOG_DIR: /dev/null     volumes:       - mongodbdata:/data/db     networks:       - backend 

container_name cho dịch vụ này là mongodb với policy khởi động lại là unless-stopped . Bạn sử dụng thuộc tính command để xác định lệnh sẽ được thực thi khi containers được khởi động. Lệnh mongod --auth sẽ vô hiệu hóa việc đăng nhập vào MongoDB shell mà không có thông tin xác thực, điều này sẽ bảo mật MongoDB bằng cách yêu cầu xác thực.

Các biến môi trường MONGO_INITDB_ROOT_USERNAMEMONGO_INITDB_ROOT_PASSWORD tạo user root với thông tin xác thực đã cho, vì vậy hãy đảm bảo thay thế trình giữ chỗ bằng một password mạnh.

MongoDB lưu trữ dữ liệu của nó trong /data/db theo mặc định, do đó dữ liệu trong folder /data/db sẽ được ghi vào mongodbdatamongodbdata được đặt tên để duy trì lâu dài. Do đó, bạn sẽ không mất database của bạn trong trường hợp khởi động lại. Dịch vụ mongoDB không tiết lộ bất kỳ cổng nào, vì vậy dịch vụ sẽ chỉ có thể truy cập được thông qua mạng backend .

Tiếp theo, bạn sẽ xác định web server cho ứng dụng của bạn . Thêm mã sau vào file docker-compose.yml của bạn để cấu hình Nginx:

docker-compos.yml
. . .   webserver:     build:       context: nginx       dockerfile: Dockerfile     image: digitalocean.com/webserver:latest     container_name: webserver     restart: unless-stopped     environment:       APP_ENV: "prod"       APP_NAME: "webserver"       APP_DEBUG: "false"       SERVICE_NAME: "webserver"     ports:       - "80:80"       - "443:443"     volumes:       - nginxdata:/var/log/nginx     depends_on:       - flask     networks:       - frontend 

Ở đây bạn đã xác định context của bản build , đó là folder nginx chứa Dockerfile . Với thuộc tính image , bạn chỉ định hình ảnh được sử dụng để gắn thẻ và chạy containers . Thuộc tính ports sẽ cấu hình dịch vụ Nginx để có thể truy cập thông qua :80:443 và các volumes gắn nginxdata bên trong containers tại folder /var/log/nginx .

Bạn đã xác định các dịch vụ trên mà dịch vụ web server depends_on như flask . Cuối cùng thuộc tính networks xác định dịch vụ web server của mạng sẽ có quyền truy cập frontend .

Tiếp theo, bạn sẽ tạo mạng cầu nối để cho phép các container giao tiếp với nhau. Nối các dòng sau vào cuối file của bạn:

docker-compos.yml
. . . networks:   frontend:     driver: bridge   backend:     driver: bridge 

Bạn đã xác định hai mạng — frontendbackend — để các dịch vụ kết nối với. Các dịch vụ front-end, chẳng hạn như Nginx, sẽ kết nối với mạng frontend vì nó cần được truy cập . Các dịch vụ back-end, chẳng hạn như MongoDB, sẽ kết nối với mạng backend để ngăn chặn truy cập trái phép vào dịch vụ.

Tiếp theo, bạn sẽ sử dụng dung lượng để duy trì database , ứng dụng và file cấu hình. Vì ứng dụng của bạn sẽ sử dụng database và file , nên bắt buộc phải duy trì các thay đổi được thực hiện cho chúng. Các tập được Docker quản lý và lưu trữ trên hệ thống file . Thêm mã này vào file docker-compose.yml để cấu hình các ổ đĩa:

docker-compos.yml
. . . volumes:   mongodbdata:     driver: local   appdata:     driver: local   nginxdata:     driver: local 

Phần volumes khai báo các dung lượng mà ứng dụng sẽ sử dụng để lưu giữ dữ liệu. Ở đây, bạn đã xác định các dung lượng mongodbdata , appdatanginxdata để duy trì database MongoDB, dữ liệu ứng dụng Flask và log web server Nginx tương ứng. Tất cả các ổ này sử dụng một trình điều khiển local để lưu trữ dữ liệu local . Các ổ đĩa được sử dụng để duy trì dữ liệu này để dữ liệu như database MongoDB và log web server Nginx của bạn có thể bị mất khi bạn khởi động lại containers .

Tệp docker-compose.yml hoàn chỉnh của bạn sẽ trông giống như sau:

docker-compos.yml
version: '3' services:    flask:     build:       context: app       dockerfile: Dockerfile     container_name: flask     image: digitalocean.com/flask-python:3.6     restart: unless-stopped     environment:       APP_ENV: "prod"       APP_DEBUG: "False"       APP_PORT: 5000       MONGODB_DATABASE: flaskdb       MONGODB_USERNAME: flaskuser       MONGODB_PASSWORD: your_mongodb_password       MONGODB_HOSTNAME: mongodb     volumes:       - appdata:/var/www     depends_on:       - mongodb     networks:       - frontend       - backend    mongodb:     image: mongo:4.0.8     container_name: mongodb     restart: unless-stopped     command: mongod --auth     environment:       MONGO_INITDB_ROOT_USERNAME: mongodbuser       MONGO_INITDB_ROOT_PASSWORD: your_mongodb_root_password       MONGO_INITDB_DATABASE: flaskdb       MONGODB_DATA_DIR: /data/db       MONDODB_LOG_DIR: /dev/null     volumes:       - mongodbdata:/data/db     networks:       - backend    webserver:     build:       context: nginx       dockerfile: Dockerfile     image: digitalocean.com/webserver:latest     container_name: webserver     restart: unless-stopped     environment:       APP_ENV: "prod"       APP_NAME: "webserver"       APP_DEBUG: "true"       SERVICE_NAME: "webserver"     ports:       - "80:80"       - "443:443"     volumes:       - nginxdata:/var/log/nginx     depends_on:       - flask     networks:       - frontend  networks:   frontend:     driver: bridge   backend:     driver: bridge  volumes:   mongodbdata:     driver: local   appdata:     driver: local   nginxdata:     driver: local 

Lưu file và thoát khỏi editor sau khi xác minh cấu hình của bạn.

Bạn đã xác cấu hình Docker cho toàn bộ ứng dụng của bạn trong file docker-compose.yml . Đến đây bạn sẽ chuyển sang viết Dockerfiles cho Flask và web server .

Bước 2 - Viết Dockerfiles của Flask và Server Web

Với Docker, bạn có thể xây dựng các containers để chạy các ứng dụng của bạn từ một file có tên Dockerfile . Dockerfile là một công cụ cho phép bạn tạo các hình ảnh tùy chỉnh mà bạn có thể sử dụng để cài đặt phần mềm theo yêu cầu của ứng dụng và cấu hình containers dựa trên yêu cầu của bạn. Bạn có thể đẩy các hình ảnh tùy chỉnh mà bạn tạo vào Docker Hub hoặc bất kỳ cơ quan đăng ký riêng tư nào.

Trong bước này, bạn sẽ viết Dockerfiles cho các dịch vụ Flask và web server . Để bắt đầu, hãy tạo folder app cho ứng dụng Flask của bạn:

  • mkdir app

Tiếp theo, tạo Dockerfile cho ứng dụng Flask của bạn trong folder app :

  • nano app/Dockerfile

Thêm mã sau vào file để tùy chỉnh containers Flask của bạn:

app / Dockerfile
FROM python:3.6.8-alpine3.9  LABEL MAINTAINER="FirstName LastName <example@domain.com>"  ENV GROUP_ID=1000 \     USER_ID=1000  WORKDIR /var/www/ 

Trong Dockerfile này, bạn đang tạo một hình ảnh phía trên hình ảnh 3.6.8-alpine3.9 dựa trên Alpine 3.9 với Python 3.6.8 được cài đặt sẵn.

Chỉ thị ENV được sử dụng để xác định các biến môi trường cho group và ID user của ta .
Cơ sở tiêu chuẩn Linux (LSB) chỉ định rằng UID và GID 0-99 được hệ thống cấp phát tĩnh. UID 100-999 phải được cấp phát động cho user hệ thống và group . UID 1000-59999 được cho là sẽ được cấp phát động cho account user . Lưu ý điều này, bạn có thể chỉ định một cách an toàn UID và GID là 1000 , hơn nữa bạn có thể thay đổi UID / GID bằng cách cập nhật GROUP_IDUSER_ID để phù hợp với yêu cầu của bạn.

Chỉ thị WORKDIR xác định folder làm việc cho containers . Đảm bảo thay thế trường LABEL MAINTAINER bằng tên và địa chỉ email của bạn.

Thêm khối mã sau để sao chép ứng dụng Flask vào containers và cài đặt các phần phụ thuộc cần thiết:

app / Dockerfile
. . . ADD ./requirements.txt /var/www/requirements.txt RUN pip install -r requirements.txt ADD . /var/www/ RUN pip install gunicorn 

Đoạn mã sau sẽ sử dụng lệnh ADD để sao chép file từ folder app local vào folder /var/www trên containers . Tiếp theo, Dockerfile sẽ sử dụng RUN chỉ thị để cài đặt Gunicorn và các gói được quy định trong requirements.txt file , mà bạn sẽ tạo ra sau đó trong hướng dẫn.

Khối mã sau thêm một user và group mới và chạy ứng dụng:

app / Dockerfile
. . . RUN addgroup -g $GROUP_ID www RUN adduser -D -u $USER_ID -G www www -s /bin/sh  USER www  EXPOSE 5000  CMD [ "gunicorn", "-w", "4", "--bind", "0.0.0.0:5000", "wsgi"] 

Theo mặc định, containers Docker chạy với quyền user gốc . User root có quyền truy cập vào mọi thứ trong hệ thống, do đó, hệ lụy của việc vi phạm bảo mật có thể rất thảm khốc. Để giảm thiểu rủi ro bảo mật này, điều này sẽ tạo một user và group mới sẽ chỉ có quyền truy cập vào folder /var/www .

Đoạn mã này trước tiên sẽ sử dụng lệnh addgroup để tạo một group mới có tên www . Cờ -g sẽ đặt ID group thành biến ENV GROUP_ID=1000 được định nghĩa đó trong Dockerfile .

Dòng adduser -D -u $USER_ID -G www www -s /bin/sh tạo user www với ID user là 1000 , như được xác định bởi biến ENV . Cờ -s tạo folder chính của user nếu nó không tồn tại và đặt shell đăng nhập mặc định thành /bin/sh . Cờ -G được sử dụng để đặt group đăng nhập ban đầu của user thành www , được tạo bởi lệnh trước đó.

Lệnh USER xác định rằng các chương trình chạy trong containers sẽ sử dụng user www . Gunicorn sẽ lắng nghe vào :5000 , vì vậy bạn sẽ mở cổng này bằng lệnh EXPOSE .

Cuối cùng, dòng CMD [ "gunicorn", "-w", "4", "--bind", "0.0.0.0:5000", "wsgi"] chạy lệnh để khởi động server Gunicorn với bốn nhân viên đang nghe cổng 5000 . Con số thường phải từ 2–4 công nhân cho mỗi lõi trong server , tài liệu của Gunicorn khuyến nghị (2 x $num_cores) + 1 là số nhân công nên bắt đầu.

Dockerfile đã hoàn thành của bạn sẽ giống như sau:

app / Dockerfile
FROM python:3.6.8-alpine3.9  LABEL MAINTAINER="FirstName LastName <example@domain.com>"  ENV GROUP_ID=1000 \     USER_ID=1000  WORKDIR /var/www/  ADD . /var/www/ RUN pip install -r requirements.txt RUN pip install gunicorn  RUN addgroup -g $GROUP_ID www RUN adduser -D -u $USER_ID -G www www -s /bin/sh  USER www  EXPOSE 5000  CMD [ "gunicorn", "-w", "4", "--bind", "0.0.0.0:5000", "wsgi"] 

Lưu file và thoát khỏi editor .

Tiếp theo, tạo một folder mới để chứa cấu hình Nginx của bạn:

  • mkdir nginx

Sau đó, tạo Dockerfile cho web server Nginx của bạn trong folder nginx :

  • nano nginx/Dockerfile

Thêm mã sau vào file để tạo Dockerfile sẽ tạo hình ảnh cho containers Nginx của bạn:

nginx / Dockerfile
FROM alpine:latest  LABEL MAINTAINER="FirstName LastName <example@domain.com>"  RUN apk --update add nginx && \     ln -sf /dev/stdout /var/log/nginx/access.log && \     ln -sf /dev/stderr /var/log/nginx/error.log && \     mkdir /etc/nginx/sites-enabled/ && \     mkdir -p /run/nginx && \     rm -rf /etc/nginx/conf.d/default.conf && \     rm -rf /var/cache/apk/*  COPY conf.d/app.conf /etc/nginx/conf.d/app.conf  EXPOSE 80 443 CMD ["nginx", "-g", "daemon off;"] 

Nginx Dockerfile sử dụng hình ảnh cơ sở alpine , là một bản phân phối Linux nhỏ với bề mặt tấn công tối thiểu được xây dựng để bảo mật.

Trong chỉ thị RUN bạn đang cài đặt nginx cũng như tạo các softlink để xuất bản lỗi và truy cập vào log lỗi chuẩn ( /dev/stderr ) và kết quả ( /dev/stdout ). Xuất bản lỗi thành lỗi chuẩn và kết quả là một phương pháp hay nhất vì containers là tạm thời, làm điều này, log được chuyển đến log docker và từ đó bạn có thể chuyển tiếp log của bạn tới một dịch vụ ghi log như ngăn xếp elastic để tồn tại lâu dài. Sau khi hoàn tất, các lệnh sẽ được chạy để loại bỏ default.conf/var/cache/apk/* để giảm kích thước của hình ảnh kết quả. Việc thực thi tất cả các lệnh này trong một lần RUN sẽ làm giảm số lượng lớp trong ảnh, điều này cũng làm giảm kích thước của ảnh kết quả.

Chỉ thị COPY sao chép cấu hình web server app.conf bên trong containers . Lệnh EXPOSE đảm bảo các containers lắng nghe trên các cổng :80:443 , vì ứng dụng của bạn sẽ chạy trên :80 với :443 là cổng an toàn.

Cuối cùng, chỉ thị CMD xác định lệnh khởi động server Nginx.

Lưu file và thoát khỏi editor .

Bây giờ Dockerfile đã sẵn sàng, bạn đã sẵn sàng cấu hình Reverse Proxy Nginx để định tuyến lưu lượng truy cập đến ứng dụng Flask.

Bước 3 - Cấu hình Nginx Reverse Proxy

Trong bước này, bạn sẽ cấu hình Nginx làm Reverse Proxy để chuyển tiếp các yêu cầu tới Gunicorn trên :5000 . Một server Reverse Proxy được sử dụng để hướng các yêu cầu của khách hàng đến server phụ thích hợp. Nó cung cấp thêm một lớp trừu tượng và kiểm soát đảm bảo stream lưu lượng mạng thông suốt giữa các client và server .

Bắt đầu bằng cách tạo folder nginx/conf.d :

  • mkdir nginx/conf.d

Để cấu hình Nginx, bạn cần tạo file app.conf với cấu hình sau trong folder nginx/conf.d/ . Tệp app.conf chứa cấu hình mà Reverse Proxy cần để chuyển tiếp các yêu cầu tới Gunicorn.

  • nano nginx/conf.d/app.conf

Đặt các nội dung sau vào file app.conf :

nginx / conf.d / app.conf
upstream app_server {     server flask:5000; }  server {     listen 80;     server_name _;     error_log  /var/log/nginx/error.log;     access_log /var/log/nginx/access.log;     client_max_body_size 64M;      location / {         try_files $uri @proxy_to_app;     }      location @proxy_to_app {         gzip_static on;          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;         proxy_set_header X-Forwarded-Proto $scheme;         proxy_set_header Host $http_host;         proxy_buffering off;         proxy_redirect off;         proxy_pass http://app_server;     } } 

Điều này trước tiên sẽ xác định server ngược dòng , thường được sử dụng để chỉ định web server hoặc ứng dụng để định tuyến hoặc cân bằng tải.

Server ngược dòng của bạn, app_server , xác định địa chỉ server bằng lệnh server , được xác định bằng bình chứa tên vùng flask:5000 .

Cấu hình cho web server Nginx được xác định trong khối server . Chỉ thị listen xác định số cổng mà server của bạn sẽ lắng nghe các yêu cầu đến. Các chỉ thị error_logaccess_log xác định các file để ghi log . Chỉ thị proxy_pass được sử dụng để đặt server ngược dòng để chuyển tiếp các yêu cầu tới http:// app_server .

Lưu và đóng file .

Với web server Nginx được cấu hình , bạn có thể chuyển sang tạo API việc cần làm của Flask.

Bước 4 - Tạo API việc cần làm của Flask

Đến đây bạn đã xây dựng xong môi trường của bạn , bạn đã sẵn sàng để xây dựng ứng dụng của bạn . Trong bước này, bạn sẽ viết một ứng dụng API việc cần làm sẽ lưu và hiển thị các ghi chú việc cần làm được gửi đến từ một yêu cầu POST.

Bắt đầu bằng cách tạo ra các requirements.txt file trong app folder :

  • nano app/requirements.txt

Tệp này được sử dụng để cài đặt các phụ thuộc cho ứng dụng của bạn. Việc thực hiện hướng dẫn này sẽ sử dụng Flask , Flask-PyMongorequests . Thêm sau vào requirements.txt file:

app / tests.txt
Flask==1.0.2 Flask-PyMongo==2.2.0 requests==2.20.1 

Lưu file và thoát khỏi editor sau khi nhập các yêu cầu.

Tiếp theo, tạo file app.py để chứa mã ứng dụng Flask trong folder app :

  • nano app/app.py

Trong file app.py mới của bạn, hãy nhập mã để nhập các phần phụ thuộc:

app / app.py
import os from flask import Flask, request, jsonify from flask_pymongo import PyMongo 

Gói os được sử dụng để nhập các biến môi trường. Từ thư viện flask bạn đã nhập các đối tượng Flask , requestjsonify để khởi tạo ứng dụng, xử lý các yêu cầu và gửi phản hồi JSON tương ứng. Từ flask_pymongo bạn đã nhập đối tượng PyMongo để tương tác với MongoDB.

Tiếp theo, thêm mã cần thiết để kết nối với MongoDB:

app / app.py
. . . application = Flask(__name__)  application.config["MONGO_URI"] = 'mongodb://' + os.environ['MONGODB_USERNAME'] + ':' + os.environ['MONGODB_PASSWORD'] + '@' + os.environ['MONGODB_HOSTNAME'] + ':27017/' + os.environ['MONGODB_DATABASE']  mongo = PyMongo(application) db = mongo.db 

Flask(__name__) tải đối tượng ứng dụng vào biến application . Tiếp theo, mã xây dựng chuỗi kết nối MongoDB từ các biến môi trường bằng cách sử dụng os.environ . Truyền đối tượng application vào phương thức PyMongo() sẽ cung cấp cho bạn đối tượng mongo , từ đó cung cấp cho bạn đối tượng db từ mongo.db .

Đến đây bạn sẽ thêm mã để tạo một thông báo index :

app / app.py
. . . @application.route('/') def index():     return jsonify(         status=True,         message='Welcome to the Dockerized Flask MongoDB app!'     ) 

@application.route('/') xác định tuyến / GET của API của bạn. Ở đây, hàm index() của bạn trả về một chuỗi JSON bằng cách sử dụng phương thức jsonify .

Tiếp theo, thêm tuyến đường /todo việc cần làm để liệt kê tất cả việc cần làm:

app / app.py
. . . @application.route('/todo') def todo():     _todos = db.todo.find()      item = {}     data = []     for todo in _todos:         item = {             'id': str(todo['_id']),             'todo': todo['todo']         }         data.append(item)      return jsonify(         status=True,         data=data     ) 

@application.route('/todo') xác định tuyến /todo GET của API của bạn, tuyến này trả về việc cần làm trong database . Phương thức db.todo.find() trả về tất cả các việc cần làm trong database . Tiếp theo, bạn lặp qua _todos để xây dựng một item mà chỉ bao gồm các idtodo từ các đối tượng phụ thêm chúng vào một data mảng và cuối cùng trở về chúng như JSON.

Tiếp theo, thêm mã để tạo việc cần làm:

app / app.py
. . . @application.route('/todo', methods=['POST']) def createTodo():     data = request.get_json(force=True)     item = {         'todo': data['todo']     }     db.todo.insert_one(item)      return jsonify(         status=True,         message='To-do saved successfully!'     ), 201 

@application.route('/todo') xác định tuyến /todo POST của API của bạn, tạo một ghi chú việc cần làm trong database . request.get_json(force=True) lấy JSON mà bạn đăng lên tuyến đường và item được sử dụng để tạo JSON sẽ được lưu trong việc cần làm. db.todo.insert_one(item) được sử dụng để chèn một mục vào database . Sau khi việc cần làm được lưu trong database , bạn trả về một phản hồi JSON với mã trạng thái là 201 CREATED .

Đến đây bạn thêm mã để chạy ứng dụng:

app / app.py
. . . if __name__ == "__main__":     ENVIRONMENT_DEBUG = os.environ.get("APP_DEBUG", True)     ENVIRONMENT_PORT = os.environ.get("APP_PORT", 5000)     application.run(host='0.0.0.0', port=ENVIRONMENT_PORT, debug=ENVIRONMENT_DEBUG) 

Điều kiện __name__ == "__main__" được sử dụng để kiểm tra xem biến toàn cục, __name__ , trong module có phải là điểm vào chương trình của bạn, là "__main__" , sau đó chạy ứng dụng. Nếu __name__ bằng "__main__" thì mã bên trong if khối sẽ thực hiện các ứng dụng sử dụng lệnh này application.run(host='0.0.0.0', port=ENVIRONMENT_PORT, debug=ENVIRONMENT_DEBUG) .

Tiếp theo, ta lấy các giá trị cho ENVIRONMENT_DEBUGENVIRONMENT_PORT từ các biến môi trường bằng cách sử dụng os.environ.get() , sử dụng khóa làm tham số đầu tiên và giá trị mặc định làm tham số thứ hai. application.run() đặt các giá trị host , portdebug cho ứng dụng.

app.py đã hoàn thành sẽ trông giống như sau:

app / app.py
import os from flask import Flask, request, jsonify from flask_pymongo import PyMongo  application = Flask(__name__)  application.config["MONGO_URI"] = 'mongodb://' + os.environ['MONGODB_USERNAME'] + ':' + os.environ['MONGODB_PASSWORD'] + '@' + os.environ['MONGODB_HOSTNAME'] + ':27017/' + os.environ['MONGODB_DATABASE']  mongo = PyMongo(application) db = mongo.db  @application.route('/') def index():     return jsonify(         status=True,         message='Welcome to the Dockerized Flask MongoDB app!'     )  @application.route('/todo') def todo():     _todos = db.todo.find()      item = {}     data = []     for todo in _todos:         item = {             'id': str(todo['_id']),             'todo': todo['todo']         }         data.append(item)      return jsonify(         status=True,         data=data     )  @application.route('/todo', methods=['POST']) def createTodo():     data = request.get_json(force=True)     item = {         'todo': data['todo']     }     db.todo.insert_one(item)      return jsonify(         status=True,         message='To-do saved successfully!'     ), 201  if __name__ == "__main__":     ENVIRONMENT_DEBUG = os.environ.get("APP_DEBUG", True)     ENVIRONMENT_PORT = os.environ.get("APP_PORT", 5000)     application.run(host='0.0.0.0', port=ENVIRONMENT_PORT, debug=ENVIRONMENT_DEBUG) 

Lưu file và thoát khỏi editor .

Tiếp theo, tạo file wsgi.py trong folder app .

  • nano app/wsgi.py

Tệp wsgi.py tạo một đối tượng ứng dụng (hoặc có thể gọi) để server có thể sử dụng nó. Mỗi khi có yêu cầu, server sử dụng đối tượng ứng dụng này để chạy trình xử lý yêu cầu của ứng dụng khi phân tích cú pháp URL.

Đặt các nội dung sau vào file wsgi.py , lưu file và thoát khỏi editor :

app / wsgi.py
from app import application  if __name__ == "__main__":   application.run() 

wsgi.py này nhập đối tượng ứng dụng từ file app.py và tạo một đối tượng ứng dụng cho server Gunicorn.

Ứng dụng việc cần làm hiện đã có sẵn, vì vậy bạn đã sẵn sàng để bắt đầu chạy ứng dụng trong containers .

Bước 5 - Xây dựng và chạy các container

Đến đây bạn đã xác định tất cả các dịch vụ trong file docker-compose.yml và cấu hình của chúng, bạn có thể bắt đầu các containers .

Vì các dịch vụ được xác định trong một file duy nhất, bạn cần phải đưa ra một lệnh duy nhất để khởi động các containers , tạo các ổ đĩa và cài đặt mạng. Lệnh này cũng xây dựng hình ảnh cho ứng dụng Flask của bạn và web server Nginx. Chạy lệnh sau để tạo containers :

  • docker-compose up -d

Khi chạy lệnh lần đầu tiên, nó sẽ download tất cả các Docker image cần thiết, có thể mất một chút thời gian. Sau khi hình ảnh được download và lưu trữ trong máy local của bạn, docker-compose sẽ tạo containers của bạn. Cờ -d daemonized quy trình, cho phép nó chạy như một quy trình .

Sử dụng lệnh sau để liệt kê các containers đang chạy sau khi quá trình xây dựng hoàn tất:

  • docker ps

Bạn sẽ thấy kết quả tương tự như sau:

Output
CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS              PORTS                                      NAMES f20e9a7fd2b9        digitalocean.com/webserver:latest   "nginx -g 'daemon of…"   2 weeks ago         Up 2 weeks          0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   webserver 3d53ea054517        digitalocean.com/flask-python:3.6   "gunicorn -w 4 --bin…"   2 weeks ago         Up 2 weeks          5000/tcp                                   flask 96f5a91fc0db        mongo:4.0.8                     "docker-entrypoint.s…"   2 weeks ago         Up 2 weeks          27017/tcp                                  mongodb 

CONTAINER ID là một số nhận dạng duy nhất được sử dụng để truy cập các containers . IMAGE xác định tên hình ảnh cho containers đã cho. Trường NAMES là tên dịch vụ mà containers được tạo, tương tự như CONTAINER ID chúng được dùng để truy cập containers . Cuối cùng, STATUS cung cấp thông tin về trạng thái của containers cho dù nó đang chạy, khởi động lại hay đã dừng.

Bạn đã sử dụng lệnh docker-compose để tạo containers từ các file cấu hình của bạn . Trong bước tiếp theo, bạn sẽ tạo một user MongoDB cho ứng dụng của bạn .

Bước 6 - Tạo user cho database MongoDB của bạn

Theo mặc định, MongoDB cho phép user đăng nhập mà không cần thông tin đăng nhập và cấp các quyền không giới hạn. Trong bước này, bạn sẽ bảo mật database MongoDB của bạn bằng cách tạo một user chuyên dụng để truy cập nó.

Để làm điều này, bạn cần tên user và password root mà bạn đã đặt trong docker-compose.yml biến môi trường tập MONGO_INITDB_ROOT_USERNAMEMONGO_INITDB_ROOT_PASSWORD cho mongodb dịch vụ. Nói chung, tốt hơn hết là bạn nên tránh sử dụng account quản trị root khi tương tác với database . Thay vào đó, bạn sẽ tạo một user database chuyên dụng cho ứng dụng Flask của bạn , cũng như một database mới mà ứng dụng Flask sẽ được phép truy cập.

Để tạo user mới, trước tiên hãy bắt đầu một shell tương tác trên containers mongodb :

  • docker exec -it mongodb bash

Bạn sử dụng lệnh thực thi docker exec để chạy một lệnh bên trong một containers đang chạy cùng với cờ -it để chạy một shell tương tác bên trong containers .

Khi bên trong containers , hãy đăng nhập vào account quản trị gốc MongoDB:

  • mongo -u mongodbuser -p

Bạn sẽ được yêu cầu nhập password mà bạn đã nhập làm giá trị cho các MONGO_INITDB_ROOT_PASSWORD biến trong docker-compose.yml file . Có thể thay đổi password bằng cách đặt giá trị mới cho MONGO_INITDB_ROOT_PASSWORD trong dịch vụ mongodb , trong trường hợp này, bạn sẽ phải chạy docker-compose up -d lệnh MONGO_INITDB_ROOT_PASSWORD docker-compose up -d .

Chạy show dbs; lệnh liệt kê tất cả database :

  • show dbs;

Bạn sẽ thấy kết quả sau:

Output
admin    0.000GB config   0.000GB local    0.000GB 5 rows in set (0.00 sec) 

Database admin là một database đặc biệt cấp quyền quản trị cho user . Nếu user có quyền đọc vào database admin , họ sẽ có quyền đọc và ghi đối với tất cả các database khác. Vì kết quả liệt kê database admin , user có quyền truy cập vào database này và do đó có thể đọc và ghi vào tất cả các database khác.

Lưu ghi chú việc cần làm đầu tiên sẽ tự động tạo database MongoDB . MongoDB cho phép bạn chuyển sang database không tồn tại bằng lệnh use database . Nó tạo database khi tài liệu được lưu vào một bộ sưu tập. Do đó, database không được tạo ở đây; điều đó sẽ xảy ra khi bạn lưu ghi chú việc cần làm đầu tiên của bạn trong database từ API. Thực hiện lệnh use để chuyển sang database flaskdb :

  • use flaskdb

Tiếp theo, tạo một user mới sẽ được phép truy cập vào database này:

  • db.createUser({user: 'flaskuser', pwd: 'your password', roles: [{role: 'readWrite', db: 'flaskdb'}]})
  • exit

Lệnh này tạo một user có tên là flaskuser có quyền truy cập readWrite vào database flaskdb . Đảm bảo sử dụng password an toàn trong trường pwd . Người userpwd ở đây là các giá trị bạn đã xác định trong file docker-compose.yml trong phần biến môi trường cho dịch vụ flask .

Đăng nhập vào database đã xác thực bằng lệnh sau:

  • mongo -u flaskuser -p your password --authenticationDatabase flaskdb

Đến đây bạn đã thêm user , hãy đăng xuất khỏi database .

  • exit

Và cuối cùng, thoát khỏi containers :

  • exit

Đến đây bạn đã cấu hình database chuyên dụng và account user cho ứng dụng Flask của bạn . Các thành phần database đã sẵn sàng, vì vậy bây giờ bạn có thể chuyển sang chạy ứng dụng việc cần làm của Flask.

Bước 7 - Chạy ứng dụng Flask To-do

Bây giờ các dịch vụ của bạn đã được cấu hình và đang chạy, bạn có thể kiểm tra ứng dụng của bạn bằng cách chuyển đến http:// your_server_ip trong trình duyệt. Ngoài ra, bạn có thể chạy curl để xem phản hồi JSON từ Flask:

  • curl -i http://your_server_ip

Bạn sẽ nhận được phản hồi sau:

Output
{"message":"Welcome to the Dockerized Flask MongoDB app!","status":true} 

Cấu hình cho ứng dụng Flask được chuyển đến ứng dụng từ file docker-compose.yml . Cấu hình liên quan đến kết nối database được đặt bằng cách sử dụng các biến MONGODB_* được xác định trong phần environment của dịch vụ flask .

Để kiểm tra mọi thứ, hãy tạo ghi chú việc cần làm bằng API Flask. Bạn có thể thực hiện việc này với yêu cầu POST curl tới tuyến đường /todo :

  • curl -i -H "Content-Type: application/json" -X POST -d '{"todo": "Dockerize Flask application with MongoDB backend"}' http://your_server_ip/todo

Yêu cầu này dẫn đến phản hồi có mã trạng thái là 201 CREATED khi mục việc cần làm được lưu vào MongoDB:

Output
{"message":"To-do saved successfully!","status":true} 

Bạn có thể liệt kê tất cả các ghi chú việc cần làm từ MongoDB với yêu cầu GET cho tuyến đường /todo :

  • curl -i http://your_server_ip/todo
Output
{"data":[{"id":"5c9fa25591cb7b000a180b60","todo":"Dockerize Flask application with MongoDB backend"}],"status":true} 

Với điều này, bạn đã Tài liệu hóa một API Flask chạy chương trình backend MongoDB với Nginx dưới dạng Reverse Proxy được triển khai cho các server của bạn. Đối với môi trường production , bạn có thể sử dụng sudo systemctl enable docker đảm bảo dịch vụ Docker của bạn tự động bắt đầu trong thời gian chạy.

Kết luận

Trong hướng dẫn này, bạn đã triển khai ứng dụng Flask với Docker, MongoDB, Nginx và Gunicorn. Đến đây bạn có một ứng dụng API không trạng thái hiện đại đang hoạt động có thể được mở rộng. Mặc dù bạn có thể đạt được kết quả này bằng cách sử dụng một lệnh như docker container run , docker-compose.yml đơn giản hóa công việc của bạn vì ngăn xếp này có thể được đưa vào kiểm soát version và cập nhật khi cần thiết.

Từ đây, bạn cũng có thể xem thêm các hướng dẫn về Python Framework của ta .


Tags:

Các tin liên quan

Cách cài đặt và sử dụng Docker trên Debian 10
2019-07-08
Cách sử dụng server Docker từ xa để tăng tốc quy trình làm việc của bạn
2019-06-25
Cách cài đặt WordPress với Docker Compose
2019-05-24
Cách di chuyển Docker compose workflow sang Kubernetes
2019-04-03
Cách tối ưu hóa image Docker cho sản xuất
2019-03-25
Giữ lại một ứng dụng Node.js để phát triển với Docker Compose
2019-03-05
Cách cài đặt và sử dụng Docker Compose trên CentOS 7
2019-01-23
Cách sử dụng Traefik làm reverse-proxy cho container Docker trên Debian 9
2019-01-08
Cách thiết lập registry Docker riêng trên Ubuntu 18.04
2019-01-07
Cách thiết lập triển khai nhiều node với Rancher 2.1, Kubernetes và Docker Machine trên Ubuntu 18.04
2019-01-03