Giới thiệu
Gần đây, tôi đã đưa ứng dụng Tideman từ máy tính cá nhân lên đám mây, và việc đưa nó trực tuyến trên AWS EC2 với Docker thực sự đơn giản hơn tôi nghĩ.
Mục tiêu bài viết
Trong bài viết này, tôi sẽ hướng dẫn bạn cách triển khai ứng dụng bầu cử Tideman sử dụng Docker trên EC2. Chúng ta sẽ đi qua từng bước, từ việc thiết lập EC2 đến cấu hình Docker và chạy ứng dụng Flask.
Tạo phiên bản EC2
Bước 1: Khởi tạo EC2
Trước tiên, tôi đã khởi tạo một AWS EC2 instance với hệ điều hành Ubuntu. Tôi chọn một phiên bản nhỏ (đủ điều kiện miễn phí) vì ứng dụng của tôi không quá nặng nề.
Bước 2: Cấu hình Security Group
Sau khi khởi tạo, tôi cấu hình Security Group của instance để cho phép các cổng thích hợp:
- Cổng 22 (SSH) cho phép kết nối tới terminal của server.
- Cổng 80 (HTTP) để ứng dụng web có thể truy cập qua trình duyệt.
Bước 3: Cài đặt Docker
Tiếp theo, tôi đã cài đặt Docker và sao chép mã nguồn vào EC2 instance:
bash
# Trên instance EC2
sudo apt-get update
sudo apt-get install -y docker.io git
# (Tùy chọn) sao chép repo và chuyển vào thư mục
git clone <đường-dẫn-repo>
cd <thư-mục-repo>
Viết Dockerfile với Multi-Stage
Giờ đây, chúng ta sẽ container hóa ứng dụng với Docker.
Bước 4: Tạo Dockerfile
Tôi đã tạo một file có tên Dockerfile trong thư mục dự án. Vì ứng dụng của tôi có hai thành phần (C++ và Python), tôi đã sử dụng multi-stage Docker build để giữ cho hình ảnh cuối cùng gọn nhẹ. Dưới đây là cách tôi thiết lập:
Giai đoạn 1: Biên dịch chương trình C++
Trong giai đoạn đầu tiên, tôi đã sử dụng một hình ảnh Docker với trình biên dịch C++ để biên dịch thuật toán:
dockerfile
# Giai đoạn 1: Biên dịch mã C++
FROM gcc:latest AS builder # Sử dụng hình ảnh trình biên dịch GCC
WORKDIR /app
# Sao chép mã nguồn C++ và biên dịch
COPY my_algorithm.cpp /app/my_algorithm.cpp
RUN g++ my_algorithm.cpp -o my_algorithm
Giai đoạn 2: Thiết lập Python + Flask
Trong giai đoạn thứ hai, tôi muốn một môi trường Python nhẹ để chạy Flask và nhị phân đã biên dịch. Tôi đã chọn một hình ảnh Python nhỏ gọn:
dockerfile
# Giai đoạn 2: Chạy ứng dụng Flask với Gunicorn
FROM python:3.10-slim AS final # Sử dụng hình ảnh Python nhỏ
WORKDIR /app
# Sao chép nhị phân C++ đã biên dịch từ giai đoạn builder
COPY --from=builder /app/my_algorithm /app/my_algorithm
# Sao chép mã ứng dụng Flask và các file khác
COPY app.py /app/app.py
COPY index.html /app/index.html
COPY requirements.txt /app/requirements.txt
# Cài đặt Flask (và Gunicorn) qua requirements
RUN pip install -r requirements.txt
# Mở cổng 5000 và khởi động ứng dụng bằng Gunicorn
EXPOSE 5000
CMD ["gunicorn", "-b", "0.0.0.0:5000", "app:app"]
Phân tích giai đoạn 2
- Chúng ta chuyển sang hình ảnh Python 3 slim (nhỏ hơn nhiều so với hình ảnh Ubuntu hoặc GCC đầy đủ).
- Sao chép nhị phân C++ đã biên dịch từ giai đoạn 1 vào hình ảnh mới này. Bằng cách này, container Python có thể sử dụng chương trình C++ mà không cần trình biên dịch.
- Sao chép mã ứng dụng Flask (
app.py),index.html, vàrequirements.txtliệt kê các phụ thuộc Python. - Cài đặt các phụ thuộc: Tôi đã bao gồm Flask (và Gunicorn cho server) trong
requirements.txt, do đópip install -r requirements.txtsẽ kéo chúng vào container. - Cuối cùng, thiết lập container lắng nghe trên cổng 5000 và định nghĩa lệnh khởi động: tôi sử dụng Gunicorn để chạy ứng dụng Flask.
Phương pháp multi-stage giúp hình ảnh cuối cùng (giai đoạn 2) không bao gồm tất cả các công cụ xây dựng cồng kềnh từ giai đoạn 1. Chúng ta chỉ mang theo nhị phân đã biên dịch và các file cần thiết. Điều này làm cho hình ảnh Docker cuối cùng nhỏ hơn và sạch hơn, rất tốt cho hiệu suất và bảo mật.
Xây dựng và chạy container Docker
Với Dockerfile đã được viết, tôi tiến hành xây dựng hình ảnh trên EC2 instance:
bash
sudo docker build -t myflaskcpp .
Chạy container
Tiếp theo, tôi đã chạy container. Đây là lúc cấu hình cổng rất quan trọng. Ứng dụng Flask của tôi (thông qua Gunicorn) được thiết lập chạy trên cổng 5000 bên trong container. Nhưng tôi muốn mọi người truy cập nó thông qua cổng HTTP chuẩn cổng 80 trên instance EC2. Vì vậy, tôi đã sử dụng ánh xạ cổng:
bash
sudo docker run -d -p 80:5000 myflaskcpp
Ở đây, -p 80:5000 ánh xạ cổng 80 trên máy chủ (EC2 instance) tới cổng 5000 bên trong container. Giờ đây, bất kỳ yêu cầu nào đến IP công cộng của EC2 trên cổng 80 sẽ được chuyển tiếp đến ứng dụng Flask trong container. Tôi đã chạy container ở chế độ tách biệt (-d) để nó chạy trong nền.
Lưu ý: Đảm bảo bạn đã mở cổng 80 trong security group của EC2. Nếu không, bạn sẽ không thể truy cập ứng dụng từ trình duyệt.
Tại sao sử dụng Gunicorn thay vì máy chủ phát triển của Flask?
Bạn có thể tự hỏi tại sao tôi lại sử dụng Gunicorn trong Dockerfile, thay vì chỉ chạy máy chủ phát triển:
bash
python app.py
Lý do là máy chủ tích hợp của Flask (máy chủ bạn nhận được với app.run()) chỉ được thiết kế cho phát triển. Nó là đơn luồng theo mặc định và không được tối ưu hóa cho nhiều người dùng hoặc độ ổn định trong sản xuất.
Gunicorn, mặt khác, là một máy chủ WSGI sẵn sàng cho sản xuất. Nó có thể xử lý nhiều yêu cầu cùng một lúc bằng cách chạy nhiều tiến trình công nhân. Điều này có nghĩa là nếu một người dùng đang thực hiện một yêu cầu chậm, những người dùng khác vẫn có thể được phục vụ song song. Gunicorn cũng được thử nghiệm tốt cho việc triển khai, làm cho ứng dụng của bạn trở nên mạnh mẽ hơn dưới lưu lượng thực tế. Tóm lại, việc sử dụng Gunicorn đảm bảo ứng dụng Flask của chúng ta có thể xử lý nhiều người cùng một lúc và không bị sập ngay khi có dấu hiệu căng thẳng.
Kết luận
Bây giờ hãy lấy IP công cộng của instance EC2 và kiểm tra xem nó có hoạt động không.
Và đó là tất cả! Chúng ta đã triển khai thành công một thuật toán C++ và một giao diện web Flask trên AWS sử dụng Docker. Là một người mới kết hợp các công nghệ này, tôi thật sự cảm thấy tuyệt vời khi thấy nó chạy trực tiếp.
Những điểm chính cần ghi nhớ
- Sử dụng security groups của EC2 để mở các cổng bạn cần (SSH và HTTP trong trường hợp này).
- Docker multi-stage builds có thể kết hợp nhiều ngôn ngữ (biên dịch trong một giai đoạn, chạy trong giai đoạn khác) để giữ mọi thứ hiệu quả.
- Ánh xạ các cổng nội bộ của container tới các cổng của server để thế giới có thể truy cập ứng dụng của bạn.
- Gunicorn là người bạn đồng hành cho việc phục vụ Flask trong môi trường sản xuất.
Chúc bạn triển khai thành công! 🚀
Các thực tiễn tốt nhất
- Luôn kiểm tra các cổng trong security group trước khi triển khai.
- Sử dụng các hình ảnh Docker nhỏ gọn để tiết kiệm tài nguyên.
- Đảm bảo xử lý lỗi trong mã nguồn để ứng dụng hoạt động ổn định.
Những cạm bẫy phổ biến
- Không mở cổng HTTP dẫn đến việc không truy cập được ứng dụng.
- Sử dụng máy chủ phát triển Flask trong môi trường sản xuất.
Mẹo hiệu suất
- Tối ưu hóa Dockerfile để giảm kích thước hình ảnh.
- Sử dụng caching cho các phụ thuộc Python khi xây dựng hình ảnh.
Giải quyết sự cố
Nếu bạn gặp sự cố khi truy cập ứng dụng:
- Kiểm tra xem container có đang chạy không bằng lệnh
sudo docker ps. - Đảm bảo rằng IP công cộng của bạn là chính xác và không có vấn đề gì về mạng.
Câu hỏi thường gặp
1. Tôi cần cài đặt gì trên EC2 trước khi chạy ứng dụng?
Bạn cần cài đặt Docker và Git trên EC2 để có thể triển khai ứng dụng.
2. Tại sao lại sử dụng multi-stage builds?
Multi-stage builds giúp giảm kích thước hình ảnh Docker cuối cùng bằng cách chỉ giữ lại những file cần thiết.
3. Gunicorn có dễ sử dụng không?
Có, Gunicorn rất dễ cấu hình và cung cấp hiệu suất tốt hơn cho ứng dụng Flask của bạn.
Tài nguyên tham khảo
Hy vọng rằng bài viết này sẽ giúp bạn triển khai ứng dụng của mình một cách dễ dàng nhất!