Dockerfile là gì?
Sơ lược 1 chút về ý nghĩa của Dockerfile, Dockerfile là một file văn bản chứa các lệnh để tự động xây dựng một image Docker (Docker image), hay Dockerfile dùng để đóng gói ứng dụng lại thành một Image và có thể chạy được trên nhiều nền tảng khác nhau như Windows, Linux, MacOS,.... sử dụng công nghệ container.
Các lệnh được khai báo trong Dockerfile dùng để:
- Cấu hình hệ điều hành
- Cài đặt các phần mềm cần thiết
- Sao chép dữ liệu
- Cấu hình ứng dụng
- Xác định lệnh khởi động
Lợi ích của việc sử dụng Dockerfile:
- Tính nhất quán: Đảm bảo rằng ứng dụng được xây dựng giống nhau trên mọi môi trường.
- Tái sử dụng: Có thể sử dụng Dockerfile để xây dựng các hình ảnh Docker cho các ứng dụng khác nhau.
- Dễ dàng chia sẻ: Chia sẻ Dockerfile với người khác để họ có thể dễ dàng xây dựng và chạy ứng dụng của bạn.
Ví dụ về Dockerfile đơn giản:
FROM ubuntu:18.04 RUN apt-get update && apt-get install -y nginx COPY index.html /usr/share/nginx/html CMD ["nginx", "-g", "daemon off;"]
Dockerfile này sẽ:
- Sử dụng hình ảnh Ubuntu 18.04 làm cơ sở. (Dòng 1)
- Cài đặt Nginx. (Dòng 2)
- Sao chép tệp index.html vào thư mục /usr/share/nginx/html. (Dòng 3)
- Khởi động Nginx với chế độ daemon off. (Dòng 4)
Tại sao phải tối ưu Dockerfile
Có nhiều lý do cần tối ưu Dockerfile, đơn giản nhất có thể chỉ ra một vài ý chính:
-
Tiết kiệm dung lượng: Image Docker nhỏ gọn sẽ giúp tiết kiệm dung lượng lưu trữ và băng thông mạng khi pull và push image
-
Tăng tốc độ build: Build hình ảnh Docker nhanh hơn giúp đẩy nhanh quá trình phát triển và triển khai ứng dụng. Ví dụ team dev ở công ty bạn build 1 project hết 20 phút và một ngày cần build 3 lần để deploy test trên dev. Giả dụ bạn tối ưu để quá trình build chỉ còn 5 phút, vậy là mỗi ngày bạn đã tiết kiệm được thêm (20-5) x 3 = 45 phút/ngày cho team dev, nhân lên 1 năm thì sẽ tiết kiệm được vô cùng nhiều thời gian và tiền bạc.
-
Tăng cường bảo mật: Giảm thiểu các lỗ hổng bảo mật bảo vệ ứng dụng khỏi các mối đe dọa, lộ lọt thông tin.
-
Dễ dàng sử dụng: Tối ưu Dockfile sẽ giúp developers dễ dàng hiểu và sửa đổi Dockerfile khi cần thiết.
Các ý tưởng tối ưu Dockfile
1. Sử dụng Image tối giản
Ví dụ khi dockerize ứng dụng Python, thay vì sử dụng base image python:3.9.19
, hãy sử dụng python:3.9.19-alpine
.
Image Alpine có kích thước nhỏ hơn nhiều vì nó chỉ bao gồm các thành phần cần thiết. Trong ví dụ trên nếu sử dụng image alpine ta đã tiết kiệm được hơn 300MB trên mỗi lần build image.
2. Không cài đặt các công cụ thừa thãi
Chỉ cài đặt các thư viện và công cụ cần thiết cho ứng dụng của bạn.
- Tránh cài đặt các gói "full" hoặc "dev" vì chúng bao gồm nhiều công cụ không cần thiết.
- Đôi khi để dễ cho công việc debug, nhiều bạn còn cài thêm nhiều các công cụ debug.
Để biết được công cụ nào là cần, công cụ nào không cần mình hay tự hỏi bản thân câu hỏi "Thứ này có cần để chạy ứng dụng không?" trước khi thêm bất cứ dòng lệnh nào vào Dockerfile.
Ví dụ:
# Không nên
RUN apt install curl python-pip jq bash speedtest net-tools # Nên
RUN apt install python-pip
3. Gộp nhiều câu lệnh RUN
Viết nhiều câu lệnh RUN tách biệt với nhau có thể sẽ giúp Dockerfile của bạn dễ nhìn hơn, tuy nhiên với mỗi câu lệnh Docker sẽ tạo ra 1 layer image tương ứng. Việc gộp các câu lệnh RUN liên tiếp thành một để giảm số lượng layer trong hình ảnh Docker, tối ưu được cache từ đó giảm thời gian build image.
Ví dụ:
# Không nên
RUN pip install flask
RUN pip install gunicorn # Nên
RUN pip install flask gunicorn
4. Sử dụng nhiều stage để build image
Sử dụng nhiều stage trong Dockerfile giúp tách biệt các giai đoạn trong quá trình build. Điều này đặc biệt hữu ích khi các thành phần phụ thuộc tại quá trình build khác với các thành phần phụ thuộc trong quá trình chạy ứng dụng. Nó giúp tạo ra Image cuối cùng chỉ với các thành phần cần thiết, giúp cho image cuối cùng để chạy ứng dụng là nhỏ gọn nhất và an toàn hơn. Dockerize cho ứng dụng Java rất hay sử dụng phương thức này
Sử dụng chỉ 1 stage
FROM openjdk:11-jre-slim WORKDIR /app COPY pom.xml . RUN mvn clean install COPY target/my-app-1.0.0.jar . CMD ["java", "-jar", "my-app-1.0.0.jar"]
Sử dụng multi-stage
#Build Stage
FROM maven:3.8-jdk-11 AS build WORKDIR /app COPY pom.xml . RUN mvn clean install # Run Stage
FROM openjdk:11-jre-slim COPY /app/target/my-app-1.0.0.jar . CMD ["java", "-jar", "my-app-1.0.0.jar"]
5. Không thêm các file không cần thiết
Trong quá trình viết Dockerfile các bạn dev hoặc devops đôi khi sẽ lười mà chọn phương thức đơn giản nhất COPY . .
để chép toàn bộ source code vào trong container, tuy nhiên điều này thường là không cần thiết. Loại bỏ các file không cần thiết như .gitignore, .env, README.md khỏi quá trình chép source code vào image để giảm kích thước.
# Không nên
RUN pip install -r requirements.txt
COPY . . # Nên
RUN pip install -r requirements.txt
COPY app.py .
6. Sắp xếp các câu lệnh cho hợp lý để tối ưu Docker build cache
Docker khi build image sẽ đọc các câu lệnh từ trên xuống dưới, khi gặp một layer mới có sự thay đổi, Docker sẽ build mà không sử dụng cache từ layer đó. Chính vì vậy có một nguyên tắc là, những layer (hay câu lệnh) có ít sự thay đổi thì nên được để ở trên cùng trong Dockerfile.
Ví dụ:
# Không nên
FROM openjdk:11-jre-slim WORKDIR /app COPY pom.xml . RUN mvn clean install COPY target/my-app-1.0.0.jar . EXPOSE 8888 CMD ["java", "-jar", "my-app-1.0.0.jar"] # Nên FROM openjdk:11-jre-slim WORKDIR /app EXPOSE 8888 COPY pom.xml . RUN mvn clean install COPY target/my-app-1.0.0.jar . CMD ["java", "-jar", "my-app-1.0.0.jar"]
Thường các thành phần như WORKDIR
, EXPOSE
, file thư viện pom.xml
, cài đặt thư viện sẽ không có thay đổi nhiều ta nên để lên trên cùng.
7. Sử dụng cache từ các image đã build trước đó
Không liên quan lắm đến Dockerfile nhưng để giảm thời gian trong quá trình build trong những môi trường mà image được build trước đó của ứng dụng không tồn tại sẵn trong môi trường build thì bạn có thể sử dụng cache bằng cách pull image phiên bản trước về và build từ image đó.
Docker có hỗ trợ trường --cache-from
, sử dụng docker build --cache-from để tận dụng cache từ các image đã build trước đó, giúp tăng tốc độ build.
Ví dụ:
docker build --cache-from <image-id> -t my-app .
8. Sử dụng .dockerignore
Định nghĩa file .dockerignore và liệt kê các file không cần thiết trong quá trình build sẽ giúp Docker loại bỏ các file này vào trong quá trình build Ví dụ với ứng dụng python:
#.dockerignore __pycache__
*.pyc
*.pyo
*.pyd
.Python
env
pip-log.txt
pip-delete-this-directory.txt
.tox
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.log
.git
.mypy_cache
.pytest_cache
.hypothesis
Kết
Hy vọng bài viết này giúp ích được cho bạn trong công việc. Nếu bạn có ý tưởng gì thêm về việc tối ưu quá trình build hay xây dựng Dockerfile thì comment dưới chia sẻ với mình nhé.
Nếu thấy bài viết hay và muốn đọc thêm nhiều bài viết khác từ mình thì UpVote và Follow mình để tiếp thêm động lực cho mình nhé! Chúc bạn một ngày tốt lành 🤟🤟🤟