Bài 40.5: Bài tập thực hành deploy containerized app

Bài 40.5: Bài tập thực hành deploy containerized app
Chào mừng bạn đến với bài thực hành quan trọng trên hành trình trở thành Fullstack Developer! Sau khi xây dựng ứng dụng web, bước tiếp theo và cũng không kém phần thử thách chính là đưa nó đến tay người dùng. Traditional deployment có thể gặp nhiều vấn đề như "nó chạy trên máy tôi mà?", xung đột thư viện, cấu hình môi trường phức tạp. Đây chính là lúc sức mạnh của Container tỏa sáng.
Containerization, với Docker là công cụ phổ biến nhất, cho phép bạn đóng gói ứng dụng cùng với tất cả các thư viện, phụ thuộc và cấu hình cần thiết vào một "hộp" độc lập, gọi là container. Hộp này có thể chạy nhất quán trên mọi môi trường, từ máy local của developer, máy chủ staging, đến máy chủ production.
Trong bài thực hành này, chúng ta sẽ cùng nhau trải qua các bước cơ bản để biến một ứng dụng web (giả định là một ứng dụng Node.js/React/Next.js đơn giản, vì nó phù hợp với chuỗi bài này) thành một container và triển khai nó.
Tại sao lại là Container?
Hãy tưởng tượng bạn dành hàng tuần, hàng tháng để phát triển một ứng dụng web tuyệt vời. Mọi thứ hoạt động hoàn hảo trên máy tính của bạn. Nhưng khi bạn cố gắng cài đặt nó trên máy chủ (server), rắc rối bắt đầu: phiên bản Node.js khác, thiếu thư viện, xung đột cổng, cấu hình hệ điều hành không tương thích... Quen thuộc đúng không?
Container giải quyết vấn đề này bằng cách cung cấp một môi trường độc lập, nhất quán và di động.
- Nhất quán: Ứng dụng và môi trường của nó được đóng gói cùng nhau. Bất kể container chạy ở đâu, nó luôn thấy cùng một môi trường.
- Độc lập: Mỗi container chạy trong không gian riêng, không ảnh hưởng đến các container hoặc ứng dụng khác trên cùng một máy chủ.
- Di động: Container có thể được di chuyển và chạy trên bất kỳ hệ thống nào có hỗ trợ container runtime (như Docker).
Công cụ chính: Docker
Docker là nền tảng phổ biến nhất để xây dựng, chia sẻ và chạy container. Nó sử dụng Dockerfile để định nghĩa các bước xây dựng một image (bản mẫu) của ứng dụng, và chạy container (một thể hiện sống động của image đó).
Bước 1: Docker hóa ứng dụng (Viết Dockerfile)
Dockerfile là một file văn bản chứa các chỉ dẫn để Docker xây dựng image của bạn. Mỗi chỉ dẫn là một lớp (layer) trong image.
Giả sử bạn có một ứng dụng Node.js đơn giản. Đây là một ví dụ về Dockerfile:
# Sử dụng một image cơ sở (base image) chứa Node.js
FROM node:18-alpine
# Thiết lập thư mục làm việc bên trong container
WORKDIR /app
# Copy file package.json và package-lock.json (hoặc yarn.lock)
# Điều này giúp tối ưu việc build image, vì layer này chỉ thay đổi khi dependencies thay đổi
COPY package*.json ./
# Cài đặt các dependencies của ứng dụng
RUN npm install
# Copy toàn bộ mã nguồn ứng dụng vào thư mục làm việc
COPY . .
# Cho Docker biết container lắng nghe ở cổng nào (ví dụ: cổng 3000 cho ứng dụng React/Next.js mặc định)
EXPOSE 3000
# Lệnh mặc định sẽ chạy khi container khởi động
CMD [ "npm", "start" ]
- Giải thích code:
FROM node:18-alpine
: Chỉ định image cơ sở. Chúng ta dùng image Node.js phiên bản 18 dựa trên Alpine Linux (một bản phân phối Linux rất nhẹ) để giữ cho image cuối cùng có kích thước nhỏ.WORKDIR /app
: Tạo thư mục/app
bên trong container và đặt nó làm thư mục làm việc hiện tại cho các lệnh tiếp theo.COPY package*.json ./
: Sao chép các filepackage.json
vàpackage-lock.json
từ thư mục hiện tại trên máy local vào thư mục/app
trong container.RUN npm install
: Chạy lệnhnpm install
bên trong container để cài đặt tất cả các dependencies được liệt kê trongpackage.json
.COPY . .
: Sao chép toàn bộ các file và thư mục còn lại từ thư mục hiện tại trên máy local (ngoại trừ những gì được liệt kê trong.dockerignore
nếu có) vào thư mục/app
trong container.EXPOSE 3000
: Thông báo rằng container sẽ lắng nghe kết nối trên cổng 3000. Lưu ý: Lệnh này không thực sự mở cổng trên máy chủ, nó chỉ là tài liệu và giúp các công cụ orchestration biết cổng nào cần phơi bày.CMD [ "npm", "start" ]
: Chỉ định lệnh sẽ chạy khi container khởi động. Đây là lệnh để khởi động ứng dụng Node.js của bạn.
Tạo một file tên là Dockerfile
(không có đuôi file) ở thư mục gốc của dự án và dán nội dung trên vào (nhớ điều chỉnh EXPOSE
và CMD
nếu ứng dụng của bạn dùng cổng hoặc lệnh khác).
Bước 2: Xây dựng Docker Image
Sau khi có Dockerfile, bạn cần xây dựng image từ nó. Mở terminal tại thư mục gốc của dự án và chạy lệnh sau:
docker build -t my-web-app:latest .
- Giải thích lệnh:
docker build
: Lệnh để xây dựng Docker image.-t my-web-app:latest
: Gắn thẻ (tag) cho image.my-web-app
là tên image,latest
là tag (bạn có thể dùng số phiên bản như1.0
thay cholatest
). Việc gắn thẻ giúp bạn dễ dàng quản lý và tham chiếu image..
: Chỉ định ngữ cảnh xây dựng (build context). Dấu chấm.
nghĩa là Docker sẽ tìm Dockerfile và các file cần thiết trong thư mục hiện tại.
Quá trình build sẽ chạy từng bước trong Dockerfile. Lần đầu có thể mất chút thời gian để tải base image và cài đặt dependencies. Những lần build sau sẽ nhanh hơn nhờ caching các layer đã thay đổi ít.
Bạn có thể kiểm tra image vừa tạo bằng lệnh:
docker images
Bạn sẽ thấy image my-web-app
với tag latest
trong danh sách.
Bước 3: Chạy Container trên máy Local (Kiểm thử)
Trước khi deploy, hãy đảm bảo container chạy đúng trên máy local của bạn. Chạy lệnh sau:
docker run -p 80:3000 my-web-app:latest
- Giải thích lệnh:
docker run
: Lệnh để chạy một container từ image.-p 80:3000
: Ánh xạ cổng (port mapping). Lệnh này yêu cầu Docker chuyển tiếp (forward) lưu lượng từ cổng80
trên máy host (máy tính của bạn) đến cổng3000
bên trong container. Nếu ứng dụng của bạn chạy trên cổng khác trong container (ví dụ: 8080), bạn sẽ đổi thành-p 80:8080
. Ánh xạ cổng 80 là phổ biến vì đây là cổng HTTP mặc định.my-web-app:latest
: Tên và tag của image bạn muốn chạy.
Bây giờ, mở trình duyệt và truy cập http://localhost
. Bạn sẽ thấy ứng dụng của mình đang chạy bên trong container!
Để chạy container ở chế độ nền (detached mode), sử dụng thêm cờ -d
:
docker run -d -p 80:3000 --name my-running-app my-web-app:latest
--name my-running-app
: Đặt tên cho container, giúp bạn dễ dàng quản lý nó sau này (dừng, khởi động lại...).
Bạn có thể xem các container đang chạy bằng lệnh:
docker ps
Và dừng container bằng tên hoặc ID của nó:
docker stop my-running-app
Bước 4: Đẩy Image lên Docker Registry
Để triển khai container trên một máy chủ khác, máy chủ đó cần có quyền truy cập vào image của bạn. Cách phổ biến nhất là đẩy image lên một Docker Registry (kho chứa image). Docker Hub là registry công cộng lớn nhất, hoặc bạn có thể dùng các registry riêng tư (như AWS ECR, Google Container Registry, GitLab Registry...).
Đầu tiên, bạn cần tạo tài khoản Docker Hub (nếu chưa có) và đăng nhập vào Docker từ terminal:
docker login
Nhập username và password Docker Hub của bạn.
Tiếp theo, bạn cần "gắn thẻ" lại (tag) image với tên Docker Hub username của bạn để Docker biết đẩy image này đi đâu:
docker tag my-web-app:latest your-dockerhub-username/my-web-app:latest
- Giải thích lệnh:
docker tag
: Lệnh để tạo một tag mới cho image hiện có.my-web-app:latest
: Image nguồn (image bạn đã build).your-dockerhub-username/my-web-app:latest
: Tag mới. Format chuẩn cho Docker Hub làusername/image-name:tag
. Thayyour-dockerhub-username
bằng username Docker Hub thực tế của bạn.
Cuối cùng, đẩy image đã được tag lên Docker Hub:
docker push your-dockerhub-username/my-web-app:latest
Quá trình này có thể mất một chút thời gian tùy thuộc vào kích thước image và tốc độ mạng của bạn. Sau khi hoàn thành, image của bạn sẽ có sẵn trên Docker Hub và có thể được kéo về từ bất kỳ máy chủ nào có Docker.
Bước 5: Triển khai Container trên Máy Chủ
Giả định bạn đã có một máy chủ ảo (VPS) hoặc máy chủ vật lý chạy Linux và đã cài đặt Docker trên đó. Các bước triển khai sẽ như sau:
Kết nối đến máy chủ: Sử dụng SSH để truy cập vào máy chủ của bạn.
ssh your-server-user@your-server-ip
Thay
your-server-user
vàyour-server-ip
bằng thông tin của bạn.Kéo Image về máy chủ: Từ terminal trên máy chủ, kéo image mà bạn vừa đẩy lên Docker Hub về.
docker pull your-dockerhub-username/my-web-app:latest
Docker sẽ tải image về máy chủ.
Chạy Container trên máy chủ: Bây giờ, chạy container từ image đã kéo về. Bạn sẽ dùng lệnh
docker run
tương tự như chạy local, nhưng có thể thêm cờ-d
để chạy ngầm và--name
để dễ quản lý.docker run -d -p 80:3000 --name my-production-app your-dockerhub-username/my-web-app:latest
-d
: Chạy container ở chế độ detached (ngầm), giải phóng terminal.-p 80:3000
: Ánh xạ cổng 80 trên máy chủ (cổng HTTP mặc định) tới cổng 3000 bên trong container. Đảm bảo cổng 80 trên máy chủ của bạn không bị ứng dụng khác chiếm dụng và firewall cho phép truy cập cổng 80.--name my-production-app
: Đặt tên cho container đang chạy.
Sau khi chạy lệnh này, ứng dụng của bạn sẽ chạy trong container trên máy chủ. Bạn có thể truy cập nó qua địa chỉ IP hoặc tên miền của máy chủ đó (nếu bạn đã cấu hình DNS).
Để kiểm tra container đang chạy:
docker ps
Để xem log của container (hữu ích cho việc debug):
docker logs my-production-app
Để dừng ứng dụng:
docker stop my-production-app
Và xóa container đã dừng (để giải phóng tài nguyên):
docker rm my-production-app
Comments