Dockerfile là file dùng để định nghĩa những thông số chính để khởi tạo ra những Image - và từ Image chúng ta tạo ra những Container. Cần lưu ý rằng, Dockerfile là một file không có phần mở rộng file (extension) mà chỉ có tên file Dockerfile.

1. Giới thiệu:

Trong bài  viết trước  chúng ta đã được giới thiệu về Docker và cách cài đặt Docker trên các Hệ Điều hành phổ biến, các bạn có thể tìm đọc lại bài viết ở đây tim-hieu-docker-p1

Lấy lại ví dụ trước chúng ta đã tìm hiểu về cách tạo một Container chạy Nginx, và trong bài viết này sẽ tiếp tục tìm hiểu cách định nghĩa một file Dockerfile để khởi tạo một Container Nginx hay với bất kỳ Image nào,

Dockerfile là file dùng để định nghĩa những thông số chính để khởi tạo ra những Image - và từ Image chúng ta tạo ra những Container. Có thể hiểu đơn giản như trong lập trình Hướng Đối tượng, Dockerfile là những file Java class, Imge là những file .class được biên dịch và Container chính là những Instance (thực thể) được tạo ra khi JRE thực thi những file .class.

Cần lưu ý rằng, Dockerfile là một file không có phần mở rộng file (extension) mà chỉ có tên file Dockerfile.

 

2. Dockerfile và Image:

2.1 Cấu tạo layer của Image:

Trước khi tìm hiểu về Dockerfile và ý nghĩa của những từ khoá của Dockerfile, chúng ta cần tìm hiểu về cách thức cấu tạo của Image. Docker Image có cấu tạo bởi các Layer xếp tầng lên nhau, các tầng Layer trên cùng là những Image gốc đầu tiên mà ban đầu được tạo ra bởi hãng Docker, các Image gốc này thường chính là Image của các Hệ Điều hành như Ubuntu, Debian, Fedora, ... 

Khi hãng Docker  phổ biến nền tảng Docker ra  công chúng, hãng đã đưa ra những Docker Image đầu tiên giả lập các Hệ Điều hành (hầu hết là Linux), sau đó các hãng phần mềm như Nginx , Oracle, ... mới sử dụng những Image gốc này để tạo ra những Image của riêng hãng để chưa những phần mềm thương mại - ví dụ như Nginx Web Server, Hệ quản trj Cơ Sở Dữ Liệu MySQL, JDK 10, JDK 12  ... Do đó không phải tất cả các phần mềm đều có thể đưa vào Docker (dockerization) được.

Như hình trên là ví dụ cho Docker Image của Hệ Điều hành Ubuntu 15.04 từ website của hãng Docker, layer bên dưới cùng là layer đầu tiên khởi tạo nên phiên bản đầu tiên Image, tiếp đó các bản cập nhật được xếp lên trên cùng. Do đó các Image được tận dụng lại (reuse) một cách tối ưu cho những bản phát triển tiếp theo. Các bạn có thể thấy tầng trên cùng có dung lượng là 0 là bởi vì tầng này chỉ đơn thuần đổi lại tên của Image mà không thêm logic nào.

Các bạn có thể tra cứu những Image cần sử dụng trên trang Hub của Docker 

 

2.2 Các thành phần của Dockerfile

Chúng ta hãy nhìn một  Dockerfile ví dụ đơn giản như sau.

FROM nginx:1.21
ENTRYPOINT ["nginx -s reload"]
EXPOSE 80

Dockerfile được cấu thành từ nhiều dòng lệnh (line), mỗi dòng lệnh có một từ khóa và các thông số đi kèm, ví dụ: từ khoá FROM và thông số nginx:1.21

- Dockerfile đều bắt đầu từ khoá FROM, chỉ định Dockerfile của chúng ta sẽ sử dụng Image gốc nào.

- ENTRYPOINT: khởi chạy Nginx service với command "nginx -s reload"

- EXPOSE: mở port 80 trong Container

Ví dụ trên chỉ sử dụng những cú pháp đơn giản nhất của Dockerfile, Docker còn hỗ trợ nhiều cú pháp nâng cao và phức tạp hơn để đáp ứng những nhu cầu sử dụng thưc tế của lập trinh viên. Trong các bài viết sau chúng ta sẽ được hướng dẫn về cách setup các project Java từ đơn giản (màn hình console) cho đến phức tạp (Tomcat + JSP và CSDL MySQL). 

Các bạn có thể tham khảo về các cú pháp được sử dụng trong Dockerfile tại trang tài liệu chính thức của hãng Docker ở đây .

 

2.3. Tạo Docker Image từ Dockerfile:

Sau khi hoàn thành file Dockerfile chúng ta có thể tạo ra các Docker Image bằng cú pháp:

Docker hỗ trợ command "docker build" với rất nhiều options mà trong giới hạn bài viết không giới thiệu được hết đến các bạn, do vậy chúng ta sẽ đi vào một ví dụ đơn giản được sử dụng trong thực tế - tạo bước đầu cho các bạn mới tiếp xúc với Docker. Chúng ta đi đến command sau:

docker build -t <name> <directory-path> [OPTIONS]

Command này sẽ tìm đến file Dockerfile trong directory </directory/path>, option -t (hoặc --tag) định nghĩa tên Image sẽ được đăng ký vào Registry của Docker Engine

Một số OPTIONS hay được dùng:

--file (hoặc -f):

Khi sử dụng option -f, Docker sẽ tìm đến file chỉ định mà không sử dụng file mặc định <directory-path>/Dockerfile

--no-cache:

Docker sử dụng cơ chế Caching để cache lại những build step sau khi đã thực hiện qua 1 lần, nhằm để tiết kiệm thời gian cho những lần build tiếp theo với cùng 1 thao tác. --no-cache chỉ định rằng chúng ta sẽ không sử dụng cache khi build mà làm mọi thứ giống như lần build đầu tiên.

 

* Sử dụng nhiều Tag (-t) với cùng một file Dockerfile

docker build -t my/fedora-jboss:latest -t my/fedora-jboss:v2.1 .

Command trên hay được sử dụng khi chúng ta cần phát hành một phiên bản mới nhất của Hệ Điều hành, khi đó Image này cùng lúc có phiên bản latest và phiên bản số cụ thể nhằm mục đích phân biệt với 

 

* Build file Dockerfile trên Git Repository:

Ngoài sử dụng file Dockerfile trên máy tính, command  "docker build" hỗ trợ build file trên một Git Repository. Command này đầu tiên clone GitHub repo về máy tính và tìm file Dockerfile trong đường dẫn mặc định

docker build github.com/creack/docker-firefox

 Command trên sẽ sử dụng file Dockerfile ngay trong đường dẫn đó.

 

2.4. Quản lý Docker Image trên máy tính:

Như đã định nghĩa ở trên, Docker Image là những registry được tạo ra bên trong Docker Engine được cài đăt trên máy tính - không phải được tạo ra dưới dạng file lưu trên đĩa cứng - nghĩa là chúng ta chỉ có thể truy xuất và sử dụng Docker Image thông qua command "docker image " của Docker API. Tuy nhiên chúng ta vẫn có thể "đóng gói" Docker Image thành file zip để lưu trữ lại, chi tiết sẽ được hướng dẫn cụ thể trong bài viết sau về các thao tác với Container

Liệt kê các Image đang có trên máy tính:

docker image ls 

Output của command trên tương tự như sau:

Cấu tạo thành phần của một Docker Image: <repository-name>:<tag>. Trong đó, <repository-name> là tên Repository - ví dụ như debian với ubuntu, và <tag> là một phiên bản trên Repository đó, ví như repository Ubuntu có các tag khác nhau như: 14.04, 20.04, đặc biệt "latest"  là từ khoá để chỉ phiên bản mới nhất của Repository đó.

Như ví dụ trên - Docker cho thấy 2 Image Debinan và Ubuntu đang có trên máy tính. Ngoài ra khi số lượng Docker Image tăng lên nhiều trong quá trình sử dụng, Docker API hỗ trợ các cú pháp hỗ trợ tìm kiếm Image như sau:

reference” : tìm kiếm Images theo tên (Repository name) và phiên bản (tag).

-- co the dung --filter
docker images --filter "<key>=<value>"

-- hoac dung -f
docker images -f "<key>=<value>"

 

docker images --filter "reference=deb*"

 

label” : tìm kiếm Image theo các Label - với điều kiện khi tạo ra các Image chúng ta phải đặt các Label trước. Cú pháp tạo Label sẽ được đề cập chi tiết sau.

docker images --filter "label=dev"

 

dangling” : tìm kiếm những Image đang không được sử dụng - tức là không có bất kỳ Container nào sử dụng Image đó.

docker images --filter "dangling=true"

 

before” & “since” :  Tìm kiếm những Image được tạo trước và sau thời điểm một Image xác định được tạo.

 

Ngoải ra, command "docker image ls" cũng hỗ trợ tìm kiếm với wildcard, ví dụ:

docker images --filter=reference='busy*:*libc'

Ví dụ trên nghĩa là chúng ta đang tìm kiếm những Image có Repository name là "busy" và có tag kết thúc bằng "libc"

 

3. Tạo Container từ Image

Container là kết quả sau cùng của quá trình từ khi chúng ta tạo các Dockerfile, tạo Image từ Dockerfile và cuối cùng là Container.

Trong ví dụ của bài viết trước , chúng ta đã thực hiện câu lệnh "docker run hello-world" để tạo một Container đơn giản in ra dòng text "Hello World" ra màn hình console. Tương tự, chúng ta sẽ tạo Container được tạo ra từ các file Dockerfile bằng command "docker run":

docker run [OPTIONS]  <name>:<tag> 

Lưu ý rằng command "docker run" luôn phải kết thúc bằng tên của Image và phiên bản của Image, các options thì phải được đặt trước đó. Sau đây là một số options hay dùng cho việc tạo Container:

-d:  Container được tạo ra sẽ được chạy dưới dạng background. Nếu không có option -d, màn hình console sẽ được gắn (attach) vào process của Container và khi chúng ta bấm tổ hợp Ctrl + C, process Container sẽ kết thúc. Container ngưng hoạt động nhưng vẫn tồn tại bên trong Docker Engine cho đến khi được huỷ bằng command "docker rm <container-id>". Các command thao tác với Container sẽ được đề cập trong bài viết sau.

--rm : Thường dùng với mục đích thử nghiệm, Container sau khi kết thúc process bằng tổ hợp phím Ctrl + C thì Container cũng bị stop and remove khỏi Docker Engine. Trong bài viết sau, chúng ta sẽ được hướng dẫn về cách stop và remove một Container bằng command.

--name: đặt tên cho Container. Khi một Container được tạo ra Docker Engine sẽ gán cho mỗi Container một text định danh là một chuỗi bao gồm chữ và số, và một friendly name là một cái tên bằng Tiếng Anh có ý nghĩa, dễ đọc, dễ nhớ. Khi sử dụng option --name , chúng ta sẽ đặt lại friendly name này theo ý mình.

-p (--port): liên thông port từ máy tính localhost với port của Container. Trong ví dụ ở bài viết trước, chúng ta đã thực hiện liên thông (mapping) port 80 của máy tính localhost với port 80 của Container Nginx.

....

Ngoài ra Docker còn hỗ trợ rất nhiều options khác mà trong giới hạn bài viết không giới thiệu được hết với các bạn

Chúng ta sẽ đến với một ví dụ đơn giản chạy một Container Nginx sử dụng các options như sau:

docker run -d --name autocode_nginx  --port 80:80 nginx:latest 

Đến đây chúng ta đã hoàn tất các bước quá trình từ việc tạo file Dockerfile - tạo Docker Image từ Dockerfile - và tạo Container từ Docker Image, ở mức độ cơ bản.

Trong bài viết sau, chúng ta sẽ đến với những command thao tác với các Container - như tạo - huỷ - copy file - tương tác shell command với Container.

 

Chúc các bạn thành công.

AutoCode.VN

 

minhnhatict@gmail.com Docker