Sử dụng Dockerfile để tự động tạo các image trong Docker
Cách viết các chỉ thị trong Dockerfile như RUN, FROM, CMD ... để thi hành các tác vụ tự động tạo ra image Docker. 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ó.
docker build -t nameimage:version --force-rm -f Dockerfile .
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.
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.
Tạo Dockerfile đơn giản đầu tiên
# 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"]
Quy tắc viết chỉ thị Dockerfile
# -- Ghi chú chỉ thị
TÊN_CHỈ_THỊ các_tham_số
# -- 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 -y
Thực hiện build một Image từ Dockerfile
# -- Sử dụng Dockerfile ở trên build ra image, 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 chạy lệnh, 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.
# -- Kiểm tra danh sách image.
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 prune
Tạo và chạy một container từ Image mới tạo
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.
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.
Các chỉ thị Dockerfile
| Command | Description |
|---|---|
| FROM | Mọi Docker file đều có chỉ thị này, chỉ định image cơ sở |
| COPY và ADD | Sao chép dữ liệu |
| ENV | Thiết lập biến môi trường |
| RUN | Chạy các lệnh |
| VOLUME | Gắn ổ đĩa, thư mục |
| USER | User |
| WORKDIR | Thư mục làm việc |
| EXPOSE | Thiết lập cổng |
FROM
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
# -- Được dùng để thêm thư mục, file vào Image
ADD thư_mục_nguồn thư_mục_đích
# -- thư_mục_nguồn => là thư mục máy host chạy Docker
# -- thư_mục_đích => là nơi dữ liệu được thêm vào ở máy container
EVN
# -- 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
# -- 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
# -- Chỉ thi tạo một ổ đĩa chia sẻ được giữa các container.
VOLUME /dir_vol
USER
# Bạn thêm user được dùng khi chạy các lệnh ở chỉ thị RUN CMD WORKDIR.
USER private
WORKDIR
# -- 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
# -- Để 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
# -- 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"]
Giảm số lượng Layer hình thành trê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 (
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
.......
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, có một mẹo nhỏ có thể gộp các lớp cha của vào thành một.
Cố gắng xây dựng Image có ít layer nhất
# -- Xem lịch sử hình thành image i-firstserver:version1
docker history i-firstserver:version1
#-----
IMAGE CREATED CREATED BY SIZE
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
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 image 9f38484d220f
- Tiếp theo chạy lệnh
yum update -ycập nhật các package, xong lưu thành image với id ac7b46806e10 - 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).
# -- 1 dòng chỉ thị RUN
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
# -- 2 dòng
ENTRYPOINT ["/usr/sbin/httpd"]
CMD ["-D", "FOREGROUND"]
# -- Thành 1 dòng
ENTRYPOINT ["/usr/sbin/httpd", "-D", "FOREGROUND"]
Cuối cùng file Dockerfile ở 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. Hoặc ngay từ đầu bạn nên nhảy vào container cài đặt hết mọi thứ cần thiết rồi xuất ra file Image mới dùng riêng.