paint-brush
3 vấn đề lớn về Python và cách giải quyết chúngtừ tác giả@dave01
3,578 lượt đọc
3,578 lượt đọc

3 vấn đề lớn về Python và cách giải quyết chúng

từ tác giả David Finson18m2023/01/21
Read on Terminal Reader

dài quá đọc không nổi

Việc quản lý các môi trường phát triển phức tạp thường đặt ra một số thách thức khi các dự án được mở rộng quy mô. Giải pháp là sử dụng container hóa, đây là một phương pháp đóng gói ứng dụng và các phần phụ thuộc của nó thành một đơn vị độc lập có thể dễ dàng triển khai và chạy trên bất kỳ nền tảng nào. Tôi sẽ trình bày cách thiết lập và sử dụng môi trường phát triển được đóng gói bằng Docker và Docker Compose.
featured image - 3 vấn đề lớn về Python và cách giải quyết chúng
David Finson HackerNoon profile picture

Mặc dù làm việc với Python thường xuyên là một trải nghiệm tuyệt vời đối với tôi, nhưng việc quản lý các môi trường phát triển phức tạp thường đặt ra một số thách thức khi các dự án mở rộng quy mô.

Để kể tên một vài ví dụ, đây là 3 vấn đề chính với Python mà tôi đã gặp phải:

1. Các ứng dụng phụ thuộc vào các biến môi trường có thể cần đặt các biến này trước khi ứng dụng có thể chạy.

2. Các ứng dụng sử dụng chứng chỉ xác thực để liên lạc giữa các dịch vụ khác nhau, có thể yêu cầu tạo cục bộ các chứng chỉ này trước khi chạy ứng dụng.

3. Các xung đột về phiên bản phụ thuộc có thể xảy ra giữa các vi dịch vụ khác nhau trong cùng một dự án.

Mọi thứ có thể trở nên đặc biệt khó khăn khi làm việc với nhiều dịch vụ siêu nhỏ phụ thuộc lẫn nhau và thành thật mà nói, với tư cách là nhà phát triển, tôi thực sự không muốn quản lý tất cả chi phí hoạt động này chỉ để bắt đầu và chạy. Điều này đặc biệt đúng nếu tôi mới bắt đầu tham gia một dự án mới.

Một giải pháp phổ biến mà tôi thấy được sử dụng khi phát triển ứng dụng Python là sử dụng môi trường ảo Python , là môi trường biệt lập có cài đặt Python và các gói bắt buộc. Tuy nhiên, việc quản lý nhiều môi trường ảo và các cấu hình liên quan đến môi trường khác vẫn có thể tốn thời gian và cồng kềnh, vì môi trường ảo chỉ cung cấp sự cô lập ở cấp trình thông dịch Python. Điều này có nghĩa là thiết lập khác liên quan đến môi trường, chẳng hạn như biến môi trường và phân bổ cổng, vẫn được chia sẻ trên toàn cầu cho tất cả các thành phần dự án.

Giải pháp mà tôi sẽ trình bày trong bài viết này là sử dụng container hóa, đây là một phương pháp đóng gói một ứng dụng và các phần phụ thuộc của nó thành một đơn vị độc lập có thể dễ dàng triển khai và chạy trên bất kỳ nền tảng nào. Docker là một nền tảng phổ biến để phát triển, triển khai và chạy các ứng dụng được chứa trong bộ chứa và Docker Compose là một công cụ giúp dễ dàng xác định và chạy các ứng dụng Docker nhiều bộ chứa bằng một tệp YAML duy nhất (thường được đặt tên là

 docker-compose.yml
). Mặc dù có các giải pháp thay thế như minikube , nhưng để đơn giản, tôi sẽ sử dụng Docker và Docker Compose trong ví dụ này.

Tôi sẽ trình bày cách thiết lập và sử dụng môi trường phát triển được đóng gói bằng Docker và Docker Compose. Tôi cũng sẽ thảo luận về một số thách thức khi sử dụng môi trường phát triển được đóng gói và cách khắc phục chúng bằng cách định cấu hình Docker và Docker soạn thảo để phù hợp với các yêu cầu chính sau đây cho môi trường phát triển hiệu quả:

1. Chạy - Chạy các kịch bản từ đầu đến cuối mô phỏng quá trình thực thi trên môi trường sản xuất mục tiêu.

2. Triển khai - Thực hiện thay đổi mã và triển khai lại một cách nhanh chóng, như với ngăn xếp thời gian chạy ứng dụng không được chứa.

3. Gỡ lỗi - Đặt điểm ngắt và sử dụng trình gỡ lỗi để duyệt qua mã, như với ngăn xếp thời gian chạy ứng dụng không được chứa, để xác định và sửa lỗi.

Thiết lập dự án

Để minh họa điều này bằng ví dụ, tôi sẽ định nghĩa một ứng dụng Python đơn giản sử dụng khung web Python nhẹ, Flask , để tạo API RESTful để truy vấn thông tin về tác giả và bài đăng của họ. API có một điểm cuối duy nhất,

 /authors/{author_id}
, có thể được sử dụng để truy xuất thông tin về một tác giả cụ thể bằng cách chỉ định ID của họ làm tham số đường dẫn. Sau đó, ứng dụng sử dụng mô-đun yêu cầu để thực hiện các yêu cầu HTTP tới một dịch vụ bài đăng riêng biệt, dịch vụ này dự kiến sẽ cung cấp danh sách các bài đăng của tác giả đó. Để giữ cho mã ngắn gọn, tất cả dữ liệu sẽ được tạo ngẫu nhiên một cách nhanh chóng bằng thư viện Faker .

Để bắt đầu, tôi sẽ khởi tạo và sau đó mở một thư mục trống cho dự án. Tiếp theo, tôi sẽ tạo hai thư mục con: Thư mục đầu tiên sẽ được gọi là

 authors_service
, va thu hai
 posts_service
. Trong mỗi thư mục này, tôi sẽ tạo 3 tệp:

1.

 app.py
: Điểm vào chính cho ứng dụng Flask, xác định ứng dụng, thiết lập các tuyến và chỉ định các chức năng sẽ được gọi khi có yêu cầu đối với các tuyến đó.

2.

 requirements.txt
: Một tệp văn bản thuần túy chỉ định các gói Python cần thiết để chạy ứng dụng.

3.

 Dockerfile
: Tệp văn bản chứa hướng dẫn xây dựng hình ảnh Docker, như đã đề cập ở trên, là một gói nhẹ, độc lập và có thể thực thi, bao gồm mọi thứ cần thiết để chạy ứng dụng, bao gồm mã, thời gian chạy, thư viện, biến môi trường, và khá nhiều thứ khác.

Trong mỗi

 app.py
tệp, tôi sẽ triển khai một vi dịch vụ Flask với logic mong muốn.

cho

 authors_service
, các
 app.py
tập tin trông như sau:

 import os import flask import requests from faker import Faker app = flask.Flask(__name__) @app.route( "/authors/<string:author_id>" , methods=[ "GET" ] )
def get_author_by_id ( author_id: str ):
 author = {        "id" : author_id,        "name" : Faker().name(),        "email" : Faker().email(),        "posts" : _get_authors_posts(author_id) }    return flask.jsonify(author) def _get_authors_posts ( author_id: str ):
 response = requests.get(        f' {os.environ[ "POSTS_SERVICE_URL" ]} / {author_id} '
 )    return response.json() if __name__ == "__main__" : app.run( host=os.environ[ 'SERVICE_HOST' ], port= int (os.environ[ 'SERVICE_PORT' ]) )


Mã này thiết lập ứng dụng Flask và xác định tuyến đường để xử lý các yêu cầu GET đến điểm cuối

 /authors/{author_id}
. Khi điểm cuối này được truy cập, nó sẽ tạo dữ liệu giả cho một tác giả có ID được cung cấp và truy xuất danh sách các bài đăng cho tác giả đó từ dịch vụ bài đăng riêng biệt. Sau đó, nó chạy ứng dụng Flask, lắng nghe tên máy chủ và cổng được chỉ định trong các biến môi trường tương ứng.

Lưu ý rằng logic trên phụ thuộc vào
 flask
,
 requests
 Faker
gói. Để giải thích cho điều này, tôi sẽ thêm chúng vào dịch vụ của tác giả
 requirements.txt
tập tin, như sau:

 flask == 2 . 2 . 2
requests == 2 . 28 . 1
Faker == 15 . 3 . 4

Lưu ý rằng không có yêu cầu cụ thể về phiên bản gói cho bất kỳ thành phần phụ thuộc nào được tham chiếu trong hướng dẫn này. Các phiên bản được sử dụng là phiên bản mới nhất có sẵn tại thời điểm viết.

Cho

 posts_service
,
 app.py
trông như sau:

 import os import uuid from random import randint import flask from faker import Faker app = flask.Flask(__name__) @app.route( '/posts/<string:author_id>' , methods=[ 'GET' ] )
def get_posts_by_author_id ( author_id: str ):
 posts = [ {            "id:" : str (uuid.uuid4()),            "author_id" : author_id,            "title" : Faker().sentence(),            "body" : Faker().paragraph() }        for _ in range (randint( 1 , 5 )) ]    return flask.jsonify(posts) if __name__ == '__main__' : app.run( host=os.environ[ 'SERVICE_HOST' ], port= int (os.environ[ 'SERVICE_PORT' ]) )


Trong mã này, khi một khách hàng (tức là

 authors_service
) gửi yêu cầu GET đến tuyến đường
 /posts/{author_id}
, chức năng
 get_posts_by_author_id
được gọi với chỉ định
 author_id
như một tham số. Hàm tạo dữ liệu giả cho từ 1 đến 5 bài đăng do tác giả viết bằng thư viện Faker và trả về danh sách các bài đăng dưới dạng phản hồi JSON cho ứng dụng khách.

Tôi cũng sẽ cần thêm các gói jar và Faker vào dịch vụ đăng bài

 requirements.txt
tập tin, như sau:

 flask == 2 . 2 . 2
Faker == 15 . 3 . 4

Trước khi chứa các dịch vụ này, chúng ta hãy xem xét một ví dụ về lý do tại sao tôi muốn đóng gói và chạy chúng tách biệt với nhau ngay từ đầu.

Cả hai dịch vụ đều sử dụng các biến môi trường

 SERVICE_HOST
 SERVICE_PORT
để xác định ổ cắm mà máy chủ Flask sẽ được khởi chạy. Trong khi
 SERVICE_HOST
không phải là vấn đề (nhiều dịch vụ có thể nghe trên cùng một máy chủ),
 SERVICE_PORT
có thể gây ra vấn đề. Nếu tôi cài đặt tất cả các phụ thuộc trong môi trường Python cục bộ và chạy cả hai dịch vụ, thì dịch vụ đầu tiên bắt đầu sẽ sử dụng cổng đã chỉ định, khiến dịch vụ thứ hai gặp sự cố vì không thể sử dụng cùng một cổng. Một giải pháp đơn giản là sử dụng các biến môi trường riêng biệt (ví dụ:
 AUTHORS_SERVICE_PORT
 POSTS_SERVICE_PORT
) thay thế. Tuy nhiên, việc sửa đổi mã nguồn để thích ứng với các ràng buộc về môi trường có thể trở nên phức tạp khi mở rộng quy mô.

Quá trình container hóa giúp tránh các sự cố như thế này bằng cách thiết lập môi trường phù hợp với ứng dụng, thay vì ngược lại . Trong trường hợp này, tôi có thể đặt

 SERVICE_PORT
biến môi trường thành một giá trị khác cho từng dịch vụ và mỗi dịch vụ sẽ có thể sử dụng cổng riêng của mình mà không bị các dịch vụ khác can thiệp.

Để chứa các dịch vụ, tôi sẽ tạo một tệp mới có tên
 Dockerfile
trong mỗi thư mục của dịch vụ. Nội dung của tệp này (cho cả hai dịch vụ) như sau:

 FROM python: 3.8
RUN mkdir /app WORKDIR /app COPY requi rements.txt /app/
RUN pip install -r requi rements.txt
COPY . /app/ CMD [ "python" , "app.py" ]

Cái này

 Dockerfile
xây dựng từ hình ảnh gốc Python 3.8 và thiết lập thư mục cho ứng dụng trong vùng chứa. Sau đó, nó sao chép
 requirements.txt
tệp từ máy chủ sang vùng chứa và cài đặt các phụ thuộc được liệt kê trong tệp đó. Cuối cùng, nó sao chép phần còn lại của mã ứng dụng từ máy chủ sang bộ chứa và chạy tập lệnh ứng dụng chính khi bộ chứa được khởi động.

Tiếp theo, tôi sẽ tạo một tệp có tên

 docker-compose.yml
trong thư mục dự án gốc. Như đã đề cập ngắn gọn ở trên, tệp này được sử dụng để xác định và chạy các ứng dụng Docker đa vùng chứa. bên trong
 docker-compose.yml
tệp, tôi có thể xác định các dịch vụ tạo nên ứng dụng, chỉ định các phụ thuộc giữa chúng và định cấu hình cách chúng sẽ được xây dựng và chạy. Trong trường hợp này, nó trông như sau:

 ---
# Specify the version of the Docker Compose file format
version: '3.9'
services:
  # Define the authors_service service
  authors_service:
    # This service relies on, and is therefor dependent on, the below `posts_service` service
    depends_on:
      - posts_service
    # Specify the path to the Dockerfile for this service
    build:
      context: ./authors_service
      dockerfile: Dockerfile
    # Define environment variables for this service
    environment:
      - SERVICE_HOST=0.0.0.0
      - PYTHONPATH=/app
      - SERVICE_PORT=5000
      - POSTS_SERVICE_URL=http://posts_service:6000/posts
    # Map port 5000 on the host machine to port 5000 on the container
    ports:
      - "5000:5000"
    # Mount the authors_service source code directory on the host to the working directory on the container
    volumes:
      - ./authors_service:/app
  # Define the posts_service service
  posts_service:
    # Specify the path to the Dockerfile for this service
    build:
      context: ./posts_service
      dockerfile: Dockerfile
    # Define environment variables for this service
    environment:
      - PYTHONPATH=/app
      - SERVICE_HOST=0.0.0.0
      - SERVICE_PORT=6000
    # Mount the posts_service source code directory on the host to the working directory on the container
    volumes:
      - ./posts_service:/app


Chạy ứng dụng

Các thùng chứa có thể được bắt đầu với

 docker-compose up
chỉ huy. Lần đầu tiên chạy, hình ảnh docker sẽ tự động được tạo.

Điều này đáp ứng yêu cầu cốt lõi đầu tiên ở trên của "Run".

triển khai lại

Lưu ý rằng trong

 docker-compose.yml
tệp, ổ đĩa được gắn kết được sử dụng để chia sẻ các thư mục mã nguồn cho
 authors_service
 posts_service
dịch vụ giữa máy chủ và các thùng chứa. Điều này cho phép mã được chỉnh sửa trên máy chủ với các thay đổi được phản ánh tự động trong các vùng chứa (và ngược lại).

Ví dụ: dòng sau gắn kết

 ./authors_service
thư mục trên máy chủ đến
 /app
thư mục trong
 authors_service
thùng đựng hàng:

 volumes: - . /authors_service:/ app

Các thay đổi được thực hiện trên máy chủ sẽ có sẵn ngay lập tức trên bộ chứa và các thay đổi được thực hiện trong bộ chứa sẽ ngay lập tức được lưu vào thư mục mã nguồn của máy chủ. Điều này cho phép nhanh chóng triển khai lại các thay đổi bằng cách khởi động lại vùng chứa có liên quan mà không cần xây dựng lại hình ảnh, đáp ứng hiệu quả yêu cầu cốt lõi thứ hai là "Triển khai".

gỡ lỗi

Đây là nơi nó được tham gia nhiều hơn một chút. Trình gỡ lỗi trong Python sử dụng các công cụ gỡ lỗi do trình thông dịch cung cấp để tạm dừng việc thực thi chương trình và kiểm tra trạng thái của chương trình tại một số điểm nhất định. Điều này bao gồm thiết lập chức năng theo dõi với

 sys.settrace()
tại mỗi dòng mã và kiểm tra các điểm ngắt, cũng như sử dụng các tính năng như ngăn xếp cuộc gọi và kiểm tra biến. Gỡ lỗi trình thông dịch Python chạy bên trong vùng chứa có khả năng tăng thêm độ phức tạp so với gỡ lỗi trình thông dịch Python chạy trên máy chủ. Điều này là do môi trường vùng chứa bị cô lập khỏi máy chủ.

Để khắc phục điều này, có thể thực hiện một trong hai cách chung sau: Có thể gỡ lỗi mã từ bên trong chính bộ chứa hoặc mã có thể được gỡ lỗi bằng cách sử dụng máy chủ gỡ lỗi từ xa.

Đầu tiên, tôi sẽ sử dụng VSCode làm trình soạn thảo lựa chọn để trình bày cách thực hiện điều này. Sau đó, tôi sẽ giải thích cách hoạt động tương tự với JetBrains PyCharm .

Gỡ lỗi mã từ bên trong vùng chứa

Để phát triển và gỡ lỗi mã từ bên trong bộ chứa docker đang chạy bằng VSCode, tôi sẽ:

1. Đảm bảo đã cài đặt và bật tiện ích mở rộng Docker cho VSCode.

2. Đảm bảo vùng chứa mà tôi muốn đính kèm đang hoạt động.

3. Mở chế độ xem thám hiểm của tiện ích mở rộng Docker bằng cách nhấp vào biểu tượng Docker ở thanh bên trái.

4. Trong chế độ xem trình khám phá, hãy mở rộng phần "Vùng chứa đang chạy" và chọn vùng chứa mà tôi muốn đính kèm.

5. Nhấp chuột phải vào vùng chứa và chọn tùy chọn "Đính kèm Mã Visual Studio" từ menu ngữ cảnh.

Điều này sẽ đính kèm Visual Studio Code vào vùng chứa đã chọn và mở một cửa sổ VSCode mới trong vùng chứa. Trong cửa sổ mới này, tôi có thể viết, chạy và gỡ lỗi mã như bình thường trên môi trường cục bộ.

Để tránh phải cài đặt các tiện ích mở rộng VSCode, chẳng hạn như Python mỗi khi bộ chứa khởi động lại, tôi có thể gắn một ổ đĩa bên trong bộ chứa lưu trữ các tiện ích mở rộng VSCode. Bằng cách này, khi vùng chứa được khởi động lại, các tiện ích mở rộng sẽ vẫn khả dụng vì chúng được lưu trữ trên máy chủ. Để làm điều này bằng cách sử dụng docker soạn thảo trong dự án demo này,

 docker-compose.yml
tập tin có thể được sửa đổi như sau:

 ---
# Specify the version of the Docker Compose file format
version: '3.9'
services:
  # Define the authors_service service
  authors_service:
    ...
    # Mount the authors_service source code directory on the host to the working directory on the container
    volumes:
      - ./authors_service:/app
      # Mount the vscode extension directory on the host to the vscode extension directory on the container
      - /path/to/host/extensions:/root/.vscode/extensions
  # Define the posts_service service
  posts_service:
    ...

Lưu ý rằng các tiện ích mở rộng VSCode thường có thể được tìm thấy tại

 ~/.vscode/extensions
trên Linux và macOS, hoặc
 %USERPROFILE%\.vscode\extensions
trên Windows.

Sử dụng máy chủ gỡ lỗi Python từ xa

Phương pháp gỡ lỗi ở trên hoạt động tốt đối với các tập lệnh độc lập hoặc để viết, chạy và kiểm tra gỡ lỗi. Tuy nhiên, việc gỡ lỗi một luồng logic liên quan đến nhiều dịch vụ đang chạy trong các vùng chứa khác nhau sẽ phức tạp hơn.

Khi một vùng chứa được khởi động, dịch vụ chứa trong đó thường được khởi chạy ngay lập tức. Trong trường hợp này, máy chủ Flask trên cả hai dịch vụ đã chạy vào thời điểm VSCode được đính kèm, do đó, việc nhấp vào "Chạy và gỡ lỗi" và khởi chạy một phiên bản khác của máy chủ Flask là không thực tế vì nó sẽ dẫn đến nhiều phiên bản của cùng một dịch vụ đang chạy trên cùng một vùng chứa và cạnh tranh với nhau, đây thường không phải là quy trình gỡ lỗi đáng tin cậy.

Điều này đưa tôi đến tùy chọn số hai; sử dụng máy chủ gỡ lỗi Python từ xa. Máy chủ gỡ lỗi Python từ xa là trình thông dịch Python đang chạy trên máy chủ từ xa và được định cấu hình để chấp nhận kết nối từ trình gỡ lỗi. Điều này cho phép sử dụng trình gỡ lỗi đang chạy cục bộ để kiểm tra và kiểm soát quy trình Python đang chạy trên môi trường từ xa.

Điều quan trọng cần lưu ý là thuật ngữ "từ xa" không nhất thiết đề cập đến một máy từ xa vật lý hoặc thậm chí là một môi trường cục bộ nhưng bị cô lập, chẳng hạn như bộ chứa Docker chạy trên máy chủ. Máy chủ gỡ lỗi từ xa Python cũng có thể hữu ích để gỡ lỗi quy trình Python đang chạy trong cùng môi trường với trình gỡ lỗi. Trong ngữ cảnh này, tôi sẽ sử dụng một máy chủ gỡ lỗi từ xa đang chạy trong cùng vùng chứa với quá trình tôi đang gỡ lỗi. Sự khác biệt chính giữa phương pháp này và tùy chọn đầu tiên để gỡ lỗi mà chúng tôi đề cập là tôi sẽ đính kèm vào một quy trình có sẵn thay vì tạo một quy trình mới mỗi khi tôi muốn chạy và gỡ lỗi mã.

Để bắt đầu, bước đầu tiên là thêm gói debugpy vào

 requirements.txt
tập tin cho cả hai dịch vụ. debugpy là trình gỡ lỗi Python mã nguồn mở cấp cao có thể được sử dụng để gỡ lỗi các chương trình Python cục bộ hoặc từ xa. Tôi sẽ thêm dòng sau vào cả hai
 requirements.txt
các tập tin:

 debugpy == 1 . 6 . 4

Bây giờ tôi cần xây dựng lại hình ảnh để cài đặt gỡ lỗi trên hình ảnh Docker cho từng dịch vụ. tôi sẽ chạy

 docker-compose build
lệnh để làm điều này. Sau đó tôi sẽ chạy
 docker-compose up
để khởi động các container.

Tiếp theo, tôi sẽ đính kèm VSCode vào bộ chứa đang chạy có chứa quy trình mà tôi muốn gỡ lỗi, như tôi đã làm ở trên.

Để đính kèm trình gỡ lỗi vào ứng dụng python đang chạy, tôi cần thêm đoạn mã sau vào mã tại điểm mà tôi muốn bắt đầu gỡ lỗi:

 import debugpy; debugpy.listen( 5678 )

Đoạn mã này nhập mô-đun gỡ lỗi và gọi

 listen
bắt đầu một máy chủ gỡ lỗi lắng nghe các kết nối từ trình gỡ lỗi trên số cổng đã chỉ định (trong trường hợp này là 5678).

Nếu tôi muốn gỡ lỗi

 authors_service
, tôi có thể đặt đoạn mã trên ngay trước
 get_author_by_id
khai báo hàm trong
 app.py
tập tin - như sau:

 import os import flask import requests from faker import Faker app = flask.Flask(__name__) import debugpy; debugpy.listen( 5678 ) @app.route( "/authors/<string:author_id>" , methods=[ "GET" ] )
def get_author_by_id ( author_id: str ):
...

Điều này sẽ khởi động một máy chủ gỡ lỗi khi khởi động ứng dụng vì

 app.py
tập lệnh được thực thi.

Bước tiếp theo là tạo cấu hình khởi chạy VSCode để gỡ lỗi ứng dụng. Trong thư mục gốc của dịch vụ chứa bộ chứa mà tôi đã đính kèm (và trên đó tôi đang chạy cửa sổ VSCode), tôi sẽ tạo một thư mục có tên

 .vscode
. Sau đó, trong thư mục này, tôi sẽ tạo một tệp có tên
 launch.json
, với nội dung như sau:

 {    "version" : "0.2.0" ,    "configurations" : [ {            "name" : "Python: Remote Attach" ,            "type" : "python" ,            "request" : "attach" ,            "connect" : {                "host" : "localhost" ,                "port" : 5678
 } } ] }

Cấu hình này chỉ định rằng VSCode sẽ đính kèm với trình gỡ lỗi Python chạy trên máy cục bộ (tức là vùng chứa hiện tại) trên cổng 5678 - điều quan trọng là cổng được chỉ định khi gọi hàm

 debugpy.listen
chức năng trên.

Sau đó tôi sẽ lưu tất cả các thay đổi. Trong chế độ xem trình khám phá của tiện ích mở rộng Docker, tôi sẽ nhấp chuột phải vào vùng chứa mà tôi hiện đang đính kèm và chọn "Khởi động lại vùng chứa" từ menu ngữ cảnh (được thực hiện trên phiên bản VSCode cục bộ). Sau khi khởi động lại bộ chứa, cửa sổ VSCode trong bộ chứa sẽ hiển thị hộp thoại hỏi tôi có muốn tải lại cửa sổ không - câu trả lời đúng là có.

Bây giờ tất cả những gì còn lại là xem nó hoạt động!Để bắt đầu gỡ lỗi, trong phiên bản VSCode đang chạy trên bộ chứa, tôi sẽ mở tập lệnh mà tôi muốn gỡ lỗi và nhấn F5 để bắt đầu trình gỡ lỗi. Trình gỡ lỗi sẽ đính kèm vào tập lệnh và tạm dừng thực thi tại dòng mà

 debugpy.listen
chức năng được gọi. Giờ đây, các điều khiển trình gỡ lỗi trong tab Gỡ lỗi có thể được sử dụng để duyệt qua mã, đặt điểm dừng và kiểm tra các biến.

Điều này đáp ứng yêu cầu "Gỡ lỗi" ở trên.

Phát triển và gỡ lỗi từ xa với Jetbrains Pycharm IDE

Theo tài liệu chính thức , có hai cách để giải quyết vấn đề này khi sử dụng PyCharm: Có thể truy xuất trình thông dịch từ hình ảnh Docker bằng tính năng trình thông dịch từ xa và/hoặc cấu hình máy chủ gỡ lỗi từ xa . Lưu ý rằng hai tùy chọn này không loại trừ lẫn nhau. Cá nhân tôi chủ yếu dựa vào tính năng phiên dịch từ xa để phát triển và sử dụng cấu hình máy chủ gỡ lỗi từ xa nếu và khi cần thiết.



Thiết lập trình thông dịch từ xa

Để thiết lập trình thông dịch từ xa trên PyCharm, tôi sẽ:

1. Nhấp vào menu bật lên tab trình thông dịch ở góc dưới cùng bên phải của cửa sổ IDE.

2. Nhấp vào Thêm trình thông dịch mới , sau đó chọn Trên trình soạn thảo docker... từ trình đơn bật lên.

3. Trong cửa sổ bật lên tiếp theo, chọn tệp soạn thảo docker có liên quan, sau đó chọn dịch vụ có liên quan từ danh sách thả xuống. Bây giờ PyCharm sẽ cố gắng kết nối với hình ảnh docker và truy xuất các trình thông dịch python có sẵn.

4. Trong cửa sổ tiếp theo, chọn trình thông dịch python mà tôi muốn sử dụng (ví dụ:

 /usr/local/bin/python
). Khi trình thông dịch đã được chọn, nhấp vào "Tạo".

Sau đó, PyCharm sẽ lập chỉ mục cho trình thông dịch mới, sau đó tôi có thể chạy hoặc gỡ lỗi mã như bình thường - PyCharm sẽ điều phối việc soạn thảo docker phía sau hậu trường cho tôi bất cứ khi nào tôi muốn làm như vậy.

Thiết lập cấu hình máy chủ gỡ lỗi từ xa

Để thiết lập cấu hình máy chủ gỡ lỗi từ xa, trước tiên tôi cần thêm hai phụ thuộc vào liên quan

 requirements.txt
(các) tệp: pydevdpydevd_pycharm . Các gói này có chức năng tương tự như gói gỡ lỗi đã trình bày ở trên, nhưng, như tên gọi của nó, pydevd_pycharm được thiết kế đặc biệt để gỡ lỗi với PyCharm. Trong ngữ cảnh của dự án demo này, tôi sẽ thêm hai dòng sau vào cả hai
 requirements.txt
các tập tin:

 pydevd ~= 2 . 9 . 1
pydevd -pycharm== 223 . 8214 . 17

Khi điều này được thực hiện và hình ảnh docker đã được xây dựng lại, tôi có thể nhúng đoạn mã sau vào mã để khởi động máy chủ gỡ lỗi pydevd_pycharm tại điểm trong mã mà tôi muốn bắt đầu gỡ lỗi:

 import pydevd_pycharm; pydevd_pycharm.settrace( 'host.docker.internal' , 5678 )

Lưu ý rằng không giống như gỡ lỗi, ở đây tôi đã chỉ định địa chỉ tên máy chủ có giá trị "host.docker.internal", là tên DNS phân giải thành địa chỉ IP nội bộ của máy chủ từ bên trong bộ chứa Docker. Điều này là do tôi không chạy PyCharm trên vùng chứa; thay vào đó, tôi đang định cấu hình hiệu quả máy chủ gỡ lỗi để nghe trên cổng 5678 của máy chủ .

Tùy chọn này cũng tồn tại với tính năng gỡ lỗi, nhưng vì trong trường hợp đó tôi đang chạy một phiên bản VSCode trên chính bộ chứa, nên nó đã đơn giản hóa mọi thứ để chỉ để địa chỉ tên máy chủ mặc định là "localhost" (tức là giao diện loopback của chính bộ chứa đó, chứ không phải máy chủ).

Bước cuối cùng là thiết lập cấu hình chạy mà PyCharm có thể sử dụng để kết nối với máy chủ gỡ lỗi từ xa.

Để làm điều này, tôi sẽ:

1. Mở hộp thoại Chạy/Gỡ lỗi Cấu hình bằng cách chọn Chạy > Chỉnh sửa Cấu hình từ menu chính.

2. Nhấp vào nút + ở góc trên cùng bên trái của hộp thoại và chọn Python Remote Debug từ trình đơn thả xuống.

3. Trong trường Tên , nhập tên cho cấu hình chạy.

4. Trong trường Đường dẫn tập lệnh , chỉ định đường dẫn đến tập lệnh mà tôi muốn gỡ lỗi.

5. Trong trường Máy chủ , hãy nhập địa chỉ IP của máy chủ mà máy chủ trình gỡ lỗi sẽ chạy. Trong ví dụ này, đó là "localhost".

6. Trong trường Cổng , hãy nhập số cổng mà máy chủ trình gỡ lỗi sẽ nghe. Trong ví dụ này, đó là 5678.

7. Trong phần Ánh xạ đường dẫn , tôi có thể chỉ định cách các đường dẫn trên máy chủ ánh xạ tới các đường dẫn bên trong vùng chứa. Điều này hữu ích nếu tôi đang gỡ lỗi mã được gắn vào bộ chứa từ máy chủ, vì các đường dẫn có thể không giống nhau trong cả hai môi trường. Trong ví dụ này, tôi sẽ muốn lập bản đồ

 path/to/project/on/host/authors_service
trên máy chủ, để
 /app
trong vùng chứa để gỡ lỗi tác giả_service hoặc
 path/to/project/on/host/posts_service
đến
 /app
trên vùng chứa để gỡ lỗi posts_service (đây sẽ cần phải là hai cấu hình chạy riêng biệt).

8. Nhấn OK để lưu cấu hình chạy.

Để bắt đầu gỡ lỗi, tôi sẽ chọn cấu hình chạy ở trên từ menu thả xuống Chạy và nhấp vào nút Gỡ lỗi , sau đó quay (các) vùng chứa có liên quan bằng

 docker-compose up
chỉ huy. Trình gỡ lỗi PyCharm sẽ đính kèm vào tập lệnh và tạm dừng thực thi tại dòng nơi tập lệnh
 pydevd_pycharm.settrace
chức năng được gọi, cho phép tôi bắt đầu đập những lỗi đó.


Tóm tắt

Trong hướng dẫn này, tôi đã đưa ra một cái nhìn tổng quan nhưng thực tế về môi trường phát triển python được container hóa, tại sao chúng lại hữu ích và cách viết, triển khai và gỡ lỗi mã python bằng cách sử dụng chúng. Xin lưu ý rằng đây không phải là hướng dẫn toàn diện để làm việc với các môi trường này. Nó chỉ đơn thuần là một điểm khởi đầu để từ đó mở rộng. Dưới đây là một vài liên kết hữu ích để kết thúc đó:

1. Tổng quan về container hóa bằng redhat

3.Tài liệu Docker chính thức

4. Tài liệu JetBrains PyCharm chính thức để gỡ lỗi từ xa

5.Tài liệu VSCode chính thức để phát triển Python trên vùng chứa dev

Tôi hy vọng bạn thấy hướng dẫn này hữu ích - cảm ơn vì đã đọc!