Manifest
KHOÁ DOCKERTỜ 03 / 34CHƯƠNG 01SỬA ĐỔI C
Tờ 03 · Chương 01Nhập môn

docker runBạn gõ một dòng, và mười hai việc xảy ra sau lưng bạn

Năm giây sau khi nhấn Enter, trình duyệt hiện trang chào của nginx. Cảm giác là xong rồi. Tờ này đi ngược lại dòng lệnh đó — kéo một gói tin qua sáu chặng, hạ sáu tấm kính namespace, và đối chiếu số hiệu thật của container với số hiệu của máy chủ.

Thời lượng20 phút
Bản vẽ05 hình
Trình độNhập môn
Truy cậpMiễn phí
Máy chủ · ngoài đường0.0.0.0:8080mọi địa chỉ của máy này, gồm cả IP công cộng-p 8080:80Máy chủMạng của Docker · 172.17.0.0/16Container 9718e1e039ec · số căn hộ172.17.0.2:80PID 1 nginx: master process6 namespace riêng · time và user dùng chung với máy chủĐọc từ ngoài vào trong — -p <cổng máy chủ>:<cổng container>
01Hiện trường

Một dòng lệnh, mười hai việc bạn không nhìn thấy

Bạn gõ đúng một dòng, đợi khoảng năm giây, mở trình duyệt và thấy trang chào của nginx. Cảm giác là "xong rồi". Thực tế là mười hai việc vừa xảy ra và bạn mới nhìn thấy đúng một trong số đó.

bash · toàn bộ những gì màn hình cho bạn xem
$ docker run -d --name web -p 8080:80 nginx:1.29-alpine
Unable to find image 'nginx:1.29-alpine' locally
1.29-alpine: Pulling from library/nginx
612c0c1df4c5: Pull complete
583599bb7d38: Pull complete
aee4e54b3865: Pull complete
82736a35d0e7: Pull complete
4a8b0b2a5b19: Pull complete
781ff50d2644: Pull complete
453da7dbc73e: Pull complete
6a0ac1617861: Pull complete
e8fc446e336c: Download complete
6192e1e6a438: Download complete
Digest: sha256:5616878291a2eed594aee8db4dade5878cf7edcb475e59193904b198d9b830de
Status: Downloaded newer image for nginx:1.29-alpine
9718e1e039ec8b1837ff4df1ac32b126ab814a2cd990ce2eec229deccf7d16e9

Chuỗi 64 ký tự cuối cùng là ID đầy đủ của container. Mọi lệnh sau này bạn chỉ cần 12 ký tự đầu, hoặc cái tên web. Tờ này đi ngược từ dòng lệnh đó, mổ từng mảnh một.

02Giải phẫu

Bốn mảnh của một lệnh, bốn hệ quả khác nhau

Lệnh trên có bốn phần tuỳ chọn và một phần bắt buộc. Mỗi phần đụng vào một tầng khác nhau của hệ thống — và đây là lý do người mới hay sửa nhầm chỗ khi gặp lỗi.

HÌNH 01
Bốn mảnh của một lệnh, bốn tầng bị đụng tới
Bước 1/6

Mảnh docker. Gọi chương trình client. Nó chưa làm gì với container cả. Tầng bị ảnh hưởng: CLI.

Lệnh bạn vừa gõTầng bị ảnh hưởngdockerrun-d--name web-p 8080:80nginx:1.29-alpineCLIDocker APIcontainerdsnapshotnhân · namespacenhân · netfilter
Bỏ đi thìKhông có lệnh nào chạy.
Kiểm bằng lệnhwhich docker

Điểm dễ bỏ qua nhất là -d. Nó không có nghĩa "chạy nền cho gọn". Nó quyết định terminal của bạn có bị gắn vào tiến trình chính hay không — và kéo theo chuyện điều gì xảy ra khi bạn nhấn Ctrl+C.

MảnhĐụng vàoBỏ đi thì
-dluồng vào ra của tiến trìnhterminal bị gắn vào nginx, Ctrl+C dừng container
--name websổ tên của daemonDocker tự đặt tên kiểu serene_khorana
-p 8080:80bảng chuyển tiếp gói tin của nhâncontainer chạy nhưng không ai ngoài máy chủ chạm tới được
nginx:1.29-alpinekho imagekhông có mặc định — đây là phần bắt buộc
03Ẩn dụ

Số nhà ngoài đường và số căn hộ bên trong

Hiểu nôm na

Cổng container là số căn hộ trong một toà chung cư

Toà chung cư hai mươi tầng. Bên trong, các căn đánh số theo hệ riêng của toà: A-0801, A-0802. Ngoài đường thì cả toà chỉ có một số nhà. Người giao hàng tới số nhà đó, đọc bảng chỉ dẫn ở sảnh, mới biết leo lên căn nào. Không có dòng chỉ dẫn ấy thì họ đứng ngoài — dù trong căn vẫn có người ở nhà.

Ở toà chung cưTrên máy bạn
Số nhà ngoài đườngCổng 8080 trên máy chủ
Số căn hộ bên trongCổng 80 bên trong container
Dòng dán trên bảng chỉ dẫn ở sảnhTham số -p 8080:80
Hộp thư riêng của căn hộNetwork namespace riêng, IP 172.17.0.2
Danh sách người ở riêng từng cănPID namespace riêng — nginx là tiến trình số 1
Tủ đồ riêng, không nhìn được sang nhà bênMount namespace riêng
Móng, khung nhà, hệ điện nước dùng chungNhân Linux của máy chủ
Ẩn dụ này sai ở chỗ

Ba chỗ, và chỗ thứ nhất là chỗ mất tiền thật.

Một — bảng chỉ dẫn ở sảnh có bảo vệ đứng cạnh. -p 8080:80 thì không. Nó ghi thẳng một luật chuyển tiếp vào bảng NAT của nhân, và luật đó nằm trước chỗ ufw kiểm. Bạn bật ufw deny 8080 mà cổng vẫn mở cho cả Internet. Mặc định -p 8080:80 mở ra 0.0.0.0, không phải mở cho riêng máy bạn.

Hai — căn hộ khoá cửa đi vắng vẫn là căn hộ, đồ đạc vẫn nằm đó, người vẫn về được. Container stop thì không còn ai bên trong — tiến trình bị giết thật, chỉ còn lớp ghi nằm trên đĩa. Không có trạng thái "container đang ngủ", chỉ có "có tiến trình" hoặc "không có tiến trình".

Ba — ở chung cư bạn sơn tường thì tường giữ màu đó. Trong container, mọi thứ bạn sửa bằng docker exec nằm ở lớp ghi và bay sạch khi tạo lại container. Ẩn dụ nhà ở đánh lừa mạnh nhất đúng ở điểm này: nó gợi cảm giác thường trú, còn container thì được thiết kế để vứt đi.

04Bản đồ

Request đi qua năm chặng trước khi tới nginx

Mở http://localhost:8080 trên trình duyệt. Gói tin không đi thẳng vào nginx. Nó qua năm chặng, và biết năm chặng đó là biết chỗ để soi khi hỏng.

HÌNH 02
Request đi qua sáu chặng trước khi tới nginx
Chặng 1/6

Chặng 1 trên sáu: trình duyệt. Trình duyệt mở kết nối TCP tới cổng 8080 của chính máy này. Chưa có gì liên quan tới Docker.

Máy chủ · không gian của bạnMạng của Docker · 172.17.0.0/16CHẶNG 01trình duyệthttp://localhost:8080CHẶNG 02cổng trên máy chủ0.0.0.0:8080CHẶNG 03luật chuyển tiếp củanhânDNAT → 172.17.0.2:80CHẶNG 04cầu docker0 + cặp veth172.17.0.1CHẶNG 05eth0 trong container172.17.0.2CHẶNG 06tiến trình nginxnghe :80 · PID 1từ Internet · vào được vì 0.0.0.0Kéo gói tin dọc đường đi, hoặc bấm thẳng vào một chặng
Địa chỉ ở chặng nàyhttp://localhost:8080
Lệnh kiểm chặngcurl -sI http://localhost:8080
Đang mở-p 8080:80 mặc định mở ra 0.0.0.0. Trên một VPS, dòng đó nghĩa là cả Internet gõ được vào cổng 8080 — và ufw deny 8080 không cứu được, vì luật của Docker nằm trước chỗ ufw kiểm.
trình duyệtTrình duyệt mở kết nối TCP tới cổng 8080 của chính máy này. Chưa có gì liên quan tới Docker.

Hai chặng đầu nằm hoàn toàn trên máy chủ và không liên quan gì tới Docker. Chặng thứ ba là chỗ Docker chen vào: một luật DNAT viết bởi daemon lúc container khởi động.

bash · chặng 1 và 2 — cổng trên máy chủ
$ docker port web
80/tcp -> 0.0.0.0:8080
80/tcp -> [::]:8080

$ ss -ltn | grep 8080
LISTEN 0      4096         0.0.0.0:8080       0.0.0.0:*
LISTEN 0      4096            [::]:8080          [::]:*

0.0.0.0 nghĩa là mọi địa chỉ của máy này, gồm cả IP công cộng. Trên một VPS, dòng đó có nghĩa là cả Internet gõ được vào cổng 8080. Đọc kỹ dòng này là thói quen đáng rèn.

Trên máy chủ thật

Muốn chỉ mình bạn vào được thì viết rõ địa chỉ: -p 127.0.0.1:8080:80. Khi đó ss in ra 127.0.0.1:8080 và không còn dòng [::]. Đây nên là mặc định trong đầu bạn, còn 0.0.0.0 là ngoại lệ có chủ ý.

bash · chặng 4 và 5 — bên trong mạng của Docker
$ docker inspect -f '{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{$v.IPAddress}}{{end}}' web
bridge 172.17.0.2

$ docker exec web ip addr show eth0
2: eth0@if275: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
    link/ether 66:a9:0a:46:eb:40 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0

Ký hiệu eth0@if275 là dấu vết của một cặp giao diện ảo: eth0 bên trong container nối với giao diện số 275 bên ngoài, cắm vào cầu docker0. Cầu đó chính là cổng 172.17.0.1 — địa chỉ mà nginx ghi vào log khi bạn gọi từ máy chủ.

bash · nhìn từ phía nginx
$ docker logs web | tail -1
172.17.0.1 - - [23/Aug/2026:02:04:37 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/8.5.0" "-"

Nginx không thấy 127.0.0.1, cũng không thấy IP thật của bạn. Nó thấy cổng của cầu.

05Đo thời gian

Một giây hai trăm mili giây đó gồm những gì

Từ lúc bạn nhấn Enter (image đã có sẵn trên máy) tới lúc nginx nhận request đầu tiên là khoảng hơn một giây. Bên trong khoảng đó có tám mốc rõ ràng.

HÌNH 03
Một giây hai trăm mili giây đó gồm những gì
Mốc 1/8

Mốc 1 trên 8: dựng lời gọi API. CLI đổi lệnh của bạn thành POST /v1.52/containers/create, kèm toàn bộ tham số ở dạng JSON.

$ docker run -d --name web -p 8080:80 nginx:1.29-alpineCLI · dockerdcontainerd · runcnhân Linuxkhông còn runc nào trên máydựng lời gọi APIdockerd nhậntìm image trong kho8 lớp · 26,9 MB néndựng snapshot ghi đượcsinh shimrunc dựng rồi thoát6 namespace mớiviết luật chuyển tiếpin ID rồi trả dấu nhắcUp 2 seconds0~1,2 strục không theo tỉ lệ · chỉ ba mốc có số đo thậtCLI đổi lệnh của bạn thành POST /v1.52/containers/create, kèm toàn bộ thamsố ở dạng JSON.
1 / 8
dựng lời gọi APICLI đổi lệnh của bạn thành POST /v1.52/containers/create, kèm toàn bộ tham số ở dạng JSON.
tổng ~1,2 s

Mốc đáng chú ý nhất là mốc thứ sáu: runc gọi clone() với các cờ tạo namespace, rồi exec nginx, rồi tự thoát. Sau đó không còn runc nào trên máy — thứ ở lại là shim, đúng như Tờ 02 đã mổ xẻ.

bash · kết quả đo được ngay sau đó
$ docker ps
CONTAINER ID   IMAGE               STATUS         PORTS
9718e1e039ec   nginx:1.29-alpine   Up 2 seconds   0.0.0.0:8080->80/tcp, [::]:8080->80/tcp

$ docker stats --no-stream web
CONTAINER ID   NAME   CPU %   MEM USAGE / LIMIT     MEM %   PIDS
9718e1e039ec   web    0.00%   6.082MiB / 11.68GiB   0.05%   7
06Ranh giới

Container nhìn thấy gì, và không nhìn thấy gì

Cách ly của container không phải phép màu. Nó là sáu cơ chế của nhân Linux gọi là namespace, và bạn đếm được chúng bằng số hiệu.

HÌNH 04
Container nhìn thấy gì — sáu ô kính, sáu namespace
Kính đã hạ 0/6

Sáu ô kính đang đóng.

Sáu namespace riêng — mỗi ô một tấm kínhBấm để hạ kính xuốngpiddanh sách tiến trình$ ps -ef 4023 dockerd 41499 containerd 63273 shim 69931 nginx: master 69987 nginx: worker … 214 tiến trình khácnhìn từ máy chủ$ ps -efPID USER COMMAND 1 root nginx: master 30 nginx workernhìn từ trong containernetgiao diện mạng$ ip -br addrlo UP 127.0.0.1/8enp3s0 UP 192.168.1.24/24docker0 UP 172.17.0.1/16veth9a1 UPveth2f7 UPnhìn từ máy chủ$ ip -br addrlo UP 127.0.0.1/8eth0 UP 172.17.0.2/16nhìn từ trong containermntcây hệ thống tệp$ ls /bin boot etc homeusr var srv opt/var/lib/docker/overlay2/ l/ 3f9c…/ 8ad1…/nhìn từ máy chủ$ ls /bin etc usrvar tmp procdocker-entrypoint.dnhìn từ trong containerutstên máy$ hostnamedsecopsnhìn từ máy chủ$ hostname9718e1e039ecnhìn từ trong containeripcbộ nhớ chia sẻ$ ipcs -mkey shmid bytes0x000000 32769 5242880x000000 65538 4194304nhìn từ máy chủ$ ipcs -mkey shmid bytes(trống)nhìn từ trong containercgroupvị trí trong cây cgroup$ cat /proc/self/cgroup0::/system.slice/ docker-9718e1e039ec… .scopenhìn từ máy chủ$ cat /proc/self/cgroup0::/nhìn từ trong container
NamespaceTrong containerMáy chủ≠ / =
cgroup40265326774026531835
ipc40265326754026531839
mnt40265326734026531841
net40265326784026531840
pid40265326764026531836
uts40265326744026531838
time40265318344026531834=
user40265318374026531837=
Hai hàng cuốitimeuser trùng khít. Container dùng chung đồng hồ hệ thống và chung bảng định danh người dùng với máy chủ.
Cách dùngMỗi ô đang hiện cảnh nhìn từ TRONG container. Bấm một ô để hạ tấm kính xuống và thấy cùng chỗ đó nhìn từ máy chủ.
đang nhìn từ trong container
bash · đếm bằng số hiệu, không đoán
$ docker exec web ls -l /proc/1/ns
cgroup -> cgroup:[4026532677]
ipc    -> ipc:[4026532675]
mnt    -> mnt:[4026532673]
net    -> net:[4026532678]
pid    -> pid:[4026532676]
time   -> time:[4026531834]
user   -> user:[4026531837]
uts    -> uts:[4026532674]

$ readlink /proc/self/ns/{time,user}
time:[4026531834]
user:[4026531837]
root trong container là root thật

user trùng nghĩa là root bên trong container chính là root của máy chủ, chỉ bị giới hạn bằng capability và seccomp. Đây là lý do gắn -v /:/host rồi chroot là con đường leo quyền, và là lý do chế độ rootless tồn tại. Docker mặc định không bật user namespace riêng.

bash · hệ quả nhìn thấy được của PID namespace
$ docker exec web ps -ef | head -3
PID   USER     TIME  COMMAND
    1 root      0:00 nginx: master process nginx -g daemon off;
   30 nginx     0:00 nginx: worker process

Bên trong, nginx là tiến trình số 1. Bên ngoài, cùng tiến trình đó mang một số PID lớn của máy chủ. Cùng một tiến trình, hai cái tên, tuỳ bạn đứng ở đâu mà nhìn.

07Lớp ghi

Mọi thứ bạn sửa đều nằm ở một chỗ

Image là chỉ đọc. Mọi thay đổi trong lúc container chạy rơi vào một lớp ghi riêng nằm trên cùng, và docker diff cho bạn xem đúng lớp đó.

bash · docker diff — nhật ký của lớp ghi
$ docker exec web sh -c 'echo "ghi thu" > /tmp/ghichu.txt'
$ docker diff web
C /var/cache/nginx
A /var/cache/nginx/scgi_temp
A /var/cache/nginx/client_temp
A /var/cache/nginx/proxy_temp
C /etc/nginx/conf.d/default.conf
A /run/nginx.pid
C /tmp
A /tmp/ghichu.txt

A là thêm mới, C là đã đổi, D là đã xoá. Nhìn danh sách này là biết ngay: chính nginx cũng ghi vào lớp đó ngay lúc khởi động — nó sửa default.conf để bật IPv6 và tạo mấy thư mục đệm.

bash · dừng rồi chạy lại — lớp ghi vẫn còn
$ docker stop web
web

$ docker ps -a
CONTAINER ID   STATUS                        PORTS     NAMES
9718e1e039ec   Exited (0) 1 second ago (trống)   web

$ docker start web
web

$ docker exec web cat /tmp/ghichu.txt
ghi thu

Chú ý cột PORTS trống khi container đã dừng. Luật chuyển tiếp cổng chỉ tồn tại cùng tiến trình; dừng container là cổng 8080 trên máy chủ được trả lại ngay lập tức.

08Gỡ rối

"Em mở localhost:8080 mà không lên"

Đây là câu hỏi phổ biến nhất trong tuần đầu học Docker, và nó có bốn nguyên nhân hoàn toàn khác nhau. Chẩn đoán phải đi từ ngoài vào trong, không được đoán mò.

HÌNH 05
Mở localhost:8080 mà không lên — chẩn đoán từ ngoài vào trong
Bước 1/4

Bước 1: docker ps -a — container có đang Up không?

mở localhost:8080 không lênCOKHONGCOKHONGCOKHONGCOKHONGcontainer đã Exited — lệnhchính kết thúc ngaycách sửa · xem khay dướithiếu -p, hoặc công bố nhầmcổng bên trongcách sửa · xem khay dướiứng dụng nghe sai địa chỉ —thường là 127.0.0.1 thay vì0.0.0.0cách sửa · xem khay dướicổng đã mở đúng — vấn đề nằm ngoài máy: tườnglửa nhà cung cấp, hoặc bạn gõ nhầm địa chỉcách sửa · xem khay dưới
Cách dùngBấm vào ô câu hỏi để mở output của cả hai trường hợp — bình thường và có lỗi — rồi chọn CO hoặc KHONG theo cái máy bạn thật sự in ra.
Đang kiểmChạy docker ps -a rồi chọn theo cái bạn thật sự nhìn thấy. Bấm vào ô câu hỏi để mở output của cả hai trường hợp.
ss → docker ps → logs → exec

Nhánh khó thấy nhất là nhánh thứ ba: container chạy, cổng đã công bố, nhưng công bố nhầm số cổng bên trong. Triệu chứng rất dễ đánh lừa vì docker ps trông vẫn khoẻ mạnh.

bash · trông thì ổn mà không ai trả lời
$ docker run -d --name web -p 8080:8081 nginx:1.29-alpine
a917880484a3958c0a07f60ae08af512f2758f00e30357e73…

$ docker ps
CONTAINER ID   STATUS        PORTS
a917880484a3   Up 1 second   80/tcp, 0.0.0.0:8080->8081/tcp, [::]:8080->8081/tcp

$ curl -sS http://localhost:8080
curl: (56) Recv failure: Connection reset by peer

Đọc cột PORTS cho ra toàn bộ câu chuyện: 80/tcp đứng riêng nghĩa là image có khai cổng 80 nhưng không ai công bố nó; còn 0.0.0.0:8080->8081/tcp là chuyển tiếp tới một cổng mà bên trong không có ai nghe. Sửa bằng cách đổi thành -p 8080:80.

09Bảng sửa đổi

Năm sai lầm tốn thời gian nhất khi chạy container đầu tiên

SỐSAI LẦM & CÁCH SỬA
01

Dùng -d với một lệnh kết thúc ngay rồi tưởng container "chết bất thường"

docker run -d --name thu alpine:3.22 echo "toi chay xong roi" cho ra Exited (0) ngay. Container không hỏng — nó làm xong đúng việc được giao rồi thoát với mã 0.

Cách sửaMuốn nó chạy lâu thì lệnh chính phải là thứ chạy lâu. Và luôn dùng docker ps -a chứ không phải docker ps khi thấy container "biến mất".

02

Chép docker inspect -f '{{.NetworkSettings.IPAddress}}' từ hướng dẫn cũ

Trên Docker 29, lệnh đó trả về template parsing error: … map has no entry for key "IPAddress". Trường ở tầng gốc đã bị bỏ.

Cách sửadocker inspect -f '{{range $k,$v := .NetworkSettings.Networks}}{{$k}} {{$v.IPAddress}}{{end}}' web

03

Tưởng -p 8080:80 chỉ mở cổng cho máy mình

Mặc định là mở ra 0.0.0.0 — mọi địa chỉ của máy, gồm cả IP công cộng. Nặng hơn: luật chuyển tiếp của Docker nằm trước chỗ ufw kiểm, nên ufw deny 8080 không cứu được.

Cách sửaTrên máy chủ hãy mặc định viết -p 127.0.0.1:8080:80, rồi cho một proxy phía trước lo phần ra Internet. Kiểm lại bằng ss -ltn | grep 8080.

04

Dùng localhost bên trong container để gọi container khác

Bên trong container, localhost là chính nó — vì nó có network namespace riêng. Ứng dụng gọi localhost:5432 để tìm Postgres đang chạy ở container bên cạnh sẽ không bao giờ tới nơi.

Cách sửaCho hai container vào cùng một mạng do bạn tạo, rồi gọi nhau bằng tên container. Mạng bridge mặc định không có phân giải tên; mạng bạn tự tạo thì có.

05

Sửa cấu hình bằng docker exec rồi coi như xong

Vào container sửa default.conf, thấy chạy đúng, đóng terminal. Lần tạo lại container tiếp theo, mọi thứ trở về như cũ — docker diff sẽ cho thấy chính xác những gì bạn sắp mất.

Cách sửaThay đổi phải nằm trong image, trong volume, hoặc trong tham số lúc chạy. docker exec là để quan sát, không phải để sửa.

10Kiểm tra

Kiểm tra hiểu bài

Năm câu, không giới hạn thời gian. Mỗi câu giải thích cả đáp án đúng lẫn vì sao các đáp án kia sai.

Phiếu nghiệm thu · Tờ 030 / 5 câu
01Bạn chạy docker run -d --name thu alpine:3.22 echo "toi chay xong roi". Ngay sau đó docker ps không thấy gì, còn docker ps -a hiện Exited (0). Chuyện gì đã xảy ra?Chọn 1
02Chọn tất cả khẳng định đúng về docker run -d -p 8080:80 nginx:1.29-alpine trên một VPS có IP công cộng.Chọn nhiều
03Với cấu hình mặc định của Docker, người dùng root bên trong container là một danh tính khác hẳn với root của máy chủ.Đúng / Sai
04docker ps hiện cột PORTS 80/tcp, 0.0.0.0:8080->8081/tcp, container đang Up, nhưng curl http://localhost:8080 trả về Recv failure: Connection reset by peer. Nguyên nhân là gì?Chọn 1
05Ứng dụng chạy trong container api gọi localhost:5432 để tìm Postgres đang chạy trong container db trên cùng một máy. Kết nối không bao giờ tới nơi. Chọn tất cả khẳng định đúng.Chọn nhiều
Nộp cả phiếu để chấm
Kiểm hết năm câu ở trên rồi nộp phiếu — máy chủ mới là nơi chấm điểm thật.
11Tóm tắt

Năm điều mang về

01

Container sống đúng bằng vòng đời tiến trình chính. Không có "container ngủ". Có tiến trình thì chạy, hết tiến trình thì Exited.

02

Cổng đọc từ ngoài vào trong. -p <cổng máy chủ>:<cổng container>, và mặc định là mở ra toàn Internet.

03

Cách ly là sáu namespace, không phải phép màu. Sáu cái riêng, hai cái dùng chung — time user. Cái thứ hai là chuyện bảo mật.

04

Mọi thay đổi lúc chạy nằm ở lớp ghi. docker diff cho xem toàn bộ, và lớp đó mất cùng container.

05

Gỡ rối đi từ ngoài vào trong. ss docker ps cột PORTS → docker logs docker exec. Bốn lệnh, đúng thứ tự, phủ gần hết mọi trường hợp.

Xong tờ này rồi?
Đăng nhập để lưu tiến độ vào tài khoản của bạn và mở khoá chứng nhận cuối khoá. Bài học vẫn đọc được đầy đủ khi chưa đăng nhập.
Đăng nhập để lưu tiến độ