Liệu bạn đã sử dụng Docker hiệu quả?

0 0 0

Người đăng: Toan Nguyen Truong

Theo Viblo Asia

Có bao giờ bạn tự hỏi mình đã dùng Docker hiệu quả như bản thân nó có thể?

Hiện nay, trong phát triển phần mềm, hầu hết các ứng dụng, dịch vụ đều sử dụng Docker. Docker giúp các nhà phát triển xây dựng, chia sẻ, chạy và xác minh ứng dụng ở mọi nơi mà không cần cấu hình hoặc quản lý môi trường phức tạp.

Trong bài viết hôm nay mình sẽ chia sẻ một số "tip" để sử dụng Docker hiệu quả hơn khi nó phát triển để phù hợp, nhanh, nhẹ hơn cho quá trình phát triển phần mềm liền mạch.

1. Dùng .dockerignore

Sử dụng tệp .dockerignore để loại trừ các tệp hoặc thư mục khỏi ngữ cảnh build image.

Khi bạn chạy lệnh build, build clients sẽ tìm kiếm tệp có tên .dockerignore trong thư mục gốc của ngữ cảnh. Nếu tệp này tồn tại, các tệp và thư mục khớp với các mẫu trong tệp sẽ bị xóa khỏi ngữ cảnh build trước khi được gửi đến trình build.

Nếu bạn sử dụng nhiều Dockerfile, bạn có thể sử dụng các ignore-file khác nhau cho mỗi Dockerfile. File ignore dành riêng cho Dockerfile tương ứng sẽ được ưu tiên hơn tệp .dockerignore ở gốc của ngữ cảnh build nếu cả hai đều tồn tại. Xem ví dụ sau:

.
├── index.ts
├── src/
├── docker
│ ├── build.Dockerfile
│ ├── build.Dockerfile.dockerignore
│ ├── lint.Dockerfile
│ ├── lint.Dockerfile.dockerignore
│ ├── test.Dockerfile
│ └── test.Dockerfile.dockerignore
├── package.json
└── package-lock.json

Thật rủi ro và vô lý khi đem những thứ như .git, .env, và node_modules lên production. Sử dụng .dockerignore, thu gọn build context của bạn, và giữ các secrets cùng những thứ không cần thiết ra khỏi image.

2. Loại bỏ version trong docker compose

Thuộc tính cấp cao nhất version được định nghĩa bởi Compose Specification để tương thích ngược. Thuộc tính này chỉ mang tính thông tin và bạn sẽ nhận được thông báo cảnh báo rằng thuộc tính này đã lỗi thời nếu sử dụng.

Thay vào đó, hiện tại thuộc tính cấp cao nhất là name, được định nghĩa bởi Compose Specification là tên dự án sẽ được sử dụng nếu bạn không đặt tên rõ ràng. Compose cung cấp cho bạn một cách để ghi đè tên này và đặt tên dự án mặc định sẽ được sử dụng nếu phần tử cấp cao nhất name không được đặt.

Ví dụ một docker-compose.yml hiện đại:

name: myapp services: foo: image: busybox command: echo "I'm running ${COMPOSE_PROJECT_NAME}"

3. Multi-stage builds

Với multi-stage builds, bạn sử dụng nhiều câu lệnh FROM trong Dockerfile của mình. Mỗi lệnh FROM có thể sử dụng một base image khác nhau và mỗi lệnh bắt đầu một giai đoạn mới của bản dựng. Bạn có thể sao chép có chọn lọc các thành phần từ giai đoạn này sang giai đoạn khác, bỏ lại mọi thứ bạn không muốn trong image cuối cùng. Điều này giúp image nhẹ hơn nhiều khi bạn loại bỏ các thứ như build tools, compilers, và test dependencies...

Ví dụ build image với multi-stage:

FROM golang:1.24 AS build
WORKDIR /src
COPY <<EOF /src/main.go
package main import "fmt" func main() { fmt.Println("hello, world")
}
EOF
RUN go build -o /bin/hello ./main.go FROM scratch
COPY --from=build /bin/hello /bin/hello
CMD ["/bin/hello"]

4. Chạy với user không phải root

Việc chạy container với quyền root trong production có thể là một rủi ro. Một số vấn lỗ hỏng bảo mật liên quan đến linux có thể gây hại cho container của bạn: CVE-2022-0847, CVE-2019-5736...

Hãy tạo một user không phải root trong Dockerfile và chuyển sang nó:

RUN useradd -m appuser
USER appuser

Chú ý cần đảm bảo rằng các volume mount thuộc về user không phải root mà bạn đã thêm để mọi thứ hoạt động.

5. Thêm Healthchecks

Thuộc tính healthcheck khai báo một kiểm tra được chạy để xác định xem các container dịch vụ có "khỏe mạnh" hay không. Nó hoạt động theo cùng một cách và có cùng các giá trị mặc định như lệnh HEALTHCHECK trong Dockerfile. File Compose có thể ghi đè các giá trị được đặt trong Dockerfile.

healthcheck: test: ["CMD", "curl", "-f", "http://localhost"] interval: 1m30s timeout: 10s retries: 3 start_period: 40s start_interval: 5s

Một trường hợp sử dụng phổ biến là để phát hiện trạng thái sẵn sàng của dịch vụ với thuộc tính condition theo tùy chọn service_healthy. Điều này chỉ rõ rằng một sự phụ thuộc được mong đợi là healthy, được định nghĩa bằng healthcheck, trước khi bắt đầu một dịch vụ phụ thuộc.

Trong ví dụ dưới Compose chờ kiểm tra tình trạng để chuyển các phụ thuộc được đánh dấu bằng service_healthy. db được mong đợi là "ổn định" (chỉ ra bởi healthcheck) trước khi service web được tạo.

services: web: build: . depends_on: db: condition: service_healthy restart: true redis: condition: service_started redis: image: redis db: image: postgres healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] interval: 10s retries: 5 start_period: 30s timeout: 10s

6. Sử dụng Docker BuildKit

Docker BuildKit là một công cụ build mới của Docker, giúp:

  • Tăng tốc độ build image.
  • Tăng khả năng tái sử dụng cache (layer caching).
  • Hỗ trợ parallel builds.
  • Cải thiện bảo mật và logs rõ ràng hơn.

Một trong những điểm mạnh của BuildKit là khả năng cache thư viện cục bộ, đặc biệt hữu ích khi làm việc với package manager như npm, pip, apt, go mod, composer,...

Giả sử bạn đang dùng Node.js, và bạn muốn cache thư viện npm để tránh phải npm install lại mỗi lần. Hãy xem ví dụ sử dụng BuildKit với Dockerfile bên dưới, các điểm chính:

  • --mount=type=cache,target=/root/.npm: Chỉ định một cache mount cho thư mục npm cache.
  • Docker sẽ giữ lại các gói đã cài, và lần build sau sẽ dùng lại cache đó nếu package.json không thay đổi.
  • Giúp tiết kiệm thời gian rất nhiều khi thường xuyên rebuild.
# syntax=docker/dockerfile:1.4
FROM node:18 WORKDIR /app # Copy package files trước để tận dụng cache
COPY package.json package-lock.json ./ # Dùng cache để lưu thư mục node_modules
RUN --mount=type=cache,target=/root/.npm \ npm ci # Copy source code vào sau
COPY . . CMD ["node", "index.js"]

Lưu ý: Dòng đầu tiên # syntax=docker/dockerfile:1.4 là để Docker biết sử dụng cú pháp BuildKit nâng cao.

Cách build tương ứng cho ví dụ trên sẽ là:

DOCKER_BUILDKIT=1 docker build -t my-node-app .

7. Tối ưu cho môi trường development

Nếu bạn đang chờ 2 phút cho mỗi lần build hoặc xem logs từ docker logs -f, bạn có thể làm tốt hơn.

  • Dùng docker compose watch để tự động rebuild khi có thay đổi file, tính năng này yêu cầu Docker Compose v2.17+
  • Hãy bind-mounted volumes để mount code từ máy host vào container bằng cách sử dụng volumes: trong compose
  • Thực hiện hot reload giúp app tự restart khi code thay đổi, tùy theo ngôn ngữ bạn sử dụng trong code mà có thể dùng nodemon, flask auto-reload,..vân vân, mây mây...

Mình sẽ thực hiện một ví dụ minh họa với serivce viết bằng NodeJS như sau:

  • Cấu trúc project:
myapp/
├── Dockerfile
├── docker-compose.yml
├── .dockerignore
├── package.json
└── src/ └── index.js
  • Nội dung Dockerfile:
# syntax=docker/dockerfile:1.4
FROM node:18 WORKDIR /app COPY package*.json ./ # Cache npm install
RUN --mount=type=cache,target=/root/.npm \ npm install # Copy source sau
COPY . . CMD ["npx", "nodemon", "src/index.js"]
  • docker-compose.yml
name: "myapp" services: app: build: context: . volumes: - .:/app # Mount code - /app/node_modules # Tránh ghi đè node_modules ports: - "3000:3000" command: ["npx", "nodemon", "src/index.js"] develop: watch: - path: . action: rebuild # Khi file thay đổi, Docker rebuild lại container
  • Trong code sẽ dùng nodemon để hot reload
  • Cách build:
DOCKER_BUILDKIT=1 docker build -t my-node-app .
  • Xem logs realtime như kiểu npm run dev:
docker compose logs -f app

Bạn có thói quen Docker lỗi thời nào mà phải bỏ không? Có những kiến thức mới và hay ho để bổ sung cho bài viết không? Hãy chia sẻ trong comments nhé.

Hy vọng với những kiến thức mình chia sẻ có thể giúp ích và cải thiện cách dùng Docker trong môi trường phát triển phần mềm hiện đại.

Tạm biệt và hẹn gặp lại các bạn!

Bình luận

Bài viết tương tự

- vừa được xem lúc

Cài đặt WSL / WSL2 trên Windows 10 để code như trên Ubuntu

Sau vài ba năm mình chuyển qua code trên Ubuntu thì thật không thể phủ nhận rằng mình đã yêu em nó. Cá nhân mình sử dụng Ubuntu để code web thì thật là tuyệt vời.

1 1 561

- vừa được xem lúc

Phần 1: Giới thiệu về Kubernetes

Kubernetes là gì. Trang chủ: https://kubernetes.io/. Ai cần Kubernetes.

0 0 108

- vừa được xem lúc

Docker: Chưa biết gì đến biết dùng (Phần 1- Lịch sử)

1. Vì sao nên sử dụng. . .

0 0 110

- vừa được xem lúc

Docker - những kiến thức cơ bản phần 1

Giới thiệu. Nếu bạn đang làm ở một công ty công nghệ thông tin, chắc rằng bạn đã được nghe nói về Docker.

0 0 87

- vừa được xem lúc

Docker: Chưa biết gì đến biết dùng (Phần 2 - Dockerfile)

1. Mở đầu.

0 0 73

- vừa được xem lúc

Docker: Chưa biết gì đến biết dùng (Phần 3: Docker-compose)

1. Mở đầu. . .

0 0 137