Chương 17 · Ảo hoá Chapter 17 · Virtualization
“Ảo” không có nghĩa là giả — nó có nghĩa là có một người trung gian “Ảo” nghĩa là có người đứng giữa dịch giúp "Virtual" does not mean fake — it means there is an intermediary
Brian Ward mở chương cuối bằng một lời thú nhận: từ virtual trong hệ thống máy tính có thể rất mơ hồ. Ông đưa ra một định nghĩa làm việc: nó chủ yếu chỉ một trung gian chuyển một tầng bên dưới vốn phức tạp hoặc phân mảnh thành một giao diện đơn giản hoá mà nhiều bên tiêu thụ có thể dùng chung.1 Ví dụ bạn đã gặp chính là bộ nhớ ảo: nhiều tiến trình cùng truy cập một kho bộ nhớ lớn như thể mỗi tiến trình có kho riêng cách ly của nó.1
Chữ “ảo” nghe rất huyền bí, nhưng nghĩa của nó rất đời thường: có một người đứng giữa. Người đó nhìn vào một đống đồ lộn xộn ở phía dưới, rồi đưa cho mỗi người dùng một cái cửa sổ gọn gàng, khiến ai cũng tưởng mình có cả kho riêng. Nhớ nhé: “ảo” không phải là giả, “ảo” là có người đứng giữa dọn dẹp giúp bạn.
Brian Ward opens the final chapter with an admission: the word virtual can be vague in computing systems. He offers a working definition: it primarily indicates an intermediary that translates a complex or fragmented underlying layer into a simplified interface that can be used by multiple consumers.1 The example you have already seen is virtual memory: multiple processes access one large bank of memory as if each had its own insulated bank.1
Ward tự nhận định nghĩa đó “vẫn còn hơi đáng ngại”, nên ông chuyển sang mô tả mục đích điển hình của ảo hoá thay vì bản chất của nó: tạo ra các môi trường cách ly, để nhiều hệ thống chạy được mà không giẫm chân nhau.1 Đây là một nước đi phương pháp luận đáng chú ý ở chương cuối: sau mười sáu chương mô tả cơ chế, ông kết thúc bằng một khái niệm mà cách hiểu tốt nhất là qua công dụng. Ông cũng nói rõ giới hạn của chương: phần máy ảo sẽ ở mức cao, chỉ nhằm giải thích những thuật ngữ bạn sẽ gặp mà không lao vào “biển mênh mông các chi tiết hiện thực”, còn phần container sẽ đi sâu hơn về kỹ thuật vì nó được dựng từ chính những thứ bạn đã thấy trong sách.1
Luận đề của chương: ảo hoá có hai hình thái chính — máy ảo dựng lại toàn bộ phần cứng và chạy một nhân riêng bên trong, và container giữ nguyên một nhân Linux duy nhất rồi dùng các tính năng của nhân để nhốt tiến trình vào một môi trường chạy bị giới hạn. Chọn cái nào là chọn mức cách ly bạn cần và cái giá bạn trả cho nó.1
Ý chính: có hai cách làm “máy trong máy”. Cách thứ nhất dựng hẳn một cái máy mới bên trong — nặng nhưng kín. Cách thứ hai chỉ quây một cái hàng rào quanh vài chương trình — nhẹ nhưng vẫn chung một cái nhân. Nhớ nhé: máy ảo là xây nhà mới, container là dựng hàng rào.
The chapter's thesis: virtualization comes in two main shapes — virtual machines, which rebuild the whole of the hardware and run their own kernel inside, and containers, which keep a single underlying Linux kernel and use its features to confine processes to a restricted runtime environment. Choosing between them means choosing how much isolation you need and what you are willing to pay for it.1
Cụm khái niệm 01 Concept cluster 01
Máy ảo: bộ nhớ ảo, nhưng áp dụng cho cả cỗ máy Máy ảo: một cái máy nằm trong máy Virtual machines: virtual memory, but for the whole machine
Ward định nghĩa máy ảo bằng cách bắc cầu từ một khái niệm bạn đã biết: máy ảo dựa trên cùng ý tưởng với bộ nhớ ảo, chỉ khác là áp dụng cho toàn bộ phần cứng của máy chứ không riêng bộ nhớ. Bạn tạo hẳn một cỗ máy mới — bộ xử lý, bộ nhớ, các giao diện vào/ra — bằng phần mềm, rồi chạy nguyên một hệ điều hành trong đó, kể cả một nhân.1
Bạn đã biết bộ nhớ ảo: mỗi chương trình tưởng mình có cả kho bộ nhớ riêng. Máy ảo cũng y như vậy, nhưng làm với cả cái máy: bộ xử lý giả, bộ nhớ giả, đĩa giả. Bên trong cái máy giả đó, một hệ điều hành thật chạy và tin rằng mình đang ngồi trên phần cứng thật. Nhớ nhé: máy ảo là cả một cái máy được dựng bằng phần mềm.
Ward defines virtual machines by bridging from something you already know: they rest on the same concept as virtual memory, except applied to all of the machine's hardware rather than memory alone. You create an entirely new machine — processor, memory, I/O interfaces and so on — with the help of software, and run a whole operating system inside it, including a kernel.1
Tên gọi chính xác và tuổi đời. Loại máy ảo này, Ward nói, có tên cụ thể hơn là system virtual machine (máy ảo hệ thống), và nó đã tồn tại hàng chục năm: các máy tính lớn (mainframe) của IBM theo truyền thống dùng máy ảo hệ thống để tạo môi trường nhiều người dùng, mỗi người nhận một máy ảo chạy CMS — một hệ điều hành đơn giản, một người dùng.1 Tên gọi này để phân biệt với process virtual machine (máy ảo tiến trình), chẳng hạn máy ảo Java (JVM), mà Ward nói rõ là ông không bàn ở đây.1
Hai cách dựng. Bạn có thể dựng một máy ảo hoàn toàn bằng phần mềm — thứ này thường được gọi là emulator (trình giả lập) — hoặc tận dụng phần cứng bên dưới nhiều nhất có thể, đúng như cách bộ nhớ ảo vẫn làm. Với mục đích Linux của quyển sách, Ward chọn xem xét loại thứ hai vì hiệu năng vượt trội; nhưng ông lưu ý rằng nhiều trình giả lập phổ biến vẫn phục vụ các máy tính và hệ máy chơi game cũ, chẳng hạn Commodore 64 và Atari 2600.1
Hai kiểu. Kiểu một: phần mềm giả lập mọi thứ, chậm nhưng chạy được cả máy cũ đời xưa. Kiểu hai: mượn luôn phần cứng thật bên dưới, nhanh hơn nhiều. Sách chọn kiểu hai. Nhớ nhé: giả hoàn toàn thì chậm, mượn đồ thật thì nhanh.
Two ways to build one. You can construct a virtual machine entirely in software — usually called an emulator — or by utilizing the underlying hardware as much as possible, as virtual memory does. For the book's Linux purposes Ward looks at the latter, for its superior performance; but he notes that a number of popular emulators support old computers and gaming systems, such as the Commodore 64 and the Atari 2600.1
guest = máy ảo + hệ điều hành của nó
host = thứ chạy hypervisor
type 2 → host là hệ thống của bạn
type 1 → host là chính hypervisor
khách = cái máy giả bên trong
chủ = cái máy thật bên ngoài
loại 2 → chạy trên máy bạn
loại 1 → tự nó là hệ điều hành
guest = the VM + its operating system
host = whatever runs the hypervisor
type 2 → host is your native system
type 1 → host is the hypervisor itself
-
hypervisor
Hypervisor — hệ điều hành của những cỗ máy Hypervisor — người quản các máy giả Hypervisor — an operating system for machines
Phần mềm trông coi một hoặc nhiều máy ảo trên một máy tính được gọi là hypervisor, hay virtual machine monitor (VMM). Ward mô tả nó bằng một phép so sánh rất gọn: nó làm việc tương tự như cách một hệ điều hành quản lý các tiến trình.1 Đây là một trong những phép loại suy hữu ích nhất của chương: nếu bạn đã hiểu Chương 1 và Chương 8, bạn đã có sẵn mô hình tư duy cho hypervisor.
Trong một cái máy có nhiều máy giả, phải có ai đó trông coi chúng: chia lượt, chia bộ nhớ, dọn dẹp. Người trông coi đó tên là hypervisor. Nó làm với các máy giả đúng việc mà hệ điều hành làm với các chương trình. Nhớ nhé: hypervisor là “hệ điều hành” dành cho các máy ảo.
The software overseeing one or more virtual machines on a computer is called a hypervisor, or virtual machine monitor (VMM). Ward describes it with a compact comparison: it works similarly to how an operating system manages processes.1 This is one of the chapter's most useful analogies: if you understood Chapters 1 and 8, you already own the mental model for a hypervisor.
Bạn gặp nó ở đâuWhere you meet it Mỗi lần bạn bấm nút tạo một instance trên một dịch vụ đám mây, bạn đang yêu cầu một hypervisor cấp cho mình một cỗ máy. Mỗi lần ai đó “thuê một máy chủ trên mây” chỉ bằng vài cú bấm. Every time you click to create an instance on a cloud service, you are asking a hypervisor to hand you a machine.Guest và host
Nói chung, một máy ảo cùng hệ điều hành của nó được gọi là guest (khách). Host (chủ) là bất kỳ thứ gì chạy hypervisor. Với hypervisor loại 2, host đơn giản là hệ thống gốc của bạn; với loại 1, host chính là hypervisor, có thể kết hợp thêm một hệ thống đồng hành chuyên biệt.1
Vì sao phép so sánh này hiệu quả
Hệ điều hành phải lập lịch, phân bổ bộ nhớ, và trung gian hoá vào/ra cho các tiến trình. Hypervisor phải làm đúng ba việc đó cho các guest. Sự khác biệt chỉ nằm ở đơn vị được quản: tiến trình so với cả cỗ máy có nhân riêng.
-
type 2 hypervisor
Hypervisor loại 2 — chạy trên một hệ điều hành bình thường Loại 2 — cài như một phần mềm thường Type 2 hypervisor — running on an ordinary OS
Với đa số người dùng, hypervisor loại 2 là loại quen thuộc nhất, vì nó chạy trên một hệ điều hành bình thường như Linux. Ward lấy VirtualBox làm ví dụ: đó là một hypervisor loại 2, và bạn có thể chạy nó trên hệ thống của mình mà không cần sửa đổi gì nhiều — rất có thể bạn đã dùng nó trong lúc đọc quyển sách này để thử nghiệm các kiểu hệ thống Linux khác nhau.1
Loại 2 giống một ứng dụng bình thường: cài vào máy bạn, mở lên, bấm tạo máy mới. Máy thật của bạn vẫn là chủ nhà, cái máy giả chỉ là khách trọ. Nhớ nhé: loại 2 sống nhờ hệ điều hành của bạn.
For most users the type 2 hypervisor is the familiar one, because it runs on a normal operating system such as Linux. Ward's example is VirtualBox: a type 2 hypervisor you can run on your system without extensive modifications — you may well have used it while reading this book to test and explore different kinds of Linux systems.1
Bạn gặp nó ở đâuWhere you meet it Cửa sổ máy ảo trên máy bàn của bạn, nơi bạn thử một bản phân phối mới mà không cần đụng vào đĩa thật. Cái cửa sổ hiện ra một máy Linux khác ngay trên màn hình của bạn. The VM window on your desktop, where you try a new distribution without touching your real disk.Dùng thì dễ hơn mô tả
Ward chèn một ghi chú đáng nhớ: dùng máy ảo đơn giản hơn nhiều so với mô tả chúng. Trong VirtualBox, bạn có thể dùng giao diện đồ hoạ để tạo và chạy một máy ảo, hoặc dùng công cụ dòng lệnh
VBoxManagenếu cần tự động hoá quy trình đó trong một kịch bản; giao diện web của các dịch vụ đám mây cũng làm việc quản trị dễ đi. Chính vì thế ông tập trung vào việc làm sáng tỏ công nghệ và thuật ngữ hơn là chi tiết vận hành.15Ngoài bản văn
Sách viết ở thời điểm 2021. Trên Linux hiện nay, con đường phổ biến nhất không phải VirtualBox mà là KVM — mô-đun ảo hoá nằm sẵn trong nhân, cung cấp giao diện
/dev/kvmcho không gian người dùng, thường ghép với QEMU làm phần mô phỏng thiết bị.67 Đây là ghi chú của trang này, không phải lời Ward; nhưng nó khớp với lập luận của ông rằng loại dùng lại phần cứng bên dưới thắng về hiệu năng. -
type 1 hypervisor
Hypervisor loại 1 — bản thân nó là một hệ điều hành Loại 1 — chính nó là hệ điều hành Type 1 hypervisor — it is its own operating system
Ngược lại, hypervisor loại 1 giống một hệ điều hành của riêng nó hơn — đặc biệt là giống một nhân — được xây dựng chuyên biệt để chạy máy ảo nhanh và hiệu quả. Loại này thỉnh thoảng dùng một hệ thống đồng hành thông thường như Linux để hỗ trợ các tác vụ quản lý.1
Loại 1 không cần ai chứa chấp cả: nó tự nằm thẳng trên phần cứng và chỉ làm mỗi một việc — chạy các máy giả thật nhanh. Nhớ nhé: loại 1 nằm ngay trên phần cứng, không có hệ điều hành nào bên dưới.
A type 1 hypervisor, by contrast, is more like its own operating system — especially like a kernel — built specifically to run virtual machines quickly and efficiently. It might occasionally employ a conventional companion system such as Linux to help with management tasks.1
Bạn gặp nó ở đâuWhere you meet it Mỗi trang web bạn mở: Ward viết rằng khi bạn truy cập một website, gần như chắc chắn bạn đang chạm vào phần mềm chạy trên một máy ảo như thế.1 Mỗi lần bạn mở một trang web bất kỳ. Every website you open: Ward writes that when you access a website, you are almost certainly hitting software running on such a virtual machine.1Bạn dùng nó mà không biết
Ward nhấn mạnh một nghịch lý: dù có thể bạn chẳng bao giờ chạy một hypervisor loại 1 trên phần cứng của riêng mình, bạn tương tác với chúng suốt ngày. Toàn bộ dịch vụ điện toán đám mây đều chạy như máy ảo dưới các hypervisor loại 1 như Xen; tạo một instance hệ điều hành trên một dịch vụ đám mây như AWS chính là tạo một máy ảo trên một hypervisor loại 1.18
Ranh giới loại 1 / loại 2 không sắc như sơ đồ
Cách chia đôi này là cách chia của bản văn và rất hữu ích để định hướng; trong thực tế nó mờ ở rìa. Tài liệu nhân mô tả KVM như một API do chính nhân cung cấp: một lần
open("/dev/kvm")lấy được tay nắm vào phân hệ kvm, rồi không gian người dùng dùng các ioctl để tạo máy ảo và CPU ảo.64 Vì hypervisor ở đây là nhân của một hệ điều hành đa dụng, cách xếp nó vào loại 1 hay loại 2 tuỳ thuộc bạn nhấn vào vế nào — đây là nhận xét của trang này, không phải của Ward. Trong phần chính, trang này giữ nguyên cách phân đôi của ông thay vì lặng lẽ chọn một cách xếp loại. -
common uses
Ba nhóm công dụng — thử nghiệm, tương thích, máy chủ Dùng máy ảo để làm gì Three common uses — testing, compatibility, servers
Trong thế giới Linux, Ward xếp việc dùng máy ảo vào vài nhóm: thử nghiệm và dùng thử — khi bạn cần thử một thứ gì đó ngoài môi trường vận hành bình thường, chẳng hạn kiểm thử phần mềm trên một máy tách biệt với máy của lập trình viên, hay nghịch một bản phân phối mới trong một môi trường an toàn và “vứt đi được”, mà không phải mua phần cứng mới; tương thích ứng dụng — khi bạn cần chạy thứ gì đó dưới một hệ điều hành khác hệ điều hành thường dùng; và máy chủ cùng dịch vụ đám mây.1
Người ta dùng máy ảo để: thử đồ mới mà không sợ hỏng máy thật; chạy chương trình chỉ chạy được trên hệ điều hành khác; và dựng máy chủ trên mây. Nhớ nhé: máy ảo là cái sân chơi mà bạn làm hỏng cũng không sao.
In the Linux world Ward sorts virtual machine use into a few categories: testing and trials — trying something outside a normal or production environment, such as testing software on a machine separate from the developer's, or experimenting with a new distribution in a safe, "disposable" environment without buying new hardware; application compatibility — running something under an operating system that differs from your usual one; and servers and cloud services.1
Bạn gặp nó ở đâuWhere you meet it Nếu cần chạy một máy chủ internet, chẳng hạn một máy chủ web, Ward nói cách nhanh nhất là trả tiền cho một nhà cung cấp đám mây để lấy một instance máy ảo.1 Khi ai đó cần một máy chủ ngay trong hôm nay. If you need to run an internet server such as a web server, Ward says the quickest way is to pay a cloud provider for a virtual machine instance.1Máy chủ chuyên biệt cũng chỉ là máy ảo
Ward bồi thêm một nhận xét dễ bị bỏ qua: các nhà cung cấp đám mây còn chào bán những máy chủ chuyên biệt, chẳng hạn cơ sở dữ liệu — nhưng đó chỉ là những bộ phần mềm được cấu hình sẵn chạy trên máy ảo.1 Nói cách khác, phần lớn cái bạn mua trên mây là cấu hình, không phải công nghệ mới.
Cụm khái niệm 02 Concept cluster 02
Phần cứng ảo: gian lận có nguyên tắc để đổi lấy tốc độ Phần cứng giả: gian lận một chút cho nhanh Virtual hardware: principled cheating in exchange for speed
Ward dựng một phản đề rất rõ. Muốn cấp cho guest một thiết bị đĩa ảo, bạn có thể tạo một tệp lớn ở đâu đó trên host rồi cấp quyền truy cập nó như một đĩa, bằng cách mô phỏng vào/ra thiết bị theo chuẩn. Cách làm này là một máy ảo phần cứng nghiêm ngặt — và nó không hiệu quả. Muốn máy ảo thực dụng cho nhiều nhu cầu khác nhau thì phải thay đổi vài thứ.1
Muốn có một cái đĩa giả thì dễ: lấy một tệp to trên máy thật rồi bảo máy giả “đây là đĩa của mày”. Nhưng nếu bắt chước từng chi tiết một thì chậm kinh khủng. Thế nên người ta cho phép máy giả nói chuyện thẳng với máy thật ở vài chỗ. Nhớ nhé: bắt chước kỹ quá thì chậm, nên phải cho đi tắt vài đoạn.
Ward sets up a sharp antithesis. To give a guest a virtual disk device, you could create a big file somewhere on the host and provide access as a disk with standard device I/O emulation. That approach is a strict hardware virtual machine — and it is inefficient. Making virtual machines practical for a variety of needs requires some changes.1
Mục tiêu bất biến. Dù cơ chế là gì, Ward chốt lại, mục tiêu của ảo hoá luôn là giảm bài toán xuống vừa đủ để hệ điều hành guest có thể đối xử với phần cứng ảo như với bất kỳ thiết bị nào khác. Điều đó bảo đảm mọi tầng nằm trên thiết bị đều hoạt động đúng: trên một guest Linux, bạn muốn nhân truy cập được các đĩa ảo như thiết bị khối, để bạn phân vùng và tạo hệ thống tệp trên chúng bằng đúng những công cụ quen thuộc.1 Đây chính là Chương 4 đang quay lại làm tiêu chí nghiệm thu cho Chương 17.
Định nghĩa. Paravirtualization (bán ảo hoá) là việc đi vòng qua phần cứng ảo giữa host và guest, cho phép guest truy cập tài nguyên của host một cách trực tiếp hơn. Phần lớn khác biệt bạn gặp giữa phần cứng thật và phần cứng ảo đều là hệ quả của một cây cầu nối kiểu này; giao diện mạng và thiết bị khối là những thứ dễ được đối xử như thế nhất.1
Nói đơn giản. Thay vì diễn kịch “tôi là một cái đĩa thật” rất mệt, máy giả và máy thật thoả thuận với nhau: “thôi khỏi diễn, nói thẳng đi cho nhanh”. Cái thoả thuận đó tên là paravirtualization. Nhớ nhé: bớt diễn kịch thì chạy nhanh hơn.
Definition. Paravirtualization means bypassing virtual hardware between the host and guest so that guests can access host resources more directly. Most of the differences you encounter between real and virtual hardware result from such a bridge; network interfaces and block devices are among the most likely to receive this treatment.1
strict HW VM → mô phỏng đủ mọi chi tiết → chậm
paravirt → guest biết mình là guest → nhanh
/dev/xvd → đĩa ảo Xen
kernel mode / user mode → vẫn là trục chính
giả kỹ → chậm
nói thẳng → nhanh
/dev/xvd → đĩa của máy trên mây
strict HW VM → emulate every detail → slow
paravirt → the guest knows it is a guest → fast
/dev/xvd → a Xen virtual disk
kernel mode / user mode → still the main axis
-
paravirtualization
Paravirtualization — cây cầu nối tắt giữa guest và host Nói thẳng thay vì diễn kịch Paravirtualization — a shortcut bridge from guest to host
Ward đưa một ví dụ cụ thể mà bạn sẽ gặp ngay nếu thuê một máy trên mây: một thiết bị
/dev/xvdtrên một instance điện toán đám mây là một đĩa ảo Xen, dùng một trình điều khiển của nhân Linux để nói chuyện trực tiếp với hypervisor.1 Nhân guest ở đây không giả vờ rằng nó đang nói với một bộ điều khiển đĩa thật — nó biết mình là guest và dùng một con đường riêng.Trên một máy thuê ngoài mây, cái đĩa có thể tên là
/dev/xvd…chứ không phải tên quen thuộc. Đó là dấu hiệu cho thấy máy này biết rõ nó là máy giả và đang nói thẳng với người quản. Nhớ nhé: tên thiết bị lạ thường là dấu hiệu của phần cứng ảo.Ward gives a concrete example you will hit the moment you rent a cloud machine: a
/dev/xvddevice on a cloud computing instance is a Xen virtual disk, using a Linux kernel driver to talk directly to the hypervisor.1 The guest kernel here does not pretend it is speaking to a real disk controller — it knows it is a guest and takes a private route.Bạn gặp nó ở đâuWhere you meet it Lần đầu bạn chạylsblktrên một máy chủ đám mây và không thấy tên thiết bị nào giống máy bàn của mình. Khi tên ổ đĩa trên máy thuê trông lạ hoắc. The first time you runlsblkon a cloud server and recognise none of the device names.Đôi khi chỉ vì tiện
Không phải lúc nào paravirtualization cũng vì hiệu năng. Ward ghi rằng đôi khi nó được dùng cho tiện lợi: trên một hệ thống có khả năng làm máy bàn như VirtualBox, có sẵn các trình điều khiển để phối hợp chuyển động con trỏ chuột giữa cửa sổ máy ảo và môi trường host.1
Ngoài bản văn
Dự án Xen — hypervisor mà Ward nêu tên — mô tả paravirtualization (PV) như một kỹ thuật ảo hoá nhẹ, không cần phần mở rộng ảo hoá của bộ xử lý, với các trình điều khiển PV riêng cho vào/ra trong nhân guest.9 Đây là nguồn ngoài dùng để đối chiếu, không phải lời của Ward.
-
CPU modes
Chế độ CPU — vì sao x86 từng là một bài toán khó Vấn đề khó: ai được quyền cao nhất? CPU modes — why x86 was once a hard problem
Ward nói rõ rằng hầu hết chi tiết về cách máy ảo hoạt động nằm ngoài phạm vi quyển sách, nhưng CPU xứng đáng được nhắc tới vì sách đã bàn về khác biệt giữa chế độ nhân và chế độ người dùng. Tên gọi cụ thể của các chế độ này thay đổi theo bộ xử lý — ví dụ bộ xử lý x86 dùng một hệ thống gọi là privilege rings (vòng đặc quyền) — nhưng ý tưởng thì luôn như nhau: ở chế độ nhân, bộ xử lý làm được gần như mọi thứ; ở chế độ người dùng, một số chỉ thị bị cấm và truy cập bộ nhớ bị giới hạn.1
Bộ xử lý có hai mức quyền: mức cao làm được mọi thứ, mức thấp bị cấm nhiều thứ. Nhân chạy ở mức cao, chương trình thường chạy ở mức thấp. Nhớ nhé: quyền cao là quyền của nhân, không phải quyền của bạn.
Ward says most of the details of how virtual machines work lie beyond the book's scope, but the CPU deserves a mention because the book has already discussed the difference between kernel mode and user mode. The specific names vary by processor — x86 processors use a system called privilege rings — but the idea is always the same: in kernel mode the processor can do almost anything; in user mode some instructions are not allowed and memory access is limited.1
Bạn gặp nó ở đâuWhere you meet it Khi một hypervisor báo lỗi rằng ảo hoá phần cứng chưa được bật trong BIOS — đó chính là ranh giới chế độ CPU đang lên tiếng. Khi máy báo “phải bật ảo hoá trong BIOS” mới chạy được máy ảo. When a hypervisor reports that hardware virtualization is disabled in the BIOS — that is the CPU-mode boundary speaking.Bài toán gốc: guest muốn quyền của nhân
Những máy ảo đầu tiên cho kiến trúc x86 chạy ở chế độ người dùng. Điều đó gây ra một vấn đề, vì nhân chạy bên trong máy ảo lại muốn ở chế độ nhân. Để đối phó, hypervisor có thể phát hiện và phản ứng lại — “bẫy” (trap) — bất kỳ chỉ thị bị hạn chế nào đến từ một máy ảo. Với một chút công sức, hypervisor mô phỏng các chỉ thị bị hạn chế đó, giúp máy ảo chạy được ở chế độ nhân trên một kiến trúc vốn không được thiết kế cho điều đó.1
Vì sao cái giá lại nhỏ
Ward giải thích luôn lý do thủ thuật bẫy-và-mô-phỏng không giết chết hiệu năng: vì phần lớn chỉ thị mà một nhân thực thi đều không bị hạn chế, nên chúng chạy bình thường, và tác động lên hiệu năng khá nhỏ.1
-
VT-x / AMD-V
VT-x và AMD-V — khi thị trường sửa chính kiến trúc Bộ xử lý được chế lại để đỡ phải giả vờ VT-x and AMD-V — when the market fixed the architecture
Ngay sau khi loại hypervisor bẫy-và-mô-phỏng xuất hiện, các nhà sản xuất bộ xử lý nhận ra có một thị trường cho những bộ xử lý có thể hỗ trợ hypervisor bằng cách loại bỏ hẳn nhu cầu bẫy và mô phỏng chỉ thị. Intel và AMD phát hành các tập tính năng này với tên VT-x và AMD-V, và hầu hết hypervisor ngày nay đều hỗ trợ chúng — trong một số trường hợp, chúng là bắt buộc.1
Lúc đầu, phần mềm phải khéo léo lừa bộ xử lý. Sau đó các hãng làm chip nghĩ: sao không chế chip biết sẵn chuyện máy ảo? Thế là có VT-x của Intel và AMD-V của AMD. Nhớ nhé: khi một mẹo phần mềm trở nên quá quan trọng, nó thường được đưa thẳng vào phần cứng.
Soon after this kind of hypervisor appeared, processor manufacturers realised there was a market for processors that could assist the hypervisor by eliminating the need for instruction trapping and emulation. Intel and AMD released these feature sets as VT-x and AMD-V respectively, and most hypervisors now support them — in some cases they are required.1
Bạn gặp nó ở đâuWhere you meet it Mục “Virtualization Technology” trong BIOS, và cờvmxhoặcsvmtrong/proc/cpuinfotrên máy Linux của bạn. Cái mục “Virtualization” trong màn hình BIOS mà nhiều người phải bật lên. The "Virtualization Technology" entry in your BIOS, and thevmxorsvmflag in/proc/cpuinfoon your Linux machine.Đối chiếu với nguồn của nhà sản xuất
Intel mô tả công nghệ này bằng chính ngôn ngữ trừu tượng hoá của Chương 1: “Intel® Virtualization Technology trừu tượng hoá phần cứng, cho phép nhiều khối công việc dùng chung một tập tài nguyên”; hãng cũng ghi rằng việc bật hay tắt nó diễn ra trong BIOS, với điều kiện cả chip lẫn BIOS đều hỗ trợ.3 Đây là nguồn đối chiếu bên ngoài cho cái tên mà Ward nêu.
Hệ quả trên Linux hôm nay
Chính các tập tính năng này là thứ KVM dựa vào: tài liệu nhân mô tả KVM như một giao diện ảo hoá do nhân cung cấp qua
/dev/kvm, để không gian người dùng tạo và chạy máy ảo.6 Nói cách khác, mẩu lịch sử phần cứng này giải thích vì sao ảo hoá trên Linux hiện nay là một tính năng của nhân chứ không còn là một mẹo của ứng dụng. -
drawbacks
Năm nhược điểm — lý do container ra đời Máy ảo có gì phiền Five drawbacks — why containers exist
Ward liệt kê năm điểm còn phiền phức trong vận hành hằng ngày: một, cài đặt và cấu hình hệ thống lẫn ứng dụng có thể lỉnh kỉnh và tốn thời gian — công cụ như Ansible tự động hoá được, nhưng dựng một hệ thống từ đầu vẫn mất nhiều thời gian; hai, ngay cả khi cấu hình đúng, máy ảo khởi động và khởi động lại tương đối chậm, vì bạn vẫn đang boot cả một hệ thống Linux; ba, bạn phải bảo trì nguyên một hệ thống Linux trên mỗi máy ảo, gồm cả systemd và sshd; bốn, ứng dụng của bạn có thể xung đột với bộ phần mềm chuẩn trên máy ảo, và phụ thuộc như thư viện có thể đổi khi nâng cấp, làm hỏng thứ từng chạy tốt; năm, cách ly dịch vụ trên các máy ảo riêng biệt có thể lãng phí và tốn kém, vì dịch vụ đám mây tính tiền theo từng instance.1
Máy ảo tiện, nhưng phiền ở chỗ: cài lâu, khởi động chậm, phải chăm sóc từng cái một như chăm một cái máy thật, dễ xung đột phần mềm, và càng nhiều máy thì càng tốn tiền. Nhớ nhé: mỗi máy ảo là một cái máy nữa mà bạn phải nuôi.
Ward lists five things that remain troublesome day to day: one, installing and configuring the system and application can be cumbersome and time-consuming — tools such as Ansible automate it, but bringing a system up from scratch still takes significant time; two, even when configured properly, virtual machines start and reboot relatively slowly, because you are still booting a full Linux system; three, you must maintain a full Linux system on each virtual machine, including systemd and sshd; four, your application may conflict with the standard software set, and dependencies such as libraries can change on upgrade, breaking things that once worked; five, isolating services on separate virtual machines can be wasteful and costly, since cloud services charge per virtual machine instance.1
Bạn gặp nó ở đâuWhere you meet it Khi hoá đơn đám mây tăng vì bạn tuân thủ đúng thực hành “mỗi máy một dịch vụ” — một mâu thuẫn mà Ward nêu thẳng. Khi tiền thuê máy tăng lên chỉ vì bạn muốn mọi thứ tách riêng cho an toàn. When the cloud bill climbs because you followed the "one service per system" practice — a tension Ward names outright.Mâu thuẫn được nêu tên
Ward chỉ ra rằng thực hành chuẩn của ngành là chạy không quá một dịch vụ ứng dụng trên mỗi hệ thống — cách làm này bền vững và dễ bảo trì hơn; nếu bạn chạy nhiều website, tốt hơn là để chúng trên các máy chủ khác nhau. Nhưng điều đó xung đột với việc giữ chi phí thấp.1 Đây không phải một lỗi kỹ thuật mà là một đánh đổi kinh tế, và ông nói thẳng như vậy.
Kết luận có điều kiện
Ông rào lại rất cẩn thận: những vấn đề này thực ra không khác gì những vấn đề bạn gặp khi chạy dịch vụ trên phần cứng thật, và chúng không nhất thiết là trở ngại trong các hệ thống nhỏ. Nhưng một khi bạn bắt đầu chạy nhiều dịch vụ hơn, chúng trở nên rõ rệt, tốn cả thời gian lẫn tiền bạc — đó là lúc bạn có thể cân nhắc container.1
Cụm khái niệm 03 Concept cluster 03
Container: không có tính năng nào tên là “container” Container: một hàng rào ghép từ nhiều mảnh Containers: there is no kernel feature called "container"
Đây là luận điểm quan trọng nhất của chương, và Ward xây dựng nó từ lịch sử. Cách vận hành mạng máy tính truyền thống là chạy nhiều dịch vụ trên cùng một máy vật lý — một máy chủ tên miền có thể kiêm luôn máy chủ thư điện tử. Nhưng bạn không nên tin bất kỳ phần mềm nào, kể cả máy chủ, là an toàn hay ổn định. Nên người ta dựng rào quanh các daemon máy chủ, nhất là khi không tin tưởng lắm một trong số chúng.1
Ngày xưa, một cái máy chạy đủ mọi dịch vụ cùng lúc. Nhưng phần mềm nào cũng có thể hỏng hoặc bị hack, nên người ta bắt đầu quây rào quanh từng dịch vụ. Container chính là cái hàng rào đó, làm bằng nhiều mảnh ghép lại. Nhớ nhé: container không phải một thứ, nó là nhiều thứ ghép lại.
This is the chapter's most important claim, and Ward builds it from history. The traditional way of operating computer networks was to run multiple services on the same physical machine — a name server could also act as an email server. But you shouldn't really trust any software, including servers, to be secure or stable. So people put up barriers around server daemons, especially ones they don't trust much.1
Hai tổ tiên được nêu tên. Ward chỉ ra hai kỹ thuật cách ly có trước container. Thứ nhất là lời gọi hệ thống chroot(), đổi thư mục gốc sang một thứ khác thư mục gốc thật của hệ thống: một chương trình có thể đổi gốc của nó sang thứ gì đó như /var/spool/my_service và không còn truy cập được gì bên ngoài thư mục đó; có cả một chương trình chroot cho phép bạn chạy một chương trình với thư mục gốc mới. Kiểu cách ly này đôi khi được gọi là chroot jail (nhà tù chroot) vì các tiến trình (thường là) không thoát ra được.110 Thứ hai là tính năng giới hạn tài nguyên (rlimit) của nhân, hạn chế một tiến trình được tiêu thụ bao nhiêu thời gian CPU hoặc tệp của nó lớn đến đâu.111 Ward chốt: đó chính là những ý tưởng mà container được dựng lên trên — bạn đang thay đổi môi trường và giới hạn tài nguyên mà tiến trình chạy với.1
Định nghĩa. Ward định nghĩa rất thận trọng: tuy không có một đặc trưng định nghĩa duy nhất nào, một container có thể được định nghĩa lỏng lẻo là một môi trường chạy bị hạn chế dành cho một tập tiến trình, với hàm ý rằng các tiến trình đó không chạm được vào bất cứ thứ gì trên hệ thống nằm ngoài môi trường ấy. Nói chung, điều này được gọi là ảo hoá ở mức hệ điều hành (operating system–level virtualization).1
Nói đơn giản. Container là một cái sân có hàng rào, trong đó vài chương trình chơi với nhau và không với tay ra ngoài được. Không có một cái nút nào tên là “container” cả — cái sân đó được rào bằng nhiều loại rào khác nhau. Nhớ nhé: container là một cái sân rào, không phải một cái hộp phép thuật.
Definition. Ward defines it carefully: although there's no single defining feature, a container can be loosely defined as a restricted runtime environment for a set of processes, the implication being that those processes can't touch anything on the system outside that environment. In general this is called operating system–level virtualization.1
container ≈ cgroups riêng
+ thiết bị & hệ thống tệp riêng
+ không thấy tiến trình khác
+ giao diện mạng riêng
nhưng vẫn: MỘT nhân Linux duy nhất
hàng rào = chia phần tài nguyên
+ thư mục riêng
+ không nhìn thấy ai khác
+ mạng riêng
nhưng nhân thì vẫn chung một cái
container ≈ its own cgroups
+ its own devices & filesystem
+ cannot see other processes
+ its own network interfaces
but still: ONE single Linux kernel
-
one kernel
Một nhân duy nhất — điều quan trọng nhất cần nhớ Vẫn chỉ có một cái nhân thôi One single kernel — the thing to keep in mind
Ward đặt câu này ở vị trí trang trọng: điều quan trọng cần ghi nhớ là một máy đang chạy một hoặc nhiều container thì vẫn chỉ có một nhân Linux nằm bên dưới. Tuy vậy, các tiến trình bên trong một container có thể dùng môi trường không gian người dùng từ một bản phân phối Linux khác với hệ thống bên dưới.1 Đây chính là chỗ ranh giới nhân / không gian người dùng của Chương 1 trở thành công cụ phân tích sắc bén nhất.
Dù bạn mở bao nhiêu container, cái nhân vẫn chỉ có một. Bên trong container có thể là một bản Linux khác hẳn — nhưng cái nhân thì dùng chung. Nhớ nhé: nhiều sân chơi, một ông trọng tài.
Ward gives this sentence a place of honour: it's important to keep in mind that a machine running one or more containers still has only one underlying Linux kernel. However, the processes inside a container can use the user-space environment from a Linux distribution different from the underlying system.1 This is where Chapter 1's kernel/user-space boundary becomes the sharpest analytical tool in the book.
Bạn gặp nó ở đâuWhere you meet it Khi bạn chạy một container Alpine trên một host Ubuntu vàuname -rtrong container trả về đúng phiên bản nhân của host. Khi bên trong container là Alpine mà máy thật lại là Ubuntu. When you run an Alpine container on an Ubuntu host anduname -rinside it returns the host's kernel version.Bốn khía cạnh của một tiến trình trong container
Ward liệt kê bốn đặc điểm quan trọng: chúng có cgroup riêng; có thiết bị và hệ thống tệp riêng; không thể thấy hay tương tác với bất kỳ tiến trình nào khác trên hệ thống; và có giao diện mạng riêng.1 Bốn dòng này chính là mục lục ngược của các chương trước: Chương 8 cho cgroup, Chương 4 cho hệ thống tệp, Chương 1 và 8 cho tiến trình, Chương 9 cho mạng.
Vì sao cần công cụ
Ông nói thẳng rằng gom tất cả những thứ đó lại là một việc phức tạp: có thể thay đổi mọi thứ thủ công, nhưng rất khó — chỉ riêng việc nắm được cgroup cho một tiến trình đã rắc rối rồi. Vì thế mới có nhiều công cụ thực hiện các tác vụ con; hai trong số phổ biến nhất là Docker và LXC, và chương này tập trung vào Docker.112
-
Docker / Podman
Docker và Podman — khác nhau ở chỗ có máy chủ hay không Hai công cụ, một kiểu dùng Docker and Podman — server or no server
Ward nêu khác biệt chính rất gọn: Docker cần một máy chủ đang chạy khi bạn dùng container, còn Podman thì không. Điều này ảnh hưởng tới cách hai hệ thống dựng container. Hầu hết cấu hình Docker cần đặc quyền siêu người dùng để truy cập các tính năng nhân mà container của nó dùng, và daemon
dockerdlàm phần việc liên quan. Ngược lại, bạn có thể chạy Podman như một người dùng thường — gọi là rootless operation (vận hành không cần root) — và khi chạy theo cách đó, nó dùng các kỹ thuật khác để đạt được sự cách ly.113Có hai công cụ hay dùng. Docker cần một “ông quản lý” chạy ngầm và thường phải có quyền cao. Podman không cần ông quản lý đó, và người dùng thường cũng chạy được. Câu lệnh thì gần như y hệt nhau. Nhớ nhé: gõ
dockerhaypodmancũng gần như nhau.Ward states the primary difference compactly: Docker requires a server to be running when using containers, while Podman does not. This affects how the two set containers up. Most Docker configurations require superuser privileges to access the kernel features its containers use, and the
dockerddaemon does the relevant work. By contrast, you can run Podman as a normal user — called rootless operation — and when run this way it uses different techniques to achieve isolation.113Bạn gặp nó ở đâuWhere you meet it Khi tài liệu bảo bạn thêm chính mình vào nhómdockerđể chạy lệnh Docker như người dùng thường — một ghi chú Ward cũng đưa vào.1 Khi lệnhdockerbáo lỗi quyền và ai đó bảo bạn “thêm vào nhóm docker đi”. When the docs tell you to add yourself to thedockergroup to run Docker commands as a regular user — a note Ward also includes.1Đối xứng hai chiều
Ward ghi rõ rằng ranh giới này không cứng: bạn cũng có thể chạy Podman như siêu người dùng, khiến nó chuyển sang một số kỹ thuật cách ly mà Docker dùng; ngược lại, các phiên bản
dockerdmới hơn có hỗ trợ chế độ rootless.114 May mắn là Podman tương thích dòng lệnh với Docker, nên bạn thaypodmanchodockertrong các ví dụ và chúng vẫn chạy — dù có khác biệt về hiện thực, nhất là ở chế độ rootless.1Cơ chế đằng sau rootless
Bản văn không đi sâu vào cách rootless hoạt động. Tài liệu nhân và man page hiện nay mô tả nền tảng của nó: user namespace ánh xạ định danh người dùng và nhóm, sao cho một tiến trình có thể có UID 0 và đầy đủ capability bên trong namespace mà không có đặc quyền nào ở bên ngoài.1516 Đây là ghi chú bổ sung của trang này, không phải lời Ward.
-
image vs container
Ảnh và container — cặp khái niệm dễ lẫn nhất Ảnh là khuôn, container là bánh Image vs container — the easiest pair to confuse
Ward cảnh báo thẳng rằng rất dễ nhầm ảnh (image) với container. Cách nghĩ ông đề xuất: coi ảnh là hệ thống tệp của container — tiến trình không chạy trong một ảnh, chúng chạy trong container. Ông tự thú rằng điều này không hoàn toàn chính xác (đặc biệt, khi bạn thay đổi tệp trong một container Docker, bạn không đang thay đổi cái ảnh), nhưng đủ gần để bắt đầu.1
Ảnh giống cái khuôn bánh: nó chứa sẵn mọi nguyên liệu nhưng không tự làm gì. Container là cái bánh đã đổ ra khuôn và đang nóng. Bạn cắt cái bánh thì cái khuôn không đổi. Nhớ nhé: khuôn không đổi khi bánh bị cắt.
Ward warns plainly that images and containers are easy to confuse. His suggested framing: think of an image as the container's filesystem — processes don't run in an image, they run in containers. He admits this is not quite accurate (in particular, when you change files in a Docker container you are not making changes to the image), but it is close enough to start.1
Bạn gặp nó ở đâuWhere you meet it Khidocker imagesvàdocker pscho bạn hai danh sách trông giống nhau với hai loại định danh rất giống nhau. Khi hai danh sách trên màn hình trông y hệt mà thật ra là hai thứ khác nhau. Whendocker imagesanddocker psgive you two similar-looking lists with two very similar kinds of identifier.Dockerfile ba dòng của Ward
Ví dụ của ông tạo một tệp Dockerfile gồm đúng ba dòng:
FROM alpine:latest,RUN apk add bash, vàCMD ["/bin/bash"].117 Cấu hình này dùng bản phân phối nhẹ Alpine; thay đổi duy nhất là thêm shell bash, làm vậy không chỉ để dùng tương tác tiện hơn mà còn để tạo ra một ảnh độc nhất và xem quy trình đó diễn ra thế nào. Ward ghi rõ rằng dùng ảnh công khai mà không sửa gì là chuyện hoàn toàn bình thường và phổ biến — trong trường hợp đó bạn không cần Dockerfile.118 -
intermediate image
Ảnh trung gian — đọc kỹ kết quả của
docker buildMỗi bước dựng sinh ra một mảnh Intermediate images — read that build outputWard dựng ảnh bằng
docker build -t hlw_test ., lệnh này đọc Dockerfile trong thư mục hiện tại và gán định danhhlw_testcho ảnh. Ông dặn: hãy chuẩn bị tinh thần cho rất nhiều dòng kết quả, và đừng bỏ qua chúng — đọc hết chúng lần đầu tiên sẽ giúp bạn hiểu Docker hoạt động ra sao.1 Ở bước 1, Docker kéo bản Alpine mới nhất từ Docker registry và tạo một ảnh mới; một ảnh không nhằm là sản phẩm cuối cùng được gọi là ảnh trung gian (intermediate image).1Khi bạn bảo máy “dựng ảnh giúp tôi”, màn hình sẽ trôi rất nhiều chữ. Đừng lướt qua — mỗi đoạn là một bước. Mỗi bước tạo ra một mảnh nhỏ, và chỉ mảnh cuối cùng là cái bạn dùng. Nhớ nhé: đọc màn hình là cách học nhanh nhất.
Ward builds with
docker build -t hlw_test ., which reads the Dockerfile in the current directory and applies the identifierhlw_test. His instruction: be prepared for a lot of output, and don't ignore it — reading through it this first time will help you understand how Docker works.1 At step 1, Docker pulls the latest Alpine from the Docker registry and creates a new image; an image not intended to be a final product is called an intermediate image.1Bạn gặp nó ở đâuWhere you meet it Ở các dòngStep 1/3,Step 2/3,Step 3/3— chúng ứng đúng với ba dòng của Dockerfile. Ở những dòng ghi “Step 1/3”, “Step 2/3”, “Step 3/3”. In theStep 1/3,Step 2/3,Step 3/3lines — they map exactly onto the three Dockerfile lines.Bí mật của bước 2
Ward đặt một câu hỏi rất hay: bạn đâu có chạy Alpine trên máy mình — vậy sao chạy được lệnh
apkvốn thuộc về Alpine? Chìa khoá nằm ở dòng ghiRunning in …: bạn chưa yêu cầu một container nào, nhưng Docker đã dựng một container mới từ ảnh Alpine trung gian ở bước trước. Container cũng có định danh, và đáng tiếc là chúng trông không khác gì định danh ảnh. Docker gọi container tạm này là container trung gian — khác với ảnh trung gian: ảnh trung gian ở lại sau khi dựng xong, còn container trung gian thì không.1Trình tự đầy đủ của bước 2
Sau khi dựng container tạm, Docker chạy lệnh
apkbên trong container đó để cài bash, rồi lưu các thay đổi trên hệ thống tệp thành một ảnh trung gian mới — và xoá container đi sau khi hoàn tất.1 Ward cũng ghi rằng kết quả in ra khác khi bạn dùng Podman, nhưng các bước thì như nhau.119 -
PID namespace
Namespace tiến trình — vì sao shell của bạn là PID 1 Trong container, chương trình đầu tiên mang số 1 PID namespaces — why your shell is PID 1
Ward khởi động container bằng
docker run -it hlw_testvà bạn nhận được một dấu nhắc bash, chạy với tư cách người dùng root. Nếu bạn liệt kê tiến trình đầy đủ bên trong, bạn chỉ nhận đúng hai mục: shell mang PID 1, và chính lệnh liệt kê. Ông nhấn mạnh sự lạ lùng đó — trên một hệ thống bình thường, PID 1 là init.1 Nhưng các tiến trình này chỉ đơn giản là những tiến trình bạn có thể thấy trên hệ thống host bình thường; mở một cửa sổ shell khác trên host, bạn sẽ tìm thấy tiến trình container trong danh sách, dù phải tìm một chút.1Vào trong container, bạn thấy chỉ có hai chương trình đang chạy, và chương trình của bạn mang số 1. Nhưng nhìn từ bên ngoài, nó vẫn nằm đó trong danh sách của máy thật, chỉ mang số khác. Nhớ nhé: cùng một tiến trình, hai cái tên số khác nhau — tuỳ bạn đứng ở đâu mà nhìn.
Ward starts the container with
docker run -it hlw_testand you get a bash prompt, running as the root user. A full process listing inside gives just two entries: the shell as PID 1, and the listing itself. He stresses the oddity — on a normal system, PID 1 is init.1 But these are simply processes you can also see on your normal host system; open another shell window on the host and you will find the container process in a listing, though it will require a little searching.1Bạn gặp nó ở đâuWhere you meet it Ngay lần đầu bạn gõps auxbên trong một container và tự hỏi phần còn lại của hệ thống đã đi đâu. Lần đầu bạn nhìn danh sách tiến trình trong container và thấy nó ngắn kỳ lạ. The first time you typeps auxinside a container and wonder where the rest of the system went.Tên của tính năng
Ward gọi đây là cuộc gặp đầu tiên với một trong các tính năng nhân dùng cho container: Linux kernel namespaces, cụ thể ở đây là cho định danh tiến trình. Một tiến trình có thể tạo ra cả một tập định danh tiến trình mới cho chính nó và các con của nó, bắt đầu từ PID 1, và rồi chúng chỉ thấy được những định danh đó.12021
-
overlay filesystem
Hệ thống tệp overlay — các tầng chồng từ phải sang trái Nhiều lớp giấy bóng chồng lên nhau Overlay filesystems — layers stacking right to left
Khi bạn xem cách hệ thống tệp gốc trong container được gắn kết, nó rất khác một mount dựa trên thiết bị thông thường: bạn thấy một overlay filesystem, một tính năng của nhân cho phép tạo một hệ thống tệp bằng cách kết hợp các thư mục có sẵn thành các tầng, với các thay đổi được lưu ở một chỗ duy nhất.123
Hãy hình dung nhiều tờ giấy bóng kính chồng lên nhau: tờ dưới là bản gốc, các tờ trên vẽ thêm. Bạn nhìn xuyên qua và thấy một bức tranh duy nhất. Muốn sửa thì chỉ vẽ lên tờ trên cùng. Nhớ nhé: sửa ở tờ trên cùng, các tờ dưới vẫn nguyên.
When you look at how the container's root filesystem is mounted, it is very different from a normal device-based mount: you see an overlay filesystem, a kernel feature that lets you create a filesystem by combining existing directories as layers, with changes stored in a single spot.123
Bạn gặp nó ở đâuWhere you meet it Trong kết quả củamountbên trong container: dòng bắt đầu bằngoverlay on / type overlayvới các tham sốlowerdir,upperdir,workdir. Khi câu lệnhmountin ra một dòng dài loằng ngoằng chứa chữ “overlay”. In themountoutput inside the container: a line beginningoverlay on / type overlaywithlowerdir,upperdirandworkdirparameters.Ba thư mục, một quy tắc đọc
Ward giải thích: thư mục lower thực ra là một chuỗi thư mục phân tách bằng dấu hai chấm, và nếu tra chúng trên host bạn sẽ thấy cái cuối cùng là bản phân phối Alpine nền, được lập ở bước đầu tiên của quá trình dựng ảnh; hai thư mục đứng trước tương ứng với hai bước dựng còn lại. Do đó các thư mục này “xếp chồng” lên nhau theo thứ tự từ phải sang trái.1 Thư mục upper nằm trên cùng, và cũng là nơi mọi thay đổi với hệ thống tệp đã gắn kết xuất hiện. Thư mục work là chỗ cho trình điều khiển hệ thống tệp làm việc trước khi ghi thay đổi vào thư mục upper, và nó phải rỗng khi mount.123
Hệ quả: nhiều bước dựng thì nhiều tầng
Ward chỉ ra hệ quả: ảnh container có nhiều bước dựng sẽ có khá nhiều tầng. Đôi khi đó là một vấn đề, và có nhiều chiến lược để giảm số tầng, chẳng hạn gộp các lệnh
RUNlại và dùng multistage build; ông không đi vào chi tiết.117 Ông cũng ghi rằng ở chế độ rootless, Podman dùng phiên bản FUSE của overlay filesystem, nên bạn sẽ không thấy thông tin chi tiết này từ danh sách mount, nhưng có thể lấy thông tin tương tự bằng cách xem các tiến trìnhfuse-overlayfstrên host.1 -
network namespace
Mạng cầu nối — một cặp giao diện ảo và một lớp NAT Mạng riêng cho container Bridge networking — a virtual interface pair plus NAT
Bạn có thể cho container chạy chung mạng với máy host, nhưng bình thường bạn muốn một mức cách ly nào đó trong ngăn xếp mạng cho an toàn. Docker có vài cách, và mặc định — cũng là phổ biến nhất — gọi là bridge network, dùng một loại namespace khác: network namespace (netns). Trước khi chạy gì, Docker tạo một giao diện mạng mới trên host, thường là
docker0, tiêu biểu được gán vào một mạng riêng như172.17.0.0/16, nên giao diện trong trường hợp đó sẽ nhận172.17.0.1. Mạng này dùng cho liên lạc giữa máy host và các container của nó.124Container có mạng riêng của nó, giống như một phòng có đường dây nội bộ. Máy thật dựng một cái ổ cắm chung, rồi cắm mỗi container vào một đầu dây. Muốn ra internet thì phải đi qua một trạm dịch địa chỉ. Nhớ nhé: container có mạng riêng, muốn ra ngoài phải qua trạm trung chuyển.
You can have a container run on the same network as the host, but you normally want some isolation in the network stack for safety. Docker has several ways to do this, and the default — and most common — is called a bridge network, using another kind of namespace: the network namespace (netns). Before running anything, Docker creates a new network interface on the host, usually
docker0, typically assigned to a private network such as172.17.0.0/16, so the interface would get172.17.0.1. This network is for communication between the host machine and its containers.124Bạn gặp nó ở đâuWhere you meet it Khiip addrtrên host bỗng hiện ra một giao diệndocker0và một loạtveth…mà bạn không tự tạo. Khi máy bạn bỗng có thêm mấy cái “card mạng” lạ sau khi cài Docker. Whenip addron the host suddenly shows adocker0interface and a row ofveth…devices you never created.Cặp giao diện ảo
Khi tạo container, Docker tạo một network namespace mới gần như hoàn toàn trống: ban đầu nó chỉ chứa một giao diện loopback (
lo) mới, riêng tư. Để chuẩn bị cho dùng thật, Docker tạo một giao diện ảo trên host mô phỏng một liên kết giữa hai giao diện mạng thật, mỗi cái có thiết bị riêng, rồi đặt một trong hai thiết bị đó vào namespace mới. Với một cấu hình mạng dùng địa chỉ trên mạng Docker trên thiết bị nằm trong namespace mới, tiến trình có thể gửi gói trên mạng đó và được nhận ở phía host.125 Ward cảnh báo rằng điều này dễ gây rối, vì các giao diện khác nhau trong các namespace khác nhau có thể trùng tên — giao diện của container có thể tên làeth0, và máy host cũng vậy.1NAT và Podman rootless
Vì đây là một mạng riêng, nếu để nguyên thế thì các tiến trình container dùng namespace đó không ra được thế giới bên ngoài; để với tới các máy ngoài, mạng Docker trên host cấu hình NAT.1 Hình 17-1 của sách vẽ đúng cảnh đó:
lovàeth0bên host,docker0với cácveth, và NAT nối mạng con Docker ra ngoài.1 Ward ghi rằng mạng ở chế độ rootless của Podman thì khác, vì lập giao diện ảo cần quyền siêu người dùng: Podman vẫn dùng một network namespace mới, nhưng cần một giao diện lập được trong không gian người dùng — một giao diện TAP, thường ởtap0— kết hợp với một daemon chuyển tiếp tênslirp4netns. Cách này kém khả năng hơn; ví dụ, các container không kết nối được với nhau.126Ngoài bản văn
Hệ sinh thái đã đi tiếp kể từ 2021: tài liệu mạng của Podman hiện mô tả
pastalà cấu hình mạng mặc định cho người dùng rootless, vớislirp4netnsvẫn là một lựa chọn, vànetavarklà chế độ mặc định cho container chạy với quyền root.27 Đây là trạng thái hiện tại theo tài liệu chính thức, không phải điều Ward viết. -
docker ps / rm
Vòng đời container — thứ đã thoát vẫn còn nằm đó Container tắt rồi vẫn chưa biến mất Container lifecycle — exited does not mean gone
Ward định nghĩa theo đúng cách Docker định nghĩa: một container được coi là “đang chạy” chừng nào nó còn một tiến trình đang chạy; bạn xem các container đang chạy bằng
docker ps. Ngay khi mọi tiến trình của nó kết thúc, Docker đặt chúng vào trạng thái exit, nhưng vẫn giữ lại các container — trừ khi bạn khởi động với tuỳ chọn--rm— bao gồm cả các thay đổi đã làm với hệ thống tệp; bạn có thể truy cập hệ thống tệp đó dễ dàng bằngdocker export.122Container tắt rồi vẫn còn nằm trên đĩa, giữ nguyên mọi thứ nó đã ghi. Nếu không dọn, một ngày nào đó đĩa của bạn đầy mà bạn không hiểu vì sao. Nhớ nhé: tắt không phải là xoá — nhớ dọn dẹp.
Ward follows Docker's own definition: a container counts as "running" as long as it has a process running, and you list running containers with
docker ps. As soon as all its processes terminate Docker puts them into an exit state but still keeps the containers — unless you start with--rm— including the changes made to the filesystem, which you can reach easily withdocker export.122Bạn gặp nó ở đâuWhere you meet it Khi đĩa đầy trên một máy chủ chạy Docker vàdocker psthản nhiên báo rằng chẳng có container nào cả. Khi máy báo hết chỗ mà nhìn quanh chẳng thấy gì đang chạy. When a Docker host fills its disk anddocker pscalmly reports no containers at all.Vì sao bạn phải biết điều này
Ward nói rõ hậu quả:
docker psmặc định không hiện các container đã thoát; bạn phải dùng tuỳ chọn-ađể thấy mọi thứ. Rất dễ tích luỹ một đống lớn container đã thoát, và nếu ứng dụng chạy trong container tạo ra nhiều dữ liệu, bạn có thể hết sạch dung lượng đĩa mà không hiểu vì sao. Dùngdocker rmđể gỡ một container đã kết thúc.128Điều tương tự xảy ra với ảnh
Phát triển một ảnh thường là quá trình lặp đi lặp lại, và khi bạn gán cùng một thẻ cho một ảnh mới, Docker không xoá ảnh gốc — ảnh cũ chỉ đơn giản mất cái thẻ đó, và hiện ra trong
docker imagesvới<none>. Dùngdocker rmiđể gỡ một ảnh; lệnh này cũng gỡ các ảnh trung gian không còn cần thiết mà ảnh đó dựng lên trên.129 Ward tổng kết: nhìn chung Docker làm rất nhiều việc đánh phiên bản và điểm kiểm tra tỉ mỉ, và tầng quản lý này phản ánh một triết lý riêng so với các công cụ như LXC.1 -
process models
Mô hình tiến trình — “một container một tiến trình” là hiểu sai Container chạy được nhiều chương trình Process models — "one process per container" is a misreading
Ward đính chính một niềm tin rất phổ biến. Trước khi một tiến trình có thể kết thúc hoàn toàn, cha của nó phải thu (“reap”) mã thoát bằng lời gọi hệ thống
wait(). Trong container, có những tình huống các tiến trình đã chết vẫn nằm lại vì cha của chúng không biết phản ứng ra sao. Điều đó, cộng với cách nhiều ảnh được cấu hình, có thể khiến bạn kết luận rằng không nên chạy nhiều tiến trình hay dịch vụ trong một container Docker. Ward nói thẳng: điều đó không đúng.130Nhiều người tưởng mỗi container chỉ được chạy đúng một chương trình. Không phải vậy. Chỉ cần chương trình cha biết dọn dẹp khi con của nó chết là được. Nhớ nhé: được chạy nhiều chương trình, miễn là có người dọn.
Ward corrects a very common belief. Before a process can terminate completely, its parent is supposed to collect ("reap") its exit code with the
wait()system call. In a container there are situations where dead processes remain because their parents don't know how to react. That, together with the way many images are configured, might lead you to conclude that you're not supposed to run multiple processes or services inside a Docker container. Ward is blunt: this is not correct.130Bạn gặp nó ở đâuWhere you meet it Khi một container “đáng lẽ đã kết thúc” cứ nấn ná với vài tiến trình còn sót — dấu hiệu của tiến trình mồ côi không được thu. Khi container mãi không chịu tắt hẳn. When a container that "should have terminated" lingers with leftover processes — the signature of unreaped orphans.Điều kiện thật sự
Bạn có thể có nhiều tiến trình trong một container: chính shell trong ví dụ đã khởi động một tiến trình con mới mỗi lần bạn chạy một lệnh. Điều duy nhất thật sự quan trọng là khi bạn có tiến trình con, tiến trình cha phải dọn dẹp lúc chúng thoát. Hầu hết tiến trình cha đều làm việc này, nhưng trong một số hoàn cảnh thì không — nhất là khi nó không biết rằng mình có con. Chuyện này xảy ra khi có nhiều tầng sinh tiến trình và PID 1 trong container rốt cuộc trở thành cha của một tiến trình con mà nó không hay biết.1
Hai cách chữa mà Ward nêu
Với một dịch vụ đơn giản, chỉ sinh ra vài tiến trình và có vẻ để sót tiến trình lảng vảng, bạn có thể thêm tuỳ chọn
--initvàodocker run: nó tạo một tiến trình init rất đơn giản chạy làm PID 1 trong container và đóng vai một tiến trình cha biết phải làm gì khi con kết thúc.122 Còn nếu bạn chạy nhiều dịch vụ hoặc tác vụ trong một container — chẳng hạn nhiều worker cho một máy chủ công việc — thay vì khởi động chúng bằng một kịch bản, hãy cân nhắc một daemon quản lý tiến trình như Supervisor (supervisord) để khởi động và theo dõi chúng; nó không chỉ cung cấp chức năng hệ thống cần thiết mà còn cho bạn nhiều quyền kiểm soát hơn.131
Cụm khái niệm 04 Concept cluster 04
LXC, Kubernetes, cạm bẫy — và một loại ảo hoá thứ ba Công cụ khác, người quản lý, và chỗ dễ vấp LXC, Kubernetes, pitfalls — and a third kind of virtualization
Ward giải thích vì sao ông chọn Docker làm trục: không chỉ vì đó là hệ thống phổ biến nhất để dựng ảnh container, mà còn vì nó rất dễ bắt đầu và dễ nhảy thẳng vào các tầng cách ly mà container thường cung cấp. Nhưng có những gói khác, với cách tiếp cận khác — và trong số đó, LXC là một trong những cái lâu đời nhất; thực tế, các phiên bản Docker đầu tiên được dựng trên LXC.112
Docker không phải công cụ duy nhất, chỉ là công cụ dễ bắt đầu nhất. Có một công cụ già hơn tên LXC, và hồi xưa Docker còn được dựng trên nó. Nhớ nhé: cái dễ dùng nhất không phải lúc nào cũng là cái có trước.
Ward explains why he chose Docker as the spine: not only because it is the most popular system for building container images, but because it makes it very easy to get started and jump into the layers of isolation containers normally provide. But other packages exist, taking different approaches — and among them LXC is one of the oldest; in fact, the first versions of Docker were built on LXC.112
Một lưu ý về thuật ngữ. Ward ghi rằng thuật ngữ LXC đôi khi được dùng để chỉ tập các tính năng nhân làm cho container khả thi, nhưng hầu hết mọi người dùng nó để chỉ cụ thể một thư viện và một gói chứa một số tiện ích để tạo và thao tác container Linux.112 Sự nhập nhằng này đáng nhớ, vì nó lặp lại chính luận điểm trung tâm của mục container: không có một thứ duy nhất tên là “container”, nên tên của công cụ dễ bị nhầm với tên của cơ chế.
Khác biệt thực hành. Không như Docker, LXC đòi khá nhiều thiết lập thủ công: ví dụ, bạn phải tự tạo giao diện mạng cho container của mình, và bạn cần cung cấp các ánh xạ định danh người dùng. Ban đầu LXC được nhắm tới việc đặt càng nhiều một hệ thống Linux trọn vẹn càng tốt vào bên trong container — kể cả init.112
Nói đơn giản. Docker giống bộ đồ chơi lắp sẵn: tải về là chạy. LXC giống bộ đồ nghề: bạn phải tự lắp từng thứ, nhưng lắp kiểu gì cũng được. Nhớ nhé: lắp sẵn thì nhanh, tự lắp thì linh hoạt.
The practical difference. Unlike Docker, LXC involves a fair amount of manual setup: you have to create your own container network interface, and you need to provide user ID mappings. Originally LXC was intended to be as much of an entire Linux system as possible inside the container — init and all.112
Docker → tải tệp về là chạy
LXC → tự dựng, API C, linh hoạt hơn
LXD → gói quản lý + REST API
K8s → điều phối container qua nhiều máy
Docker → lắp sẵn
LXC → tự lắp
LXD → người phụ việc cho LXC
K8s → quản nhiều máy cùng lúc
Docker → download files and go
LXC → build it yourself, C API, more flexible
LXD → management package + REST API
K8s → orchestrates containers across machines
-
LXC / LXD
LXC — linh hoạt vì thủ công, và có API để lập trình LXC — tự lắp nên muốn gì cũng được LXC — flexible because manual, with an API to program against
Ward kết luận rằng bạn có thể thấy LXC linh hoạt hơn khi thích nghi với những nhu cầu khác nhau: ví dụ, mặc định LXC không dùng overlay filesystem như bạn đã thấy với Docker, dù bạn có thể thêm vào. Và vì LXC được dựng trên một API C, bạn có thể dùng mức chi tiết này trong ứng dụng phần mềm của chính mình nếu cần.112
Vì LXC để bạn tự lắp từng mảnh, bạn có thể lắp theo kiểu riêng. Và vì nó có một bộ lệnh dành cho lập trình viên, chương trình của bạn cũng gọi được vào. Nhớ nhé: tự lắp thì mệt hơn nhưng vừa ý hơn.
Ward concludes you may find LXC more flexible in adapting to different needs: by default, for example, LXC does not use the overlay filesystem you saw with Docker, although you can add one. And because LXC is built on a C API, you can use this granularity in your own software application if necessary.112
Bạn gặp nó ở đâuWhere you meet it Trong các hệ thống muốn container hành xử như một máy chủ đầy đủ có init riêng, thay vì như một tiến trình được đóng gói. Khi người ta muốn container giống một cái máy hoàn chỉnh hơn. In systems that want a container to behave like a full server with its own init, rather than like a packaged process.LXD — gói quản lý đi kèm
Ward giới thiệu LXD, một gói quản lý đồng hành giúp bạn xử lý một số điểm thủ công tinh tế của LXC — như tạo mạng và quản lý ảnh — và cung cấp một REST API mà bạn có thể dùng để truy cập LXC thay cho API C.132
Vì sao Ward không đưa ví dụ LXC
Ông nói thẳng lý do: nếu bạn đã hiểu phần thảo luận về cách Docker làm việc, bạn sẽ không gặp khó khăn với các khái niệm kỹ thuật của LXC, nên ông không đi qua ví dụ nào mà chỉ khám phá vài khác biệt thực hành.1 Đây là một minh hoạ rõ cho phương pháp của cả quyển sách: hiểu cơ chế một lần, rồi đổi công cụ là việc nhỏ.
-
Kubernetes
Kubernetes — năm việc mà không ai muốn làm tay Người quản nhiều container trên nhiều máy Kubernetes — five jobs nobody wants to do by hand
Container trở nên phổ biến cho nhiều loại máy chủ web, vì bạn có thể khởi động một loạt container từ một ảnh duy nhất trên nhiều máy, tạo ra độ dự phòng tuyệt vời. Đáng tiếc, điều này khó quản lý. Ward liệt kê các việc phải làm: theo dõi máy nào chạy được container; khởi động, giám sát và khởi động lại container trên các máy đó; cấu hình khởi động container; cấu hình mạng container theo yêu cầu; và nạp phiên bản ảnh mới rồi cập nhật mọi container đang chạy một cách mượt mà. Ông nói rõ đó chưa phải danh sách đầy đủ, và cũng không truyền tải đúng độ phức tạp của từng việc.133
Nếu bạn có một trăm container nằm trên mười cái máy, ai nhớ nổi cái nào đang chạy ở đâu? Phải có một người quản lý. Google làm ra một người quản lý như vậy, tên là Kubernetes. Nhớ nhé: nhiều container quá thì phải có người điều phối.
Containers became popular for many kinds of web servers, because you can start a bunch of containers from a single image across multiple machines, providing excellent redundancy. Unfortunately this is hard to manage. Ward lists the jobs: track which machines can run containers; start, monitor and restart containers on them; configure container startup; configure container networking as required; and load new image versions and update all running containers gracefully. He says outright that this is neither a complete list nor a fair account of each task's complexity.133
Bạn gặp nó ở đâuWhere you meet it Ở mọi nơi có một cụm máy chủ web hiện đại — và ở khối lượng tệp cấu hình mà một đội phải duy trì cho nó. Ở những hệ thống web lớn có hàng chục máy chủ. Anywhere there is a modern web server cluster — and in the volume of configuration files a team must maintain for it.Hai phía, và phía nào tốn công hơn
Ward viết rằng Kubernetes của Google đã trở nên thống trị trong số các giải pháp xuất hiện, và có lẽ một trong những yếu tố đóng góp lớn nhất là khả năng chạy ảnh container Docker. Nó có hai phía cơ bản, giống bất kỳ ứng dụng khách–chủ nào: phía máy chủ gồm các máy sẵn sàng chạy container, còn phía khách chủ yếu là một tập tiện ích dòng lệnh để khởi chạy và thao tác các tập container. Các tệp cấu hình có thể rất đồ sộ, và bạn sẽ nhanh chóng thấy rằng phần lớn công việc ở phía khách là tạo ra cấu hình phù hợp.133
Cách thử mà không dựng cụm
Nếu bạn không muốn tự lập các máy chủ, Ward gợi ý dùng công cụ Minikube để cài một máy ảo chạy một cụm Kubernetes ngay trên máy của bạn.134 Lưu ý ngoài bản văn: từ phiên bản 1.24 (2022), Kubernetes đã gỡ bỏ dockershim và không còn dùng Docker Engine trực tiếp làm container runtime; nó chạy các runtime tuân thủ CRI như containerd hay CRI-O — nhưng ảnh dựng bằng Docker vẫn chạy được, vì chúng theo chuẩn ảnh OCI.3536 Đây là trạng thái hiện tại theo tài liệu chính thức, không phải điều Ward viết năm 2021.
-
pitfalls
Sáu cạm bẫy — container không xoá được vật lý Sáu chỗ dễ vấp khi dùng container Six pitfalls — containers do not repeal physics
Ward nhắc trước một chi phí nền: tối thiểu, bạn vẫn cần một hoặc nhiều máy để chạy container, và đó phải là một máy Linux đầy đủ, dù trên phần cứng thật hay trên máy ảo; vẫn có chi phí bảo trì ở đây, dù hạ tầng lõi này có thể dễ bảo trì hơn một cấu hình đòi hỏi nhiều cài đặt phần mềm tuỳ biến. Chi phí đó có thể ở nhiều dạng: tự quản hạ tầng là một khoản đầu tư thời gian đáng kể cộng chi phí phần cứng, lưu trữ và bảo trì; dùng một dịch vụ container như một cụm Kubernetes thì bạn trả bằng tiền để người khác làm việc đó.1
Container nhẹ hơn máy ảo, nhưng không miễn phí. Bạn vẫn cần một cái máy thật để chứa chúng, và vẫn phải chăm sóc cái máy đó. Nhớ nhé: hàng rào nhẹ hơn nhà, nhưng vẫn cần một mảnh đất.
Ward flags a baseline cost: at minimum you still need one or more machines to run your containers, and this has to be a full-fledged Linux machine, whether on real hardware or a virtual machine; there is still a maintenance cost, although maintaining this core infrastructure may be simpler than a configuration requiring many custom software installations. That cost takes several forms: administering your own infrastructure is a significant investment of time plus hardware, hosting and maintenance costs; using a container service such as a Kubernetes cluster means paying the monetary cost of having someone else do the work.1
Bạn gặp nó ở đâuWhere you meet it Lần đầu một đội chuyển sang container để “đơn giản hoá vận hành” và phát hiện mình vừa nhận thêm một hệ thống nữa để vận hành. Khi chuyển sang container để cho gọn, mà hoá ra lại thêm việc. The first time a team moves to containers to "simplify operations" and discovers it has acquired one more system to operate.Sáu điểm về chính các container
Ward liệt kê: một, container có thể lãng phí về lưu trữ, vì để một ứng dụng chạy được, container phải chứa mọi hỗ trợ cần thiết của một hệ điều hành Linux như các thư viện chia sẻ — tình hình được giảm nhẹ phần nào khi dùng overlay filesystem với nhiều bản sao cùng một container, vì chúng chia sẻ cùng các tệp nền, nhưng nếu ứng dụng tạo nhiều dữ liệu lúc chạy thì các tầng trên của mọi overlay đó có thể phình to; hai, bạn vẫn phải nghĩ về các tài nguyên hệ thống khác như thời gian CPU — bạn có thể cấu hình giới hạn, nhưng vẫn bị ràng buộc bởi năng lực của hệ thống bên dưới, vì vẫn còn một cái nhân và các thiết bị khối; ba, bạn có thể phải nghĩ khác đi về nơi lưu dữ liệu.1
Ba điểm còn lại
Bốn, hầu hết công cụ và mô hình vận hành container đều hướng tới máy chủ web; Kubernetes nói riêng có nhiều tính năng an toàn để ngăn mã máy chủ chạy loạn — một lợi thế, vì nó bù cho việc (nói thẳng ra) phần lớn ứng dụng web được viết khá tệ; nhưng khi bạn cố chạy một loại dịch vụ khác, đôi khi cảm giác như đang đóng cọc vuông vào lỗ tròn. Năm, dựng container cẩu thả dẫn tới phình to, lỗi cấu hình và trục trặc: việc bạn tạo ra một môi trường cách ly không che chắn bạn khỏi những sai lầm trong môi trường đó — bạn cần hiểu những thay đổi mình thực hiện. Sáu, việc đánh phiên bản có thể rắc rối: sách dùng thẻ
latestcho các ví dụ, và khi bạn dựng một container dựa trên bản phát hành mới nhất của một bản phân phối hay gói, thứ gì đó bên dưới có thể đổi và làm hỏng ứng dụng của bạn — một thực hành chuẩn là dùng thẻ phiên bản cụ thể của container nền.117Vấn đề tin cậy, và một kết luận cân bằng
Ward thêm vấn đề tin cậy, áp dụng đặc biệt cho ảnh dựng bằng Docker: khi bạn dựa container của mình trên các ảnh trong kho ảnh Docker, bạn đang đặt niềm tin vào một tầng quản lý phụ rằng chúng không bị sửa đổi để đưa vào thêm vấn đề bảo mật, và rằng chúng sẽ còn ở đó khi bạn cần — tương phản với LXC, nơi bạn được khuyến khích tự dựng lấy ở một mức độ nhất định.1 Rồi ông cân bằng lại: khi cân nhắc những vấn đề này, bạn có thể nghĩ container có nhiều bất lợi so với các cách quản lý môi trường hệ thống khác — nhưng không phải vậy; dù bạn chọn cách nào, những vấn đề này đều hiện diện ở mức độ và hình thức nào đó, và một số dễ quản lý hơn trong container. Chỉ cần nhớ rằng container không giải quyết được mọi vấn đề: ví dụ, nếu ứng dụng của bạn mất nhiều thời gian để khởi động trên một hệ thống bình thường, nó cũng sẽ khởi động chậm trong container.1
-
runtime-based virtualization
Ảo hoá theo môi trường chạy — chỉ tách riêng một ứng dụng Hộp đồ nghề riêng cho một chương trình Runtime-based virtualization — isolating one application only
Loại ảo hoá cuối cùng Ward nhắc tới dựa trên kiểu môi trường dùng để phát triển một ứng dụng. Nó khác các máy ảo hệ thống và container ở chỗ không dùng ý tưởng đặt ứng dụng lên những cỗ máy khác nhau; thay vào đó, đây là một sự tách biệt chỉ áp dụng cho một ứng dụng cụ thể. Lý do tồn tại của những môi trường này: nhiều ứng dụng trên cùng một hệ thống có thể dùng cùng một ngôn ngữ lập trình, gây xung đột tiềm tàng. Ví dụ, Python được dùng ở nhiều nơi trên một bản phân phối tiêu biểu và có thể gồm nhiều gói bổ sung; nếu bạn muốn dùng phiên bản Python của hệ thống trong gói của mình, bạn có thể gặp rắc rối khi muốn một phiên bản khác của một trong các gói bổ sung đó.137
Đôi khi bạn không cần cả một cái máy hay một hàng rào — bạn chỉ cần một hộp đồ nghề riêng cho một chương trình, để nó không mượn nhầm đồ của người khác. Python có sẵn kiểu hộp như vậy. Nhớ nhé: đôi khi chỉ cần một hộp đồ riêng là đủ.
The final kind of virtualization Ward mentions is based on the type of environment used to develop an application. It differs from system virtual machines and containers because it does not use the idea of placing applications onto different machines; instead it is a separation that applies only to a particular application. The reason for such environments: multiple applications on the same system can use the same programming language, causing potential conflicts. Python, for example, is used in several places on a typical distribution and can include many add-on packages; if you want to use the system's Python in your own package, you can run into trouble if you want a different version of one of the add-ons.137
Bạn gặp nó ở đâuWhere you meet it Mỗi lần một hướng dẫn Python bảo bạn tạo một môi trường ảo trước khi cài bất cứ thứ gì — chính là cơ chế này. Mỗi lần một hướng dẫn bảo “tạo môi trường ảo trước đã”. Every time a Python tutorial tells you to create a virtual environment before installing anything — this is the mechanism.Ví dụ cụ thể của Ward
Ông tạo môi trường bằng
python3 -m venv test-venv, rồi ghi chú rằng đến lúc bạn đọc điều này, có thể bạn chỉ cần gõpythonthay vìpython3. Nhìn vào thư mục mới, bạn sẽ thấy một số thư mục giống hệ thống như bin, include và lib. Để kích hoạt môi trường ảo, bạn cần source (không phải thực thi) kịch bản bin/activate.137Vì sao phải source chứ không chạy
Ward giải thích lý do: kích hoạt về bản chất là đặt một biến môi trường, thứ bạn không thể làm bằng cách chạy một tệp thực thi. Sau đó, khi bạn chạy Python, bạn nhận được phiên bản trong thư mục test-venv/bin — bản thân nó chỉ là một liên kết tượng trưng — và biến môi trường
VIRTUAL_ENVđược đặt thành thư mục gốc của môi trường; bạn chạydeactivateđể thoát ra.137 Với biến môi trường đó được đặt, bạn có một thư viện gói mới, rỗng trong test-venv/lib, và mọi thứ mới bạn cài khi đang ở trong môi trường sẽ đi vào đó thay vì vào thư viện của hệ thống chính.1Vì sao chương kết thúc ở đây
Ward khép lại bằng một lý do rất thẳng thắn: không phải ngôn ngữ lập trình nào cũng cho phép môi trường ảo theo cách Python làm, nhưng vẫn đáng biết tới nó — nếu không vì lý do nào khác thì cũng để làm sáng tỏ đôi chút sự nhập nhằng quanh từ “virtual”.1 Chương mở ra bằng lời than rằng từ này mơ hồ, và đóng lại bằng việc gỡ nốt một nghĩa cuối cùng của nó. Đó cũng là câu cuối của phần thân quyển sách.
Đính chính Corrections
Ba ngộ nhận mà người đọc lần đầu hay mắc Ba chỗ hay hiểu nhầm Three misconceptions first readers hit
Phần này thuộc mức đọc Đầy đủ: nó đối chiếu điều người đọc thường nghĩ với điều bản văn thật sự nói.
Phần này hơi khó, bạn có thể bỏ qua và quay lại sau. Nhớ nhé: hiểu chậm mà chắc vẫn hơn.
This block belongs to the Đầy đủ (full) reading level: it sets what readers usually assume against what the text actually says.
“Container là một cái máy ảo siêu nhẹ” "A container is just a very lightweight virtual machine"
Ngộ nhận: container và máy ảo là cùng một thứ, chỉ khác nhau ở kích thước.
Bản văn nói: khác biệt là khác biệt về loại, không phải về mức độ. Máy ảo chạy nguyên một hệ điều hành trong đó, kể cả một nhân; còn một máy đang chạy một hay nhiều container thì vẫn chỉ có một nhân Linux duy nhất nằm bên dưới.1 Hệ quả trực tiếp: bên trong container bạn có thể dùng không gian người dùng của một bản phân phối khác, nhưng bạn không thể dùng một nhân khác.1
Misconception: containers and virtual machines are the same thing at different sizes.
The text says: the difference is one of kind, not of degree. A virtual machine runs a whole operating system inside it, including a kernel; a machine running one or more containers still has only one underlying Linux kernel.1 The direct consequence: inside a container you can use another distribution's user space, but you cannot use another kernel.1
“Mỗi container chỉ được chạy đúng một tiến trình” "A container may only ever run one process"
Ngộ nhận: vì trong container ps chỉ hiện một tiến trình, nên nhiều tiến trình là sai nguyên tắc.
Bản văn nói: Ward nêu đúng ngộ nhận này rồi bác bỏ bằng đúng bốn chữ — “điều này không đúng”. Bạn có thể có nhiều tiến trình trong một container; điều duy nhất thật sự quan trọng là tiến trình cha phải dọn dẹp khi con của nó thoát.1 Khi cha không làm được việc đó, --init hoặc một daemon quản lý tiến trình như supervisord là cách chữa mà ông nêu tên.131
Misconception: because ps inside a container shows one process, more than one must be against the rules.
The text says: Ward raises exactly this belief and dismisses it in four words — "this is not correct." You can have many processes in a container; the only thing that really matters is that parents clean up when their children exit.1 When a parent cannot, --init or a process-management daemon such as supervisord are the remedies he names.131
“Container giải quyết được vấn đề hiệu năng và chi phí” "Containers solve the performance and cost problem"
Ngộ nhận: chuyển sang container thì ứng dụng nhanh hơn và hệ thống rẻ hơn.
Bản văn nói: Ward đóng mục cạm bẫy bằng một câu rất cụ thể: nếu ứng dụng của bạn mất nhiều thời gian để khởi động trên một hệ thống bình thường, nó cũng sẽ khởi động chậm trong container.1 Và bạn vẫn cần một máy Linux đầy đủ để chạy chúng, dù trên phần cứng thật hay máy ảo; vẫn còn một cái nhân và các thiết bị khối, nên nếu bạn nạp quá tải thì container, hệ thống bên dưới, hoặc cả hai đều chịu trận.1
Misconception: moving to containers makes the application faster and the system cheaper.
The text says: Ward closes the pitfalls section with a very concrete sentence: if your application takes a long time to start on a normal system, it will also start slowly in a container.1 And you still need a full-fledged Linux machine to run them, on real hardware or a virtual machine; there is still a kernel and block devices, so if you overload things then your containers, the system underneath, or both will suffer.1
Tự kiểm tra Self-check
Bạn đã phân biệt được ba mức ảo hoá chưa? Thử trả lời xem nào Can you tell the three levels of virtualization apart?
Trả lời bằng lời của bạn, không tra sách. Nếu một câu khiến bạn ngập ngừng, đó chính là mục bạn nên đọc lại.
Thử trả lời miệng thôi, không cần giở lại. Câu nào bí thì quay lại đọc phần đó nhé. Nhớ nhé: chỗ bí chính là chỗ cần học.
Answer in your own words, without looking back. Whichever question makes you hesitate points at the section you should reread.
-
Ward định nghĩa từ virtual như thế nào, và ví dụ nào trong sách ông dùng để neo định nghĩa đó?
Gợi ý sâu hơn: vì sao ông chuyển ngay sang mô tả mục đích của ảo hoá thay vì bám vào định nghĩa?
-
Hypervisor loại 1 và loại 2 khác nhau ở chỗ nào, và trong mỗi trường hợp thì “host” là cái gì?
Gợi ý sâu hơn: bạn tương tác với loại nào thường xuyên nhất mà không hề hay biết?
-
Paravirtualization giải quyết vấn đề gì, và một thiết bị
/dev/xvdnói cho bạn biết điều gì?Gợi ý sâu hơn: vì sao “máy ảo phần cứng nghiêm ngặt” lại không hiệu quả?
-
Vì sao những máy ảo x86 đầu tiên gặp rắc rối, và hai tập tính năng nào của bộ xử lý đã gỡ rắc rối đó?
Gợi ý sâu hơn: vì sao thủ thuật bẫy-và-mô-phỏng lại không làm hiệu năng sụp đổ?
-
Bốn khía cạnh nào của một tiến trình trong container được Ward liệt kê, và mỗi khía cạnh ứng với tính năng nhân nào?
Gợi ý sâu hơn: câu nào trong mục đó là câu quan trọng nhất cần nhớ về nhân?
-
Trong một overlay filesystem,
lowerdir,upperdirvàworkdirlần lượt làm gì — và chúng xếp chồng theo thứ tự nào?Gợi ý sâu hơn: nhiều bước dựng ảnh dẫn tới hệ quả gì, và người ta giảm nó bằng cách nào?
-
Vì sao
docker pscó thể báo “không có gì đang chạy” trong khi đĩa của bạn đã đầy?Gợi ý sâu hơn: hai lệnh nào dọn dẹp, và tuỳ chọn nào tránh được vấn đề ngay từ đầu?
-
Ward bác bỏ niềm tin nào về số tiến trình trong một container, và điều kiện thật sự là gì?
Gợi ý sâu hơn: lời gọi hệ thống nào nằm ở tâm của vấn đề này?
“Ảo” nghĩa là gì? Có phải là “giả” không?
Máy ảo và container khác nhau chỗ nào? Cái nào nặng hơn?
Trong container, chương trình đầu tiên mang số mấy? Bình thường số đó là của ai?
Vì sao tắt container rồi mà đĩa vẫn đầy?
Một container có được chạy nhiều chương trình không?
-
How does Ward define the word virtual, and which example from earlier in the book anchors that definition?
-
What separates a type 1 from a type 2 hypervisor, and what counts as the "host" in each case?
-
What problem does paravirtualization solve, and what does a
/dev/xvddevice tell you? -
Why did the first x86 virtual machines run into trouble, and which two processor feature sets resolved it?
-
Which four aspects of a process in a container does Ward list, and which kernel feature backs each?
-
In an overlay filesystem, what do
lowerdir,upperdirandworkdireach do — and in what order do they stack? -
Why can
docker psreport nothing running while your disk is full? -
Which belief about the number of processes in a container does Ward reject, and what is the real condition?
Khép lại chương — và khép lại quyển sách Closing the chapter — and the book
Chương cuối không thêm một tầng mới nào vào hệ thống — nó lắp lại các tầng cũ theo một hình dạng khác. Container không đến từ một tính năng riêng lẻ nào mà từ một tập hợp các tính năng,1 và tập hợp ấy chính là quyển sách bạn vừa đọc: namespace cho tiến trình và mạng, cgroup cho tài nguyên, overlayfs cho hệ thống tệp. Ward khép lại đúng chỗ ông mở ra — gỡ nốt một nghĩa cuối của từ virtual.1
Chương cuối không dạy thêm thứ mới — nó ghép lại những thứ bạn đã học thành một hình khác. Container chỉ là nhiều mảnh cũ lắp vào nhau. Nhớ nhé: học xong thì đừng cất đi — hãy lắp chúng lại theo cách của bạn.
The final chapter adds no new layer to the system — it reassembles the old layers into a different shape. Containers come not from one particular feature but from a collection of them,1 and that collection is the book you have just read: namespaces for processes and networking, cgroups for resources, overlayfs for filesystems. Ward closes where he opened — undoing one last sense of the word virtual.1
Một cách đọc chương này là đọc nó như mục lục ngược. Ranh giới nhân / không gian người dùng của Chương 1 là thứ giải thích vì sao container dùng chung một nhân.1 Thiết bị khối và hệ thống tệp của Chương 3 và 4 là thứ quyết định tiêu chí nghiệm thu cho một đĩa ảo.1 init của Chương 6 là lý do PID 1 trong container trông lạ lùng.1 cgroup của Chương 8 là cái quay lại nguyên vẹn trong danh sách bốn khía cạnh của một tiến trình container.138 Và NAT cùng mạng riêng của Chương 9 là thứ dựng nên mạng cầu nối của Docker.1 Nếu một mục nào ở trên khiến bạn ngập ngừng, chương cần đọc lại không phải chương 17.