Docker là gì và tại sao lập trình viên nên học nó?
Phân tích thực tế Docker cho lập trình viên: container vs VM, các lệnh cốt lõi, Dockerfile, và cách bắt đầu sử dụng nó trong các dự án thực tế.
Docker liên tục xuất hiện trong các bài đăng tuyển dụng và hướng dẫn thiết lập, và nếu bạn chưa bao giờ chạm vào container, nó có thể cảm giác như một bức tường bạn phải vượt qua trước khi được phép viết code thực sự. Nó không phức tạp như vậy khi bạn vượt qua từ vựng.
Container thực sự là gì
Container đóng gói ứng dụng của bạn cùng với mọi thứ nó cần để chạy: code, runtime, thư viện hệ thống, và tệp config. Nó không phải là máy ảo. Máy ảo ảo hóa toàn bộ hệ điều hành, bao gồm kernel, điều đó có nghĩa là khởi động nó có thể mất một phút và tiêu tốn vài gigabyte RAM. Container chia sẻ kernel của máy host và chỉ cách ly process, vì vậy nó khởi động trong dưới một giây và thường chỉ sử dụng hàng chục megabyte thay vì gigabyte.
Sự khác biệt này là lý do Docker tiếp quản phát triển cục bộ và pipeline CI rất nhanh. Bạn có thể khởi động một cơ sở dữ liệu Postgres, một cache Redis, và server ứng dụng của bạn trên một máy tính xách tay mà không cần cài đặt bất kỳ cái nào trực tiếp trên OS của bạn.
Các phần cốt lõi bạn cần biết
Có bốn thuật ngữ bao gồm hầu hết những gì bạn sẽ phải xử lý hàng ngày:
- Image: một template chỉ đọc được xây dựng từ Dockerfile. Hãy coi nó như một snapshot của hệ thống tệp cộng với metadata về cách chạy nó.
- Container: một instance đang chạy của một image. Bạn có thể bắt đầu, dừng, và xóa container mà không cần chạm vào image mà chúng đến từ.
- Dockerfile: một tệp văn bản có chỉ thị để xây dựng image, từng dòng một.
- Registry: nơi các image được lưu trữ và kéo từ đó, phổ biến nhất là Docker Hub.
Một Dockerfile tối thiểu cho ứng dụng Node.js trông như thế này:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
Xây dựng nó với docker build -t my-app . và chạy nó với docker run -p 3000:3000 my-app. Flag -p ánh xạ một cổng trên máy của bạn đến một cổng bên trong container, đây là cách bạn thực sự tiếp cận ứng dụng từ trình duyệt.
Các lệnh bạn sẽ sử dụng liên tục
Một số ít lệnh bao gồm hầu hết công việc hàng ngày:
docker ps— liệt kê các container đang chạydocker ps -a— liệt kê tất cả container, bao gồm những cái đã dừngdocker images— liệt kê các image trên máy của bạndocker logs <container>— kiểm tra đầu ra từ một container đang chạy hoặc bị lỗidocker exec -it <container> sh— mở shell bên trong một container đang chạydocker rm/docker rmi— dọn dẹp các container và image bạn không còn cần
Cặp cuối cùng lại quan trọng hơn những gì mọi người mong đợi. Docker sẽ vui vẻ để không gian đĩa biến mất thành các image cũ và container đã dừng. Chạy docker system prune thỉnh thoảng sẽ giải phóng một lượng không gian đáng ngạc nhiên.
Tại sao docker-compose thay đổi quy trình làm việc
Hầu hết các dự án thực tế cần nhiều hơn một container: server ứng dụng, cơ sở dữ liệu, có thể là cache. Viết ra các lệnh docker run cho mỗi cái sẽ mau chóng trở nên nhàm chán. docker-compose.yml cho phép bạn định nghĩa toàn bộ stack trong một tệp:
services:
web:
build: .
ports:
- "3000:3000"
depends_on:
- db
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: devpassword
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
Chạy docker compose up và cả hai service khởi động cùng nhau, kết nối mạng để web có thể tiếp cận db theo tên service. Đây là thiết lập bạn sẽ thấy trong hầu hết README của repo mã nguồn mở, và hiểu nó có nghĩa là bạn có thể sao chép một dự án và chạy nó trong vài phút thay vì thủ công cài đặt Postgres, Redis, và bất cứ thứ gì khác mà ứng dụng cần.
Nơi mọi người bị vấp phải sớm
Volume làm nhầm lẫn hầu hết mọi người ngay từ đầu. Nếu không có volume, bất cứ thứ gì được viết bên trong container sẽ biến mất khi container bị xóa, điều này là vấn đề đối với cơ sở dữ liệu. Phần volumes trong tệp compose ở trên ánh xạ một volume được đặt tên đến một đường dẫn bên trong container để dữ liệu tồn tại qua các lần khởi động lại.
Một sai lầm phổ biến khác là sao chép node_modules hoặc .git vào image vì không có tệp .dockerignore. Thêm một cái giống như .gitignore:
node_modules
.git
.env
Điều đó giữ cho quá trình xây dựng nhanh hơn và image nhỏ hơn, điều này quan trọng khi bạn đẩy các image đến registry hoặc triển khai đến Kubernetes.
Nơi đi sau những điều cơ bản
Khi xây dựng và chạy container cảm thấy bình thường, các kỹ năng hữu ích tiếp theo là multi-stage build cho các image production nhỏ hơn, hiểu các chế độ Docker networking, và đọc đầu ra docker inspect khi có gì đó không kết nối đúng. Không có gì khó, nó chỉ là không quen lần đầu tiên.
Để biết thêm về containerizing các ứng dụng thực tế và kết nối chúng với cloud deployment pipeline, hãy xem các phần DevOps và Cloud trên Korra Studio.
Viết với hỗ trợ của AI, được xem xét và đăng bởi Michal Pilch (CISSP), Korra Studio.
Đây là một ghi chép từ cơ sở kiến thức Korra Studio — nền tảng kết hợp mỗi chủ đề với phiên hỗ trợ 1-kèm-1.
Bắt đầu miễn phíarrow_forward