Ở các phần trước ta đã sử dụng các lệnh Docker tương tác trực tiếp hết lệnh này đến lệnh khác để lấy image về, tạo container, chạy và cài đặt các thành phần vào container ... Rất nhiều thao tác trong quá trình này bạn có thể lưu vào một file gọi là Dockerfile
, và ra lệnh cho Docker đọc file đó, chạy từng lệnh theo chỉ thị trong file đó để cuối cùng có được image theo nhu cầu.
Sử dụng Dockerfile
Dockerfile là một file text, trong đó chứa các dòng chỉ thị để Docker đọc và chạy theo chỉ thị đó để cuối cùng bạn có một image mới theo nhu cầu. Khi đang có một Dockerfile giả sử có tên là Dockerfile
để ra lệnh cho Docker chạy nó bạn có thể gõ:
docker build -t nameimage:version --force-rm -f Dockerfile .
Bạn chú ý dấu .
ở cuối lệnh docker build
ở trên, có nghĩa tìm file có tên Dockerfile
ở thư mục hiện tại.
-t nameimage:version
là đặt tên và tag được gán cho image mới tạo ra.
Bạn có thể dùng Visual Studio Code
có cài thêm Extension Docker for Visual Studio Code
để khi soạn thảo file có tên Dockerfile
nó gợi ý và highlight cú pháp cho bạn.
Tạo Dockerfile đơn gian đầu tiên
Dockerfile là file text, bạn dùng bất kỳ trình soạn thảo text nào tạo ra file này, và đưa vào nội dung là các chỉ thị. Giờ ta sẽ vừa thực hành vừa học từng bước. Ví dụ tạo file có tên Dockerfile
nhập nội dung sau:
# xây dựng image mới từ image centos:latest (CENTOS 7) FROM centos:latest # Thêm hai lệnh sau nếu CENTOS 8 không cập nhật được # RUN dnf -y --disablerepo '*' --enablerepo=extras swap centos-linux-repos centos-stream-repos # RUN dnf -y distro-sync # Cập nhật các gói và cài vào đó HTTPD, HTOP, VIM RUN yum update -y RUN yum install httpd httpd-tools -y RUN yum install epel-release -y \ && yum update -y \ && yum install htop -y \ && yum install vim -y #Thiết lập thư mục hiện tại WORKDIR /var/www/html # Copy tất cả các file trong thư mục hiện tại (.) vào WORKDIR ADD . /var/www/html #Thiết lập khi tạo container từ image sẽ mở cổng 80 # ở mạng mà container nối vào EXPOSE 80 # Khi chạy container tự động chạy ngay httpd ENTRYPOINT ["/usr/sbin/httpd"] #chạy terminate CMD ["-D", "FOREGROUND"]
Do RED HAT công bố CentOS Stream, bản CentOS 8 bị kết thúc vòng đời vào cuối năm 2021, nên sau thời điểm đó khi cập nhật với lệnh yum update có dẫn tới lỗi AppStream. Để khắc phục, bạn có thể chuyển thành CentOS Stream 8 bằng lệnh:
dnf -y --disablerepo '*' --enablerepo=extras swap centos-linux-repos centos-stream-repos dnf -y distro-sync
Cùng thư mục với Dockerfile, bạn cũng tạo thêm một file có tên test.html
để làm dữ liệu kiệm tra, nội dung của nó đơn giản là:
<!DOCTYPE html> <html> <body> <h1>HELLO WORLD!</h1> </body> </html>
File trên chính là các chỉ thị, để Docker căn cứ vào đó mà thực hiện từng bước một. Bạn có nhìn thấy các chỉ thị như FROM
, RUN
, ADD
... Các chỉ thị cụ thể sẽ giải thích phần sau.
Ở đây bạn chú ý khi viết các chỉ thị trong Dockerfile thì một chỉ thị có thể viết theo cấu trúc:
# Ghi chú chỉ thị TÊN_CHỈ_THỊ các_tham_số
Ví dụ, chỉ thị RUN
là chạy một lệnh, muốn chạy lệnh cập nhật của CentOS yum update -y
thì viết trong Dockerfile
RUN yum update -yThực hiện build một image từ Dockerfile
Hiện giờ đang có Dockerfile với tên Dockerfile
ở trên, Dockerfile này căn cứ theo các chỉ thị của nó, nó sẽ: xây dựng một image chứa CentOS
, cài vào đó Apache HTTPD
, HTOP
, VIM
, copy các file ở thư mục hiện tại vào /home/code
, khi container tạo ra từ Image mới này thì tự động chạy /usr/sbin/http
(máy chủ web) và bash
đồng thời mở cổng 80
trên network container nối vào.
Giờ sử dụng file này build ra image xem, image mới sẽ đặt tên là i-firstserver:version1
, gõ lệnh sau:
docker build -t i-firstserver:version1 -f Dockerfile .
Sau khi gõ lệnh này, Docker bắt đầu đọc Dockerfile và thực hiện từng bước của chị thị. Nó sẽ tạo container tạm, đưa vào đó các gói, dữ liệu, cấu hình ... theo chỉ thị, mỗi bước này tạo ra một lớp image. Cuối cùng nó tạo ra một image mới có tên và tag do bạn chỉ ra ở trên, lưu trong hệ thống Docker của bạn!.
Build xong, kiểm tra danh sách image sẽ thấy tên này.
docker images -a REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> cf6721d88752 5 minutes ago 588MB i-firstserver version1 740cbb2e87ac 5 minutes ago 588MB <none> <none> 3661794c0ee8 5 minutes ago 588MB <none> <none> 2027afe1b677 5 minutes ago 588MB <none> <none> 59328245bd43 5 minutes ago 588MB
Lưu ý: trong quá trình Docker build image mới từ Dockerfile, nó có thể tạo ra các image tạm thời gây rác hệ thống. Để xóa các image tạm này hãy dùng lệnh:
docker image pruneTạo - chạy một container từ image mới
Image mới có tên i-fitserver:version1
đã được buid ra, giờ bạn có thể tạo container từ nó như bất kỳ image nào khác. Ví dụ:
docker run -it --name mywebserver -p 8888:80 -h firstserver i-firstserver:version1
Lệnh trên tạo ra một container có tên mywebserver
từ image i-firstserver:version1
, khi container chạy nó ánh xạ cổng 8888
vào cổng 80
của container (cổng HTTP đang chạy lắng nghe). Thử kiểm tra bằng gõ vào trình duyệt http://localhost:8888
.
Container đã chạy thành công, điều đó chứng tỏ bạn đã có một image có sẵn CentOS
và Apache HTTPD
. Bạn cũng gõ http://localhost:8888/test.html
để xem dữ liệu được copy vào có thành công!
Các chỉ thị Dockerfile
Phần này tìm hiểu các chỉ thị cơ bản:
FROM
: mọi Docker file đều có chỉ thị này, chỉ định image cơ sởCOPY
ADD
: sao chép dữ liệuENV
: thiết lập biến môi trườngRUN
: chạy các lệnh.VOLUME
: gắn ổ đĩa, thư mụcUSER
: userWORKDIR
: thư mục làm việcEXPOSE
: thiết lập cổng
FROM Trong Dockerfile
Như trên đã nói, chỉ thị này chỉ ra image cơ sở để xây dựng nên image mới. Để xây dựng từ image nào đó thì bạn cần đọc document của Image đó để biết trong đó đang chứa gì, có thể chạy các lệnh gì trong đó ... Ví dụ, nếu bạn chọn xây dựng từ image centos:laste
thì bạn bắt đầu bằng hệ điều hành CentOS và bạn có thể cài đặt, cập nhật các gói với yum
, ngược lại nếu bạn chọn ubuntu:latest
thì trình quản lý gói của nó là APT
...
COPY và ADD Trong Dockerfile
Được dùng để thêm thư mục, file vào Image. Cú pháp viết đó là:
ADD thư_mục_nguồn thư_mục_đích
Trong đó thư_mục_nguồn
là thư mục ở máy chạy Dockerfile, chứa dữ liệu cần thêm vào. thư_mục_đích
là nơi dữ liệu được thêm vào ở container.
ENV Trong Dockerfile
Chỉ thị này dùng để thiết lập biến môi trường, như biến môi trường PATH
..., tùy hệ thống hay ứng dụng yêu cầu biến môi trường nào thì căn cứ vào đó để thiết lập.
ENV biến giá_trị
RUN Trong Dockerfile
Thi hành các lệnh, tương tự bạn chạy lệnh shell trên OS từ terminal.
RUN lệnh-và-tham-số-cần-chạy
RUN ["lệnh", "tham số1", "tham số 2" ...]
VOLUME Trong Dockerfile
Chỉ thi tạo một ổ đĩa chia sẻ được giữa các container.
VOLUME /dir_vol
Xem thêm Chia sẻ dữ liệu giữa các Container
USER Trong Dockerfile
Bạn thêm user được dùng khi chạy các lệnh ở chỉ thị RUN
CMD
WORKDIR
.
USER private
WORKDIR Trong Dockerfile
Thiết lập thư mục làm việc hiện tại chi các chỉ thị CMD
, ENTRYPOINT
, ADD
thi hành.
WORKDIR path_current_dir
EXPOSE Trong Dockerfile
Để thiết lập cổng mà container lắng nghe, cho phép các container khác trên cùng mạng liên lạc qua cổng này hoặc đỉ ánh xạ cổng host vào cổng này.
EXPOSE port
ENTRYPOINT, CMD Trong Dockerfile
Chạy lệnh trong chỉ thị này khi container được chạy.
ENTRYPOINT commnad_script
ENTRYPOINT ["command", "tham-số", ...]
CMD
ý nghĩa tương tự như ENTRYPOINT
, khác là lệnh chạy bằng shell của container.
CMD command param1 param2
Chú ý ở dạng sau của CMD thì nó lại là thiết lập tham số cho ENTRYPOINT
CMD ["tham-số1", "tham-số2"]
Đó là các chỉ thị cơ bản, đủ để bạn tự viết các Dockerfile
xây dựng ra các image chứa các thành phần theo nhu cầu của mình. Hãy quay trở lại phần
Cài đặt PHP, APACHE, MYSQL trên Docker tự thực hành tạo ra các Dockerfile với các image: image PHP-FPM, image Apache, image MySQL.
Giảm số lượng Layer hình thành nên Image
Quay trở lại ví dụ tạo image i-firstserver:version1
ở trên, khi bạn có được Image này thì trong hệ thống cũng tồn tại thêm một số image không có tên, không tag. Hãy gõ lệnh xem sách sách image, sẽ thấy:
docker images -a
REPOSITORY TAG IMAGE ID CREATED SIZE
i-firstserver version1 6a964f7f5321 About an hour ago 588MB
<noned> <none> 6a655bf3192b About an hour ago 588MB
<none> <none> bb535a125b19 About an hour ago 588MB
<none> <none> e43cbe953b7d About an hour ago 588MB
<none> <none> 5f8bda4bcb01 About an hour ago 588MB
<none> <none> 6d8ae47da227 About an hour ago 588MB
<none> <none> bc535a902e02 About an hour ago 411MB
<none> <none> ac7b46806e10 About an hour ago 296MB
debian latest 2d337f242f07 40 hours ago 101MB
xtl_tool latest 4c7b23777fc7 3 days ago 349MB
centos latest 9f38484d220f 13 days ago 202MB
php 7.3-fpm 9ef96f997360 2 weeks ago 367MB
httpd latest 2d1e5208483c 3 weeks ago 132MB
mysql latest 91dadee7afee 3 weeks ago 477MB
busybox latest d8233ab899d4 5 weeks ago 1.2MB
Như đã thấy, để có image cuối cùng thì Docker cũng đã sinh ra tới 7 image khác, image đầu tiên ac7b46806e10
được kế thừa bới bc535a902e02
cứ như vậy đến cho đến image cuối i-firstserver
. Do tính kế thừa, như vậy nên các image cha không thể xóa được. Tuy nhiên một mẹo nhỏ có thể gộp các lớp cha của vào thành một ở phần sau.
Cố gắng xây dựng Image có ít layer nhất
Gõ lệnh xem lịch sử hình thành image i-firstserver:version1
:
IMAGE CREATED CREATED BY SIZE COMMENT 6a964f7f5321 About an hour ago /bin/sh -c #(nop) CMD ["-D" "FOREGROUND"] 0B e43cbe953b7d About an hour ago /bin/sh -c #(nop) ENTRYPOINT ["/usr/sbin/ht… 0B bb535a125b19 About an hour ago /bin/sh -c #(nop) EXPOSE 80 0B 6a655bf3192b About an hour ago /bin/sh -c #(nop) ADD dir:519c5971b42e7e73b1… 1.49kB 5f8bda4bcb01 About an hour ago /bin/sh -c #(nop) WORKDIR /var/www/html 0B 6d8ae47da227 About an hour ago /bin/sh -c yum install epel-release -y &… 177MB bc535a902e02 About an hour ago /bin/sh -c yum install httpd httpd-tools -y 116MB ac7b46806e10 About an hour ago /bin/sh -c yum update -y 94MB 9f38484d220f 13 days ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B <missing> 13 days ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B <missing> 13 days ago /bin/sh -c #(nop) ADD file:074f2c974463ab38c… 202MB
Hãy nhìn từ dưới lên trên, đó là quá trình hình thành nên Image khi bạn build từ Docker file:
- Đầu tiên nó tải
centos:latest
về và chạy nó, lưu thành image9f38484d220f
- Tiếp theo chạy lệnh
yum update -y
cập nhật các package, xong lưu thành image với idac7b46806e10
- Cứ như vậy, sau các chỉ thị trong Dockerfile thì một Image lại được lưu lại cho đến Image cuối cùng có tên bạn tạo!
Từ đó bạn nhận thấy: Trong Dockerfile có bao nhiêu chỉ thị RUN
thì có bấy nhiêu layer được tạo ra, tương tự là ADD
, ENTRYPOINT
, CMD
... Nên muốn ít layer thì cần viết sao cho ít chỉ thị nhất. Ở ví dụ trên thay vì có 3 chỉ thị RUN
có thể viết thành 1 như vậy 3 layer chỉ còn 1. WORKDIR
chưa dùng đến bỏ đi (giảm 1 layer). Tham số ENTRYPOINT
có thể viết gộp cùng lệnh này, thay vì phải dùng thêm CMD
(giảm 1 layer).
RUN yum update -y \ && yum install httpd httpd-tools -y \ && yum install epel-release -y \ && yum update -y \ && yum install htop -y \ && yum install vim -y ENTRYPOINT ["/usr/sbin/httpd", "-D", "FOREGROUND"]
Cuối cùng file Dockerile ở trên vẫn cùng kết quả nhưng sinh ra ít layer sẽ như sau:
FROM centos:latest RUN yum update -y \ && yum install httpd httpd-tools -y \ && yum install epel-release -y \ && yum update -y \ && yum install htop -y \ && yum install vim -y ADD . /var/www/html EXPOSE 80 ENTRYPOINT ["/usr/sbin/httpd", "-D", "FOREGROUND"]
Bạn hãy xóa container mywebserver
, image i-fitserver:version1
rồi chạy lại Dockerfile thực hiện lại quy trình tạo Image, Container như trên, kết quả số layer sinh ra chỉ còn 3 thay vì 7.
Dù vậy, vẫn còn 3 Image không tên, không tag nếu vẫn muốn loại bỏ thì bạn có thể xuất image cuối ra file, rồi xóa image này đi. Sau đó nạp image lại từ file. Xem phần Lưu và Nạp Image từ file