---
# System prepended metadata

title: 虛擬化技術（一） 硬體虛擬化、Container、KVM、Xen、LXC/LXD、Docker
tags: [LSA2]

---

# 虛擬化技術（一） 硬體虛擬化、Container、KVM、Xen、LXC/LXD、Docker
###### tags: `LSA2` 

[toc]


## 虛擬化從何而來？

- ![](https://i.imgur.com/eKhdkZo.png) 
> [圖片來源](https://www.google.com/url?sa=i&url=https%3A%2F%2Fwww.techtarget.com%2Fsearchitoperations%2Ffeature%2FThe-history-of-virtualization-and-its-mark-on-data-center-management&psig=AOvVaw0XvLfSxsy-ZPetLyToE4uP&ust=1680685114653000&source=images&cd=vfe&ved=0CA8QjRxqFwoTCKjQz43uj_4CFQAAAAAdAAAAABAE)

### 虛擬化的出現

- 20世紀 ~ 60世紀初：
    - 電腦是龐大、速度緩慢且昂貴的產品。
        - 多人共用一台電腦
        - 使用上不方便，且效率低
        - 在等待他們的實驗結果時，經常會有閒置的狀況
    - 產生如果可以讓多人共用電腦資源的想法 - Time Sharing
:::info
### Time Sharing
- 將使用時間分給多位使用者使用
    - 將 cpu 的運作時間分割成很小段的時間去執行不同 process，並不斷在這些小段的時間中切換
    - 一個小時間段約在 0.01 sec ~ 0.1 sec，因此使用者不會感覺到 process 中斷

![](https://i.imgur.com/nlpjUF4.png)
> [圖片來源](https://www.geeksforgeeks.org/time-sharing-operating-system/)
> [參考資料](https://www.geeksforgeeks.org/time-sharing-operating-system/)
:::
- 1964年，IBM設計並推出了CP-40：
    - 第一個使用 Time Sharing 的大型電腦系統
    - 可以支援多個使用者同時使用
- 1974年，由兩位科學家（Gerald Popek和Robert Goldberg）提出 hypervisor 的概念，並將其分為 type 1 和 type 2 兩種類型
### 虛擬化開始進入資訊行業
- 1995 年 Red Hat 發布了使用 Linux kernel 的通用版本操作系統
- 1998年，VMware 成立並發布了第一個支援 x86 架構的作業系統 - VMware Workstation。
:::info
### x86?
- x86 是一種指令集家族，使用 CISC 指令集
- 從最早只有 16 bits（x86-16） 到 32 bits（x86-32）
### x86-64?
- 可以說是 x86 的下一代（x86-64）
    - 使用 64 bit
    - 提升可處理的記憶體大小且不影響性能
    - 具有向後（向下）兼容特性，因此 32 bits 及 64 bits 皆可處理

### x86-32 v.s. x86-64


|                    | x86-32                        | x86-64                            |
| ------------------ | -------------------------- | ------------------------------ |
| Bits                | 32                         | 64                             |
| 可支援最大記憶體 | 4 GB (實際可用約為 3.2 GB) | 16 EB（ 1EB = 1000TB）|
| 運算速度           | 較慢                       | 較快（快一倍）                 |
> Reference:
> [x86 v.s. x64](https://phoenixnap.com/kb/x64-vs-x86)
> [x86-64](https://zh.wikipedia.org/wiki/X86-64)
:::
:::info
### 指令集 Instruction Set Architecture (ISA)
- cpu 的語言，定義了軟體如何控制 cpu
- ![](https://i.imgur.com/PbH5OTh.png)
> [圖片來源](https://zh.wikipedia.org/zh-tw/%E6%8C%87%E4%BB%A4%E9%9B%86%E6%9E%B6%E6%A7%8B)
#### CISC and RISC
- 指令集分為兩大類
1. 複雜指令集（Complex Instruction Set Computer, CISC）
    - 再執行一項工作時只需一道指令
    - ex: 就像一位大廚，具備多項技能，因此可以獨立完成一道佳餚
    - ex: x86，如今大多數電腦仍使用複雜指令集
    - 優點:
        - 因單一指令就可完成工作，工程師使用上較方便
    - 缺點：
        - 每條指令長度不一，因此電腦判讀時需多花費效能（產生較多的效能消耗）

2. 精簡指令集（Reduced instruction set computer，RISC）
    - 由多個簡單的指令組合來完成工作，就像工廠中的流水線一樣
    - ex: 像是一群各會不同技術的廚房助手，一起共同完成一道佳餚
    - ex: ARM、MIPS、RISC-V 指令集，多用於手機、平板等行動裝置
    - 優點：
        - 指令長度一致，方便讀取，因此速度快，效率高且省電
    - 缺點：
        - 工程師在開發及編譯時較費工 
>[Instruction Set Architecture (ISA)](https://www.arm.com/glossary/isa)
:::
### 虛擬化的熱潮
- 虛擬化技術於 2000 年代開始引起熱潮，許多虛擬化相關公司陸續成立，例如 VMware、Red Hat、IBM、以及 Citrix Systems 等
- 管理員可以依據不同的服務和軟體來虛擬化他們的資料中心和硬體，例如虛擬 CPU 和記憶體等
- 2001 年，VMware 發布了 ESX 1.0 Server，使用 Type 1 hypervisor 的作業系統
- 2003 年，Xen 發布，使用半虛擬化技術
- 2008 年，Microsoft 推出 Hyper-V，協助管理員在 Windows x64 和 x86 系統上安裝虛擬機器
- 2013 年，Docker 發布，採用容器的概念，改變了傳統虛擬化的方式
 
> References：
> [1. The history of virtualization and its mark on data center management](https://www.techtarget.com/searchitoperations/feature/The-history-of-virtualization-and-its-mark-on-data-center-management)
> [2. History of VMware: Evolution Timeline](https://nakivo.medium.com/history-of-vmware-evolution-timeline-6173482c6d21)
> [3. A brief history of virtualization, or why do we divide something at all](https://www.ispsystem.com/news/brief-history-of-virtualization)
> [4. 虛擬化簡介](https://www.cc.ntu.edu.tw/chinese/epaper/0004/20080320_4012.htm)
## 為什麼需要虛擬化 
### 早期 / 傳統架構
- 早期時，電腦及相關硬體資源都十分昂貴，
    - 一台電腦只能使用一個作業系統 
    - 需要具備多個伺服器才能運行所有的作業系統
    - ⇨ 需要花費大量的成本
<br>
    - ![](https://i.imgur.com/ac8QmQw.png)
    >[圖片來源](https://www.alibabacloud.com/tc/knowledge/what-is-virtualization) + 自行修改

- 傳統架構
    - 由作業系統（OS）管理整台主機的運算資源
    - 應用程式需要運算資源
        - 應用程式 ⇨ 作業系統 ⇨ 主機
    - 使作業系統同時要掌硬體溝通及掌握資源的分配
<br>
    - ![](https://i.imgur.com/Gl1k4EX.png)
    > [圖片來源](https://www.digihunch.com/2020/07/overview-of-virtualization/) + 自行修改
### 虛擬化 / 虛擬架構
- 如果我們使用虛擬化技術
    - 可以在單個實體伺服器（電腦）上運行多個作業系統
    - ⇨ 節省時間與金錢
<br>
    - ![](https://i.imgur.com/8fZNdVo.png)
    >[圖片來源](https://www.alibabacloud.com/tc/knowledge/what-is-virtualization) + 自行修改
- 虛擬架構
    - 架構上有所改變被替代或多了一層虛擬化層(hypervisor)
        - hypervisor 以軟體的方式呈現
        - 使用虛擬架構後，可建立多個虛擬環境使用不同作業系統
        - 幫助電腦提高資源利用率
- tpye 1（右圖）
    - 將 os 及 hypervisor 整合在一起作為 host os 使用，並完成原先作業系統的工作
    - 呼叫流程：
        - Guest OS ⇨ hypervisor（幫忙分配主機運算資源） ⇨ 硬體
- type 2（左圖）
    - 依據需求可以在 guest 及 host os 間加入 hypervisor
    - 呼叫流程: Guest OS ⇨ Hypervisor ⇨ Host OS ⇨ 硬體

- ![](https://i.imgur.com/Fahn4Bw.png)

> [圖片來源](https://vgyan.in/type-1-and-type-2-hypervisor/) 

> Reference:
>[1. 為什麼要做虛擬化?](https://ithelp.ithome.com.tw/articles/10289701?sc=iThelpR)
> [2. 什麼是虛擬化？](https://aws.amazon.com/tw/what-is/virtualization/)
> [3. 何謂虛擬化？](https://www.alibabacloud.com/tc/knowledge/what-is-virtualization)
> [4. Virtualization 1 of 4 – Hypervisor](https://www.digihunch.com/2020/07/overview-of-virtualization/)

## 什麼是虛擬化？
- 將實體的資源進行抽象化處理（像是 CPU、記憶體、磁碟空間、網路卡等等）
- 在原先電腦中可在建立多個獨立的虛擬機、虛擬環境（VM）
- ![](https://i.imgur.com/n9aPdaR.png)
> [圖片來源](https://www.google.com/url?sa=i&url=https%3A%2F%2Fwww.digitimes.com.tw%2Ftech%2Fdt%2Fn%2Fshwnws.asp%3Fid%3D0000148576_5WO43U548HS9DA50U6ILF&psig=AOvVaw35TW5F_xzDb5HSkZduNooJ&ust=1680685345259000&source=images&cd=vfe&ved=0CA8QjRxqFwoTCOCrmfnuj_4CFQAAAAAdAAAAABAE)
- 對開發者而言：
    - 模擬獨立的操作系統、硬體和網路環境，在不同的平台上進行應用程式開發和測試，而無需實際擁有這些平台
    - 幫助開發者更輕鬆地設計及部署應用程式
    - 虛擬化可提供一個安全的環境，幫助開發者測試應用程式和系統配置，而不會影響到本身電腦的作業系統
    - 
- ![](https://i.imgur.com/UkzpuIL.png)
> [圖片來源](https://www.google.com/url?sa=i&url=https%3A%2F%2Fwww.digitimes.com.tw%2Ftech%2Fdt%2Fn%2Fshwnws.asp%3Fid%3D0000148576_5WO43U548HS9DA50U6ILF&psig=AOvVaw35TW5F_xzDb5HSkZduNooJ&ust=1680685345259000&source=images&cd=vfe&ved=0CA8QjRxqFwoTCOCrmfnuj_4CFQAAAAAdAAAAABAE) 
- 對使用者而言：
    - 可以在單一實體電腦中建立多個虛擬環境，每個虛擬環境都可以運行不同的作業系統
        - 可將單一系統拆成數個各自獨立、獨特且安全的環境
    - 這種技術可以讓使用者更有效地利用硬體資源
        - 可幫助將機器資源從硬體上分離出來並妥善分配
- 虛擬化中的各個名稱：
    - 實體硬體：「主體」（host）
    - 使用 host 資源的眾多虛擬機器：「客體」（guest）
    - 運算資源：CPU、記憶體和儲存空間 
        - 作業人員可控制 CPU、記憶體、儲存空間和其它資源
        - 提供 guest 所需的資源。
    - 應用程式、伺服器：軟體形式（虛擬形式）
## 虛擬化的優缺點
### 優點
1. 👍 降低成本
    - 購買新伺服器或儲存設備的費用 ⇩
    - 作業系統管理需求 ⇩
    - 維護成本 ⇩
    - 伺服器作業成本 ⇩
2. 👍 提高資源利用率
    - 可在一個實體電腦建立多個虛擬環境，使用多種作業系統，並最大限度地利用硬體資源
    - 從使用單一實體伺服器變成使用多個虛擬伺服器
    - 資源使用效率更好、更靈活
3. 👍 配置與部屬較輕鬆
    - 可快速架設虛擬環境，並依照需求進行不同設定
    - 修復彈性高，使用虛擬化技術可較方便的實時備份數據資料，如果搭配好的備份，可以快速修復回需要的狀態
4. 👍 安全性較高
    - 當其中一個虛擬環境當機或出現問題時，不會影響到其他虛擬環境或主機本身
    - 可以利用虛擬環境去測試檔案、軟體使否安全
5. 👍 集中管理
    - 伺服器數量 ⇩ 管理員負擔 ⇩
    - 簡化架構管理流程
6. 👍 環保（綠色效益）
    - 減少能源消耗
        - ex: 微軟將1995台實驗室伺服器，透過虛擬化的方式整合成149台，節約了將近九成的電源，也因此節省了佔地面積
### 缺點
1. 👎 前期實施成本高昂
    - 開發、製造或購買硬體、軟體設備
2. 👎 架構複雜
    - 當有問題需要排查時，需一個個確認，比物理伺服器難解決
    - 確認工作增加
        - ex: 我在關機實體電腦前還要先確認我的虛擬機關機了沒
3. 👎 性能影響
    - 虛擬環境中，需要透過 Hypervisor 才能完成請求
    - 步驟增加，性能有所損耗
> [1. 虛擬化有何好處？](https://www.redhat.com/zh-tw/topics/virtualization#%E6%9C%89%E5%93%AA%E4%BA%9B%E7%94%A8%E9%80%94)
> [2. 虛擬化能夠提供什麼好處？](https://aws.amazon.com/tw/what-is/virtualization/)
> [3. 虛擬化的優勢](https://www.vmware.com/tw/solutions/virtualization.html)
## 虛擬化如何運作
### 虛擬化方法
- ![](https://i.imgur.com/cTjHN07.png)
> [圖片來源](https://www.google.com/url?sa=i&url=https%3A%2F%2Fkopu.chat%2F%25E9%259B%25B2%25E7%25AB%25AF%25E9%2581%258B%25E7%25AE%2597%25E7%259A%2584%25E9%2597%259C%25E9%258D%25B5%25E5%259F%25BA%25E7%25A4%258E%25EF%25BC%259A%25E8%2599%259B%25E6%2593%25AC%25E6%25A9%259F%2F&psig=AOvVaw3y6uWq7BhEED0mJ3i-n6Ev&ust=1680767252322000&source=images&cd=vfe&ved=0CBAQjRxqFwoTCIjC-4mgkv4CFQAAAAAdAAAAABAJ)

1. 確認 cpu 是否可以支援虛擬化指令
    - 如果可以支援：使用上速度較快
    - 如果不能支援：還是可以使用虛擬化，但速度會較慢
2. 進入 BIOS 開啟 VT (Virtualization technology)
    - 將電腦重新開機，再開機過程中按 `F2` 或 `Delect` 進入 BIOS
    - 找到 `Advanced Mode(F7)` 並點擊
    ![](https://i.imgur.com/ypWK56U.jpg)
    - 找到 `Advanced` 並點擊
    ![](https://i.imgur.com/2FKvgpo.jpg)
    - 點擊 `cpu configuration` 選擇 cpu 
    ![](https://i.imgur.com/azT0SsV.jpg)
    - 將虛擬化技術的 `disabled` 改為 `enbled` 開啟 VT 功能
    ![](https://i.imgur.com/o2JlqZT.jpg)
    - 將改變的設定儲存並重新開機
    ![](https://i.imgur.com/ePbxvBC.jpg)
    > [圖片來源](https://blog.csdn.net/weixin_45156610/article/details/117415309)
    - 完成設定就可安裝虛擬機
        - 電腦：Host、虛擬機：Guest
            - Guest 可同時在 Host 上執行，且具有自己的作業系統
            - 作業系統可與 Host 作業系統相同，也可不同 

- ![](https://i.imgur.com/wmbwY6Z.png)
> [圖片來源](https://www.google.com/url?sa=i&url=https%3A%2F%2Fwww.cc.ntu.edu.tw%2Fchinese%2Fepaper%2F0057%2F20210620_5709.html&psig=AOvVaw3d5RoTrp0kU0ycpJpyvICS&ust=1680101628393000&source=images&cd=vfe&ved=0CBAQjRxqFwoTCNC9hLjw_v0CFQAAAAAdAAAAABAE)
:::info
### BIOS (Basic Input/Output System)
- BIOS 是位於電腦主機板上的一個程式，是個簡單的操作系統，用於控制硬體的基本操作
- BIOS 是啟動電腦時運作的第一個軟體程式，BIOS 會測試硬體以確保一切正常
- BIOS 主要的任務：在啟動前測試電腦、初始化和識別系統硬體、加載作業系統以及提供運行時服務
- ![](https://i.imgur.com/iRWud9s.png)
> [圖片來源](https://tw.easeus.com/diskmanager/what-is-bios.html)
> [What is BIOS](它是存在於電腦主機板上的一個程式，用於在開機時初始化和測試電腦硬體，並協助作業系統載入並運行。BIOS是一個簡單的操作系統，用於在電腦上控制硬體的基本操作。)
:::
> Reference:
> [虛擬化如何運作？](https://aws.amazon.com/tw/what-is/virtualization/)
> [虛擬化的運作方式](https://www.vmware.com/tw/solutions/virtualization.html)
> [Bios](https://m.facebook.com/nt/screen/?params=%7B%22note_id%22%3A342388213716578%7D&path=%2Fnotes%2Fnote%2F&refsrc=deprecated)
## 虛擬化應用
- 虛擬化技術依照物件分類主要分為四種類型: 伺服器虛擬化、網路虛擬化、儲存虛擬化、桌面虛擬化
### 伺服器虛擬化（Server Virtualization）
- ![](https://i.imgur.com/hg3LT9L.png)
- 伺服器虛擬化是一種將一台實體伺服器分割成多個虛擬伺服器的技術，且每個虛擬伺服器都運行著獨立的操作系統和應用程式
- 使用率高，超過 90% 的企業已經使用虛擬伺服器來代替物理伺服器
    - 共享 CPU、記憶體、儲存和網路功能
- 優點：
    - 更好地劃分資源：如此可以降低營運成本，並擁有更好的應用程式性能
    - 更快的部署時間：系統管理員可快速添加更多虛擬機，並減少購買新物理伺服器的時間和成本
    - 可實現冗餘
    - 方便遷移：因不需依賴於物理硬體，虛擬伺服器可在不同的物理伺服器之間移動，且不影響到應用程式或使用者
- 缺點
    - 性能損耗：會有處理能力減弱、速度變慢等狀況，引此不適合對處理能力有高要求的應用程式的服務器
:::info
### 冗餘
- 確保系統能夠在發生故障或組件故障時維持運行
- ![](https://i.imgur.com/lCVNhu2.png)
> [圖片來源](https://www.linkedin.com/pulse/virtualization-redundancy-options-gloria-e-ram%C3%ADrez)
:::

### 網路虛擬化 (Network Virtualization)
- ![](https://i.imgur.com/awwYfkh.png)
- 將一個物理網路基礎架構轉換為虛擬網路，融合物理網路和虛擬網路的元素，如網路帶寬、交換機、路由器和防火牆等，分配為多個虛擬網路，以便更好地管理和控制網路資源
- 網路硬體只需負責轉發數據封包 (data packet)，虛擬網路負責部署和管理網路服務
- 由 SDN 控制器管理，可隨時根據使用者需求更改虛擬網路的配置、分配和釋放網路資源
- 盛行於電信行業
- 優點：
    - 節省需多空間
    - 改善網路資源使用效率及使用彈性：可以自動檢測故障，並迅速切換到另一個可用的網絡資源
    - 降低運維成本
    - 提高網路安全性：虛擬網路間為相互隔離，因此駭客無法直接訪問另一個虛擬網路中的資源
- 缺點：
    - 性能問題：需共享有限的物理資源，如CPU、記憶體和網路頻寬，可能導致網路擁塞和延遲
    - 管理複雜性：網路虛擬化需具備更複雜的管理和配置來確保虛擬網路正確運作
:::info
### SDN
:::
### 儲存虛擬化（Storage Virtualization）
- ![](https://i.imgur.com/N9OFIHl.png)
- 通過軟體方式將儲存硬體資源抽象化（例如硬碟），且將多個實體儲存設備集合匯聚成一個，並統一由中央進行管理控制
    - 將其功能與附加的功能進行整合，再統一對使用者提供資料儲存服務
- 儲存虛擬化有兩種：內部及外部的
    - 內部儲存虛擬化只能在供應商的軟體中使用，限制了數據的範圍
    - 外部存儲虛擬化通常也由供應商提供，但對提取和儲存數據的限制較少
- 優點:
    - 降低管理成本：數據的儲存與管理越來越難，透過存儲虛擬化來集中管理減少備份、歸檔和恢復所消耗的時間
    - 擴展存儲容量且有效利用儲存：
### 桌面虛擬化(Desktop Virtualization)
- ![](https://i.imgur.com/d3DifdF.png)
- 模擬將使用者的工作站虛擬化
- 可以從遠程連接的設備訪問，允許使用者在任何有網絡的地方工
    - ex: 用手機遠程控制在家裡的電腦、遠距工作時可操作辦公室的電腦
- 優點：
    - 較好的資源利用
    - 遠程勞動力支援
    - 更好的安全性：因工作環境被隔離在虛擬機中，因此可以更好地保護敏感資料和應用程式，並防止惡意攻擊
- 缺點：
    - 性能損耗：因運作在虛擬機中，因此會產生性能有所損耗
    - 依賴伺服器與網路：如果伺服器或網路故障，可能會無法使用
> https://www.cc.ntu.edu.tw/chinese/epaper/0057/20210620_5709.html
> https://www.vmware.com/tw/topics/glossary/content/server-virtualization.html
## 虛擬化安全
### 虛擬化安全的重要性
- 虛擬化安全指的是虛擬化架構的安全措施，防止惡意攻擊或其他未經授權的存取
- 由於虛擬術可同時運行多個虛擬機，共享硬體資源，因此也帶來安全風險
- Hypervisor 尤其需要被保護，因其管理上層虛擬機及分配資源，十分重要
    - 一旦被駭客入侵，駭客將對上層虛擬機中的任何使用者行為會被一覽無遺，
    - 被入侵即可能擁有所有 VM 和其中作業系統的控制權
    - 且很難檢測到可疑活動
    - 要特別檢視跟重視 hypervisor 的安全性
- ![](https://i.imgur.com/yaS0IVv.png)
> [圖片來源](https://www.google.com/url?sa=i&url=https%3A%2F%2Ftoutiao.io%2Fposts%2F6tqr99%2Fpreview&psig=AOvVaw0DwaO1BulQY72kZ_xJzCBU&ust=1680769389843000&source=images&cd=vfe&ved=0CBAQjRxqFwoTCODhwsyokv4CFQAAAAAdAAAAABAD)
- 主機安全性
    - 至關重要
    - 主機上方具有多台虛擬機並且與他們共享資源
        - ex: 實體主機裝置、儲存裝置、網路存取、虛擬客機
    - 假如主機系統被攻擊駭入，Host、及 Guest 其中的資料皆會被侵入
- 客機安全性
    - 同樣重要
    - 客機存有許多重要資料
        - ex: 重要的企業資料或敏感的客戶資訊
- 複雜的架構及環境：host 和 guest 之間建立一層虛擬化軟體，並對 guest 進行管理、控制、分配資源等，加上涉及到多種不同的技術和工具，如虛擬機監控、虛擬網絡、虛擬儲存等
    - 系統難以管理及維護
    - 因儲存裝置等資源散佈各處，且仰賴多台機器
    - 增加安全風險，駭客會在架構中尋找弱點攻擊
### 虛擬化安全策略 / 建議
- 嚴格控制存取權限：只有授權使用者才能存取虛擬機器和虛擬化環境。可以通過使用身份驗證和授權機制來實現這一點
- 監控虛擬環境：要定期監控虛擬環境中的資源和虛擬機器，及時發現任何異常活動或未經授權的存取。
- 分割虛擬環境：將虛擬環境分割成多個區域，每個區域只運行一個虛擬機器，以減少攻擊的影響範圍。
- 加密敏感資料：對存儲在虛擬機器中的敏感資料進行加密，以保護其不被未經授權的存取。
- 更新虛擬化軟體：定期更新虛擬化軟體，以修復任何已知的漏洞和安全問題。
- 每個部分都有做好安全措施：虛擬化的安全程度取決於每一個個別組件的安全性，因此每台虛擬機上皆執行與安全相關的設定和程式才有辦法維持整體安全
    - ex: 管理程式、伺服器主機和主機作業系統、guest 作業系統、應用程式和存儲設備或系統

### 為什麼虛擬化後 hypervisopr 那麼容易被針對攻擊還要使用虛擬化技術？
- 虛擬化利大於弊
    - 可測試性：可以使用一個虛擬環境去測試是否檔案安全性，避免後續被駭入的問題
    - ex: sandbox (沙盒)
- 虛擬化技術帶來的便利性以無可替代
- 本身虛擬化後的安全性會比傳統架構安全，做好安全策略保護好 hypervisor
> 參考資料
> [為什麼虛擬化安全至關重要？](https://access.redhat.com/documentation/zh-tw/red_hat_enterprise_linux/7/html/virtualization_security_guide/sect-virtualization_security_guide-introduction-why_virtualization_security_matters)
> [虛擬化安全的挑戰](https://www.cc.ntu.edu.tw/chinese/epaper/0057/20210620_5709.html)
> [Virtualization security](https://www.liquidweb.com/blog/virtualization-security/)
## CPU 特權指令
- ![](https://i.imgur.com/bJDWpgG.png)
> [圖片來源](https://www.baeldung.com/cs/os-rings)
- 被稱為保護環（Protection Rings）或 CPU 環（CPU Rings）
- 一種用來保護資料和避免惡意行為的機制
    - 發生故障時可以保護數據
    - 提升容錯度
    - 避免惡意操作
    - 提升電腦安全性
- 分為四個環，Ring 0, 1, 2, 3
    - Ring 0: 權限最高
        - 通常為 kernal 模式: 可直接與 Kernel 溝通，可執行最核心的作業系統功能，控制實體主機硬體的所有資源，ex：處理器、記憶體
        - 操作系统：需要運行在 Ring 0 才能存取和控制所有的硬體和軟體資源，執行內存管理、進程管理、設備驅動程式等最核心的操作系统功能
        - 虛擬化：如要虛擬化，需要 Ring 0 才能存取和控制虛擬機器中的所有硬體和軟體資源，再進一步實現虛擬機器的操作系统和應用程式
    - Ring 1 and Ring 2:
        - 具有 Ring 0、3 沒有的特性：可以直接訪問應用程式和驅動程式，且不需要擁有作業系統 kernal 的所有權限
        - 輸出及輸入的權限
        - Ring 1 可以處理一些對作業系統的緊急需求，ex: 在系統崩潰時執行硬體重建
        - Ring 2 想比 Ring 1 權限更低，主要負責執行一些安全軟體，跟系統儲存、裝載、保存文件等工作
        - ex of Ring 1: 
            - 中斷處理：當發生中斷時，作業系統必須立即停止正在執行的任務，並為中斷處理程式提供存取系統資源的權限（Ring 1）以處理中斷事件，保護 kernal 的作業並控制資源的存取
        - ex of Ring 2: 
            - 將 excel 檔案從 storage 中 loading 出來
            - 當要使用防火牆軟體的時候，會由 Ring 2 運作
    - Ring 3: 權限最低
        - 使用者模式，不能直接存取硬體的相關資源
        - 操作 Application 相關
- cpu 會將 Rings 的模板設置好，但是實際要執行什麼會由 os 來決定
- 當 user 需要使用系統服務時（ex I/O 設備），會發送 trap，將 user mode 轉成 kernal mode
- 如果有特權比較低的 Ring 嘗試訪問特權高的 Ring 時，會向作業系統報告，並終止動作
- 當 ring 3 試圖做跟 kernal 相關的動作時或有發生錯誤時，cpu 會發出 trap
-  ![](https://i.imgur.com/tJaPULJ.png)

> [圖片來源]
:::info
### trap（中斷）
- trap 可以用來改變 CPU 執行程式的流程，當 CPU 在 user mode 執行一個程式時，能夠及時地將其暫停，並切換到 kernal mode 中
### syscall
- 當 user 向 os 發出執行特權指令的請求，由 syscall 發出中斷訊號將操作從 user mode 轉向 kernal mode
- 與 trap 不同的是由 program 自己主動請求
> 參考資料：
> [trap and syscall](https://www.geeksforgeeks.org/traps-and-system-calls-in-operating-system-os/)
:::
> 參考資料
> [What is cpu rings](https://www.baeldung.com/cs/os-rings)
> [CPU rings](https://www.geeksforgeeks.org/protection-ring/)
## 虛擬化層級
![](https://i.imgur.com/Bc1wszZ.png)
### 硬體抽象層等級的虛擬化（Hardware Abstraction Level）
- ![](https://i.imgur.com/HYkiAGQ.png)
- 硬體層面上實現的虛擬化技術
- 基於虛擬機的 CPU 硬體指令集一般與原主機實際 CPU 硬體指令集非常相似
- 硬體虛擬化可以將虛擬機的大多數操作指令通過映射方式(hypercall)在主機上直接執行
- 但需要硬體本身有提供相對的技術來支援虛擬化
    - Intel VT and AMD-V
:::info
### Intel VT and AMD-V
#### Intel VT (Intel Virtualization Technology)
- 支援 Intel 的虛擬化技術
- 為了解決 Intel 虛擬化的安全性及性能不足
- 讓一個 CPU 運作時像多個 CPU 同時運作
    - 使一部電腦可同時運作多個作業系統

#### AMD-V (AMD Virtualization)
- 是一種針對 x-86 的硬體虛擬化輔助技術
- 為了使 Hypervisor 可以充分利用資源及提高虛擬化效率等
:::
#### 優點
- 簡單
- 提高硬體資源利用率：HAL 層可以通過管理硬體的訪問和防止軟體及應用程式之間的衝突來加強硬件資源的使用
- 無論硬件架構如何，都能使作業系統正常運行
#### 缺點
- 能虛擬的硬體平台範圍有限，且可能需要硬體對虛擬化的支援
#### 代表軟體有
- Xen
    - 使用半虛擬化技術來提升效能
    - 可以在不停止的情況下在多個物理主機之間即時遷移
- KVM
    - Kernel-based Virtual Machine
    - 現在屬於 Linux 核心架構下的一部分，且具備虛擬化的功能，可將 Linux kernel 轉化為一個 virtual machine monitor
    - 例如：CPU(Intel VT 或 AMD-V)

- KVM 內的虛擬電腦，主要分為兩大部份
    - 第一種：
        - CPU 與記憶體的運作，並提高運算效能與速度
    - 第二種：
        - 週邊裝置的連結
        - 透過 QEMU 這個虛擬系統套件來控制。
        - ![](https://i.imgur.com/ITquepI.png)
        > [圖片來源](https://www.google.com/url?sa=i&url=https%3A%2F%2Fwww.polarsparc.com%2Fxhtml%2FLinux-KVM.html&psig=AOvVaw37RGssnbu9WFqEtSkPf1e2&ust=1680776780908000&source=images&cd=vfe&ved=0CBAQjRxqFwoTCMirvcnDkv4CFQAAAAAdAAAAABAh)
- KVM 可以達到快速且大量的虛擬系統平台，
    - 可輕鬆架構自有的雲端服務
    - 輕鬆備份
    - 快速移機與異地備援
### 指令集架構等級的虛擬化（Instruction Set Architecture Level）
- 處理器的一部分
- 只有程式設計師或 compiler writer 可以看見
- 是通過純軟體的方式模擬各種不同 CPU 硬體的指令集

#### 優點
- 可以完全的模擬出所需要虛擬設備的所有特性
#### 缺點
- 性能太差，而且實現複雜
#### 代表軟體
- QEMU
    - quick emulator
    - 是模擬處理器的自由軟體
    - 通常用來模擬一些不存在的硬體裝置
    - 由軟體模擬 CPU，處理 Guest 的硬體請求，並由其轉譯給真正的硬體。
    - 因為 QEMU 是純軟體實現的，所有的指令都要經過 QEMU ，使得效能很差 (配合 KVM 則可以解決這一問題。)
###  作業系統等級的虛擬化（Operating System Level）
- 作業系統的核心允許多個獨立的使用者空間（創建一些容器），將 os kernal 虛擬化，使 Container 可以共用同一個 host os
- 可以安全且有效的分配大量不互相信任的使用者資源
- 資源和性能損耗比較小，因為不需要有多層轉譯
#### 代表
- LXC(Linux 容器)
- Docker
### 函式庫等級的虛擬化（Library Level）
-  大部分應用程式使用許多函式庫組成的 API（Application Programming Interface）來設計
- 函式庫虛擬化後，可以使用不同系統編譯的檔案
#### 代表
- Wine 
    - 一種在類 Unix 系統上執行 Windows 程式
    - 全名：Wine Is Not an Emulator
    - 可以在 Linux, BSD (UNIX like) , MacOS 中執行 windows 的執行檔(.exe)
    - 利用黑箱測試法並參照開發文件，來實做所有的 Win32 APIs
:::info
### 白箱與黑箱測試法
#### 白箱測試法（white-box testing）
- 模擬使用者操作的方式去測試軟體
    - ex:
    1. 使用者選擇商品成立一筆訂單
    2. 在單據內填寫設定相關必填資料後完成訂單
    3. 完成訂單後再進行線上繳款動作
    4. 成功完成線上繳款交易等模擬測試
- 測試系統是否出現無回應狀態、以及不可出現例外錯誤，當出現錯誤時需停止測試，將相關問題回報給開發人員進行修正及調整，調整完成再進行測試
- **測試人員知道測試目標在哪**，並模擬使用者的操作情境，嘗試找出使用者操作時會遇到的問題
### 黑箱測試法（black-box testing）
- 模擬駭客去測試軟體
    - ex:
    1. 使用線上訂單系統進行測試時，輸入商品數量的極大值或極小值
    2. 在單據內在填寫相關欄位資料時，填寫錯誤格式資料
- 測試這些駭客操作是否會影響系統穩定性與安全性，當會時，需請開發人員進行修正與調整
:::
### 應用程式等級的虛擬化（Application Level）
- 將高階語言轉譯成一種名為 bytecode 的語言，透過虛擬機器 compile 成為可以直接執行的命令
:::info
### Bytecode（字節碼）
- 是一種介於機器語言和高級語言之間的中間語言。它是一種以二進制形式表示的中間語言，可以在不同的平台上運行
:::
- 允許使用者從安裝應用程式的電腦外的另一台電腦訪問和使用應用程式
- ![](https://i.imgur.com/dnVFVgR.png)
> [圖片來源](https://www.google.com/url?sa=i&url=https%3A%2F%2Ftechvidvan.com%2Ftutorials%2Fjava-virtual-machine%2F&psig=AOvVaw3AgKhUWi7e3njwp6K6Ha2v&ust=1680784737182000&source=images&cd=vfe&ved=0CBAQjRxqFwoTCLDxy5vhkv4CFQAAAAAdAAAAABAE)
- 一個欺騙應用程式的過程
    - 讓沒有安裝此應用程式的系統，誤以爲已經安裝了
- ![](https://i.imgur.com/zPzy15r.png)
> [圖片來源](https://en.wikipedia.org/wiki/Application_virtualization)
#### 優點
- 跨作業系統平台
- 跨語言
- 簡化管理
- 較安全
#### 代表
- Oracle Java
- Parrot virtual machine
    - It can efficiently compile and execute bytecode for dynamic languages. 
    - Parrot currently hosts a variety of language implementations in various stages of completion, 
        - including Tcl, Javascript, Ruby, Lua, Scheme, PHP, Python, Perl 6, APL, and a .NET bytecode translator
- ![](https://i.imgur.com/I75bg26.png)
> [圖片來源](http://www.parrot.org/)

> http://dns2.asia.edu.tw/~jdwang/TeachingCourses/Virtualization/Part1-_.pdf
## 虛擬化類型
### 全虛擬化（Full virtualization, FV）
- ![](https://i.imgur.com/vae5NkY.png)
- 完全虛擬出一個主機所需要的所有環境
- 透過軟體來模擬
- 對於運行於其上的虛擬機來說，感覺不到 Hypervisor，因此是對 Guest OS 的支援類型最廣泛的一種
- hypervisor 在 guest 和硬體之間用於工作協調，讓虛擬機感覺像實體機一般地完全自由的操作，一些受保護的指令必須由 Hypervisor 來捕獲和處理
- 權限被降成 Ring 1，guest OS 運作在 Ring 1
- 但 Hypervisor 接受 Guest OS kernel 指令必須做動態指令碼轉譯 (Dynamic Binary Translation) 成為 CPU 可以解碼執行的模擬指令
- ![](https://i.imgur.com/hjT5xoP.png)
> [圖片來源](https://www.geeksforgeeks.org/difference-between-full-virtualization-and-paravirtualization/)

### 半虛擬化（Para‐Virtualization, PV）
- ![](https://i.imgur.com/La9H56f.png) 
- 為改善 FV 的缺點：效能損耗
- hypervisor 只虛擬化 CPU 及 Memory 
- 虛擬機的操作指令直接給 hypervisor 執行，減少中間轉換造成的性能損失和時間延遲（修改 Guest OS 程式，增加hypercall 強迫呼叫 hypervisor）
- 權限維持 Ring 0
- 性能接近真實系統
- ![](https://i.imgur.com/Ym7V3ZM.png)
> [圖片來源](https://www.geeksforgeeks.org/difference-between-full-virtualization-and-paravirtualization/)

:::info
### Hypercall
- ![](https://i.imgur.com/cZH05Gk.png)
> [圖片來源](https://www.cnblogs.com/echo1937/p/7227385.html)
- 使用 Hypercall 會將 Guest OS 的部分程式碼改變，使其會將跟特權指令相關的資訊傳給 Hypervisor 中的 Hypercall，再經由 Hypercall 轉換成 Hypervisor 可以執行的指令，再向 Hardware 索取資源
- 避免因為虛擬化而將 CPU rings 調降到 Ring 1，使其可保持在Ring 0
- 也避免虛擬化執行衝突的問題
:::
### 硬體輔助虛擬化（Hardware-Assisted Virtualization）
- ![](https://i.imgur.com/rK5XYJR.png)
- 硬體支援：硬體虛擬化技術與 hypervisor 結合可以極大地提高虛擬化的效率
![](https://i.imgur.com/dhrLMhY.png)
> [圖片來源](https://www.google.com/url?sa=i&url=https%3A%2F%2Fnetworksandservers.blogspot.com%2F2011%2F11%2Fhardware-assisted-virtualization-was.html&psig=AOvVaw16g5EZQYrqarnuRX1fQzlP&ust=1681208290944000&source=images&cd=vfe&ved=0CBEQjRxqFwoTCJixzImLn_4CFQAAAAAdAAAAABAf)
- 將原本Ring 0、1、2、3層歸類為 Non-Root Mode，並新增 Root Mode，並將作業系統維持在原 Ring 0
    - Guest OS運行於Ring 0。
- Hypervisor 調整到 Root Mode 等級（Ring -1），使 Hypervisor 和 Guest OS 分別運行在 ROOT 和 Non-ROOT 模式，
- Guest OS 的指令可以直接下令電腦系統的硬體執行，不需要透過 Hypervisor，當 Guest OS 執行特殊指令時，系統會切換到 Hypervisor，讓 Hypervisor 來處理特殊指令
- Hypervisor 運行在 Root Mode 的 Ring 0，Guest OS 的運行在 Non-Root Mode 的 Ring 0，Guest OS 的應用程式運行在 Non-Root Mode 的 Ring 3
- ![](https://i.imgur.com/FrJ1ueo.png)
> [圖片來源](https://www.lib.ncku.edu.tw/journal/pdf/29/29_02.pdf)
### FV vs PV vs HVM

|   |   FV  |  PV                          |  HVM             |
|:------------------:|:------------------:|:----------------------------------------------------:|:---------------------------:|
|   怎麼處理特權指令   | Binary translation | 修改 kernel 及使用 hypercall | 新增一個 root mode 特權等級 |
| 怎麼執行 CPU 指令 |        軟體        |                         軟體                         |            硬體             |
|      效能    |        👎🏿        |                          👍                          |             👍              |
|   OS 相容性    |         👍         |                         👎🏿                         |             👍              |
## DEMO of QEMU-KVM
::: info
### QEMU
- QEMU 等於是一個 Hypervisor，可以用來模擬 CPU
- Guest os 會誤以為是直接跟 Hardware 交流，但其實是跟 QEMU 模擬出來的 Hardware 交流，接著 QEMU再將這些指令轉給真正的 Hardware
- ![](https://i.imgur.com/VLcxuIY.png)
> [圖片來源](https://www.google.com/url?sa=i&url=https%3A%2F%2Fcloudzy.com%2Fblog%2Fqemu-vs-kvm%2F&psig=AOvVaw0VMXI0YTRf8R9kisvaUWeb&ust=1680778210192000&source=images&cd=vfe&ved=0CBAQjRxqFwoTCLif-fLIkv4CFQAAAAAdAAAAABAE)
### QEMU_KVM
- KVM 通常負責 cpu 虛擬化 + 記憶體虛擬化實現了，但 KVM 無法模擬其他設備
- 使用 QEMU 操作使用者空間，模擬 IO 設備（網路卡，磁碟等），以及模擬虛擬設備（Network, Disk）並進行管理
- 組合兩者形成 QEMU-KVM
- QEMU-KVM 中：
    - KVM 為 kernel 空間，
    - QEMU 為使用者空間
![](https://i.imgur.com/MjiFC70.png)
> [圖片來源](https://www.google.com/url?sa=i&url=https%3A%2F%2Fhuangwei.me%2Fwiki%2Ftech_cloud_kvm_qemu_libvirt_openstack.html&psig=AOvVaw3ao0Lb52GbYq35kmDqgIFZ&ust=1681207238946000&source=images&cd=vfe&ved=0CBEQjRxqFwoTCJjNnJSHn_4CFQAAAAAdAAAAABAE)
### libvirt
- ![](https://i.imgur.com/Q58iKA1.jpg)
- 一個用於管理虛擬化平台（如KVM、QEMU、Xen、LXC等）的開源工具
- 提供了一個通用的 API，讓開發人員可以編寫應用程式來管理虛擬機器（VM）和虛擬網絡，同時也提供了一個命令行工具和圖形界面來管理虛擬機和虛擬網絡

:::
### QEMU-KVM
- 可支援不同作業系統的同時運作、且讓同時運作的作業系統彼此互相為獨立的系統環境
- QEMU-KVM 中，KVM 與 QEMU 相互配合來創建虛擬化空間
    - KVM 運行在 kernal 空間：將 cpu 及記憶體做虛擬化
    - QEMU 運行在使用者空間：模擬 IO 設備（磁碟，網路卡等）
- 使用在 Ubuntu 中，在主機 Linux 上可利用 Kvm (kernel-based virtual machine) 做虛擬化，再加上 QEMU 來管理虛擬機器

### Demo
:::success
### 前置作業
1. 查看 cpu 是否支援虛擬化
- 輸入以下指令 ：
    - `sudo grep -E -c '(vmx|svm)' /proc/cpuinfo` 確認 cpu
    - 如果回傳 0 表示 cpu 支援虛擬化
    - 如果回傳非 0 訊息 表示 cpu 不支援虛擬化
    - ![](https://i.imgur.com/HtUhESs.png)

2. 確認電腦是否支援 kvm
- 輸入以下指令：
    - `sudo apt update`
    - `sudo apt install cpu-checker`
    - `kvm-ok`
    - 如果支援 kvm，會回傳
    `INFO: /dev/kvm exists`
    `KVM acceleration can be used`
    ![](https://i.imgur.com/dMMadr1.png)

3. 如果想進一步確認 cpu 是否支援 kvm
- 如果是 Intel cpu 輸入以下指令：
    - `grep -c vmx /proc/cpuinfo`
- 如果是 AMD cpu 輸入以下指令：
    - `grep -c svm /proc/cpuinfo`
    - 會回傳可用 cpu 的數量
:::
:::success
### 安裝
1. 安裝 QEMU-KVM
- 輸入以下指令：
    - `sudo apt install qemu-kvm`
    - ![](https://i.imgur.com/e7R8GZc.png)

2. 安裝 libvirt
- 一套用於管理硬體虛擬化的 API，用來管理 KVM
- 輸入以下指令：
    - `sudo apt install libvirt-daemon-system libvirt-clients`
    - ![](https://i.imgur.com/KMqMLDj.png)

- 確認 libvirt 運作狀態：
    - `sudo systemctl status libvirtd.service`
    - ![](https://i.imgur.com/PgHO7D6.png)
3. 將使用者添加到 kvm 群組中
- `sudo adduser $USER kvm`
4. 重新開機使其正常運作
- `sudo reboot`
5. 確認群組
- `groups`
- 正常會看到 kvm 及 libvirt 顯示在其中
- ![](https://i.imgur.com/BCXiE73.png)

6. 確認 kvm 是否已安裝且可以運作
- `virsh list --all`
- ![](https://i.imgur.com/RMgfjET.png)

:::info
#### Virsh 指令
- 用來啟動、關閉虛擬機器與顯示虛擬機器資訊相關的指令
    - `virsh list --all`：顯示所有虛擬機狀態
    - `virsh start [虛擬機name]`: 啟動虛擬機
    - `virsh suspend [虛擬機name]`：暫停虛擬機
::: 
:::success
### 建立新的 VM
1. 安裝 virt manager 
- 為 kvm 的圖形介面，方便使用與管理 kvm
    - `sudo apt install virt-manager`
    - 安裝完畢就可以在應用程式清單中看到並開啟
    - ![](https://i.imgur.com/h0qWkfO.png)
2. 開啟 virt manager 建立 VM
    - 選擇 iso 文件
    - ![](https://i.imgur.com/JF3BUEd.png)
    - ![](https://i.imgur.com/QpqPwem.png)
    - 設定記憶體大小與 cpu
    - 設定分配的磁碟大小
    - 為虛擬機命名並建立
3. 都設定完成後就可以使用新建立的 VM
- 在我們的 Ubuntu 虛擬機上就會再有一個 KVM 虛擬機
:::


---
 
## 虛擬機 (VM)
- ![](https://i.imgur.com/rr8K9jN.png)
    - `Host` : 實際的作業系統和硬體環境 
    - `Hypervisor` : 負責管理與分配硬體資源
    - `Dependency`(相依性資源) : 官方是以 bins/libs 稱之 
        - `Bin` (binaries) : 二進位執行檔 
       - `Lib` (libraries) : 函式庫 
       - 可能是 MySQL、Nodejs 等運行 App 所需要的執行環境
- 實體電腦的數位版本
- ![](https://i.imgur.com/Z7rV76j.png)
    - 鳴人的本體(硬體)、影分身之術(虛擬化)、分身(虛擬機)
### 為何要使用虛擬機 ?
- ![](https://i.imgur.com/l4oidmH.png)
- 提供一個可供測試的隔離環境
    - 例如 : 存取感染病毒的資料、瀏覽易中毒的網站、下載看起來有病毒的檔案
- 可在單一實體電腦上執行多個作業系統環境 
    - 太多可能會造成效能不穩定
- 將系統資源的使用最佳化
    - 同一個主機上執行多個 VM
### 虛擬機管理程式（Hypervisor）
- 又稱**虛擬機器監視器（virtual machine monitor) (VMM)**
- 主要功能是讓我們在同一台實體機器上能運行多個 VM，各個 VM 可以擁有不同的 OS，且各個 VM 彼此獨立，就如同擁有實體環境
- 當虛擬機器要使用實體資源時， 就需要 Hypervisor 來控制
- 它是一個軟體層，充當虛擬機器與底層硬體或主機作業系統之間的中介
- 類型 
    - Type 1 : Bare Metal Hypervisor (裸機型)
    - Type 2 : Hosted Hypervisor (主機型)
    - ![](https://i.imgur.com/P62QpAL.png)
        - hypervisor 用來執行一個或多個 VM 的電腦稱為 **host machine**
        - VM 稱為 **guest machine**
#### Type 1 : Bare Metal Hypervisor
- ![](https://i.imgur.com/ZWLkRgq.png)
- 直接把 Hypervisor 建立在硬體上，直接控制著實體機器的硬體
    - 所以才稱為「裸機型」
- 呼叫流程 : Guest OS/kernel :point_right: Hypervisor :point_right: 硬體
- 不需要 OS 就可以建立
- 通常用於企業
- 優點  
    - 執行效率高
        - 因為直接使用硬體資源
    - 較安全
        - 降低了針對 OS 安全缺陷和漏洞的攻擊風險
    - 可移植性高
        - 可以直接移到另一個硬體上 
        - type 2 還要考慮 OS
            - 例如 : 本來程式運行在 Windos 的環境 ，但如果換到 Linux 上，就要考慮程式是否相容，可能要調一些設定
- 缺點
    - 較難實作 
- 例如 
    - Xen
    - KVM
    - Microsoft Hyper-V
#### Type 2 : Hosted Hypervisor
- ![](https://i.imgur.com/obKCcDg.png)
- 呼叫流程 : Guest OS/kernel :point_right: Hypervisor 接收 :point_right: **Host OS/kernel** :point_right: 硬體
- Hypervisor 作為應用程式執行在 Host OS 環境內
- 通常用於個人的 PC
- 優點 
    - 更易於安裝、設定和使用
        - 類似於桌面應用程式
- 缺點 
    - 執行效率一般較 Type 1 低
        - 因為無法直接存取硬體，而是要透過 Host OS 轉送
    - 如果 Host OS 出現問題，所有 VM 就不能運作
- 例如 
    - Oracle VM VirtualBox 
    - VMware Workstation Pro and VMware Fusion 
    - QEMU

#### Type 1 vs Type 2 比較
|  | Bare-Metal Hypervisor(Type 1) | Hosted Hypervisor(Type 2) |
| -------- | -------- | -------- |
| 執行方式     | 在實體主機硬體上執行     | 在 Host OS 上執行     |
|呼叫流程 | Guest OS/kernel :point_right: Hypervisor :point_right: 硬體|Guest OS/kernel :point_right: Hypervisor 接收 :point_right: Host OS/kernel :point_right: 硬體 |
| 效能 |  👍 | 👎 |
| 穩定度 | 👍 | 👎 |
| 安全性 | 👍 | 👎 |
| 可移植性 | 👍 | 👎 |
| 易用性 | 👎 | 👍 |

> [參考1](https://hackmd.io/@ncnu-opensource/book/https%3A%2F%2Fhackmd.io%2F3EevJHwRSnep8pdlXd7YrA#Hypervisor)、[參考2](https://hackmd.io/@ncnu-opensource/book/https%3A%2F%2Fhackmd.io%2F%40108213034%2FB1_qNP2xc#Hypervisor)
## 容器 (Container)
- ![](https://i.imgur.com/KlzN852.png)
     - `Container` : 應用程式與其相依性資源 (Dependency) 會被封裝在 Container 中
    - `Container Engine`：類比 Hypervisor 在硬體的上層建置一個可以運行虛擬機的環境
        - 例如 : Docker 也同樣需要在 Host OS 上建置一個可以運行容器的環境，Docker Engine 就是這樣的角色，其可將 Docker Image 轉換成 Container
- 共用 kernel 
- 利用 **Namespace** 和 **cgroup**，達到 Container 互相隔離
- 讓軟體開發更加方便
    - 傳統上，一個軟體要從某個運算環境移植到另一個運算環境上執行，會遭遇許多困難
        - 例如，當底層支援的軟體環境不同時，就要去設定相關的東西
    - 現在，使用 Container 
        - 將所有必要的元素 (**包含應用程式與相關的函式庫、環境配置檔**) 全部包裝在一起，消除底層作業系統和基礎架構差異性所帶來的問題
### 特點
- ==**不須裝載 OS**==
    - 共用 Host OS kernal
    - 更加輕型
    - 啟動速度會相對快
        - 當有高流量活動出現時，容器的橫向擴充速度也相對優勢很多
-  彼此隔離，較安全
    - 一個 Container 出現了 BUG 並不會影響到其他 Container 的運作
    - 開發團隊修復這個 Container 中的問題時，不需要讓其他的 Container 停止運作
- 啟動快速
    - 沒有開機的流程

### LXC (Linux Container)
- ![](https://i.imgur.com/aPXYueH.png)
    > [來源](https://blog.csdn.net/allway2/article/details/122291953)
- 可以單一 **Linux 主機**上運行多個 Linux 虛擬環境，可以像使用 VM 一樣，在 LXC 安裝任何東西
    - 例如 : Ubuntu、Red Hat 或 CentOS

- **isolated operating system environment** with its own file system, network, process and block I/O space 
    - Container 裡的資料被保存在 Container 的 Filesystem 中，就像在一個獨立的 Linux 系統
### Docker Container 
- ![](https://i.imgur.com/NNC5aSF.png)
    - 由很多層 image 所組成的
    - Docker 在 1.0 版之前使用 LXC 來創建與主機系統的隔離。後來，Docker 開發了自己的 LXC 替代品，稱為 `libcontainer`
- 一個 Docker Container 執行一個 process
    - docker 的 best practice
:::info
### libcontainer
- 用 go 語言寫的
- 用於創建具有 namespaces、cgroups 的 Container
- 為 Docker 提供了對 Linux 容器 API 的直接訪問
- libcontainer 是一個開源項目，可以在 GitHub 上找到它的程式碼和相關文件
### AUFS （AnotherUnionFS）
- 一種 UnionFS (聯合檔案系統) 
- 將不同的目錄合併成一個虛擬目錄
- 預設情況下，只有第一層目錄是可寫的，其他目錄都只是可讀
- 方便地管理虛擬環境中的文件和目錄，同時也可以 host 的 filesystem 不受到 Container 的影響
- 最新版本的 Ubuntu 都把 AUFS 換成 overlay2 了
:::
### LXC VS Docker Container 
- ![](https://i.imgur.com/lm51xK9.png)
    
|  | LXC | Docker |
| -------- | -------- | -------- |
| virtualization     | OS     | application     |
| Filesystem      | 有自己的 Filesystem     | 共用 host 的 Filesystem     |
| 環境     | 只能在 Linux    | 可以跨平台     |
| 功能    | 提供一個完整的虛擬化環境   | 只包含應用程式和它們所需要的環境     |
| 情境    | 需要 Linux 的環境   | 跨平台執行程式     |

> [來源](https://blog.csdn.net/allway2/article/details/122291953)

## Container 與 VM 
- ![](https://i.imgur.com/d8b40a8.png)

    |                         | VM         | Container |
    | ----------------------- | ---------- | --------- | 
    | 技術                |   需要安裝 OS（Guest OS）  | 不需要安裝 OS     |
    | 啟動速度                | 數分鐘     | 數秒      |
    | 效能                | 慢       | 快      | 
    | 硬碟容量                | 幾GB       | 幾MB      | 
    |  單一主機同時運行  |  一般幾十個  |   上千個容器   |
    |隔離性                | 完全隔離       | 不完全隔離(共用 OS)      |
    |安全性                | 較好       | 較差      |

    
 > [參考1](https://blog.ewocker.com/intro-to-container-00/)、[參考2](https://ithelp.ithome.com.tw/articles/10238498)、[參考3](https://medium.com/mr-efacani-teatime/%E6%B7%BA%E8%AB%87%E8%99%9B%E6%93%AC%E5%8C%96%E6%8A%80%E8%A1%93-%E8%99%9B%E6%93%AC%E6%A9%9F-vm-%E8%88%87%E5%AE%B9%E5%99%A8-container-%E4%B9%8B%E6%8A%80%E8%A1%93%E5%83%B9%E5%80%BC%E8%88%87%E6%AF%94%E8%BC%83%E5%88%86%E6%9E%90-5c10457aad62#:~:text=%E6%90%AC%E9%81%B7%E7%9A%84%E5%95%8F%E9%A1%8C%E3%80%82-,%E7%B8%BD%E7%B5%90,-%E6%88%91%E5%80%91%E6%87%89%E8%A9%B2%E8%A6%81)
- Container 不是用來取代 VM 的
    - VM 簡化了硬體資源配置與作業系統安裝的工作
    - Container 簡化了介於作業系統與應用程式 (App) 之間的環境建置工作



## Namespace (命名空間)
- 提供一個獨立環境將系統資源**隔離**，保證 Container 之間彼此互不影響
- 一個 Container 可能看起來擁有一個獨立的檔案系統、網路介面、PID 和主機名稱
- 把一個 Container 放在某一個種類的 Namespace 中，它就會只看得到該 Namespace 下看得到的資源
- 不同種類的 Namespace 可以隔離出不同種類的資源給該 Namespace 下的 process 使用


| Namespace| 被隔離的資源 |
| -------- | -------- | 
| **PID Namespace**   | Process ID|
|**Network Namespace**|網卡、 iptables、routing table|
|**UTS Namespace** |hostname、NIS domain name|
|**IPC Namespace**|IPC resources、namely、System V IPC objects、POSIX message queues|
|**User Namespace**|User & group ID|
|**Mount Namespace**|Mount point|


### UTS namespace (Unix Time-sharing)
- 處在不同 UTS namespace 中的 process ，可以有不同的 hostname 與 domain name
    - ![](https://i.imgur.com/346JXfu.png)
- 在網路上可以被視作一個獨立的節點，而非主機上的一個程式

:::info
### `unshare` 
- `unshare -[namespace]`
- 例如:
    - `unshare -u`
    - 新增一個 UTS Namespace
:::
:::warning
### 小實作
- 輸入`sudo unshare -u`
- 在裡面更改 hostname ， `hostname [your name]`
- ![](https://i.imgur.com/jU4ptkw.png)
- **開新的 Terminal**，確認 host 的 hostname 有被更改嗎
- ![](https://i.imgur.com/QAFWiAu.png)

> [來源](http://redhatgov.io/workshops/containers_the_hard_way/exercise3/)
:::

### IPC namespace (Inter-Process Communication)
- process 只能和相同 Namespace 內的 process 溝通
- 當一個 IPC namespace 被刪除時，底下的 IPC object也會被刪除
### PID namespace (Process ID)
- 每個 PID namespace，裡面的 process 可以和另外一個 PID namespace，擁有重複的 PID 
    - 像是在 Container的使用時機就是，比如今天要把一個 Container 移到 A 機器時，有可能這個 Container 中的 process 的 PID 跟 A 機器上原先有的 process 的 PID 重複了 
    - 如果這時讓上面的 process 在獨立的 PID Namespace 中執行，就可以避免這個問題
- ![](https://i.imgur.com/50teBHa.png)
    - 使用 PID namespace 時 ， 每個 Container 都會有 PID =1 的 process，這個 process 在本機上也會有另一個 PID
    - parent PID namespace 知道 child PID namespace 的存在
    - 使得這兩個 PID namespace 像是兩個獨立的作業系統

 
### mount namespace
- 可以掛載主機上不存在的文件系統
- 一個 mount namespace 中的 process 無法訪問掛載在另一個 mount namespace 中的 Filesystem
    - 舉例 :　在　A mount namespace 的 USB ， B mount namespace 就無法使用 A 的USB
:::info
### Filesystem 檔案系統
- 是一種儲存和組織電腦資料的方法
- 使用**檔案**和**樹形目錄**代替了硬碟和光碟等**物理裝置**使用資料塊的概念
- 使用者使用 Filesystem 存資料，不必知道資料實際存在硬碟的哪個位置，只需要記住檔案的所屬目錄和檔名。寫入新資料時，也不必關心硬碟上哪個位址沒有被使用，Filesystem 會幫你分配，只需要記住資料被寫入哪個檔案就好
- `cat /proc/filesystems`
    - 查看 kernel 支援的 filesystems 
:::

:::warning
### 小實作
- `sudo unshare -m`
- `mount -t tmpfs wallytest /mnt`
    - 將 tmpfs 這個檔案系統掛載至 `/mnt` 這個目錄，並將這個掛載的檔案系統取名叫 wallytest
- `mount -t tmpfs`
    - 看有沒有被掛載進去
-  ![](https://i.imgur.com/yOlCskJ.png)
-  `date > /mnt/time`
-  `cat /mnt/time`
- ![](https://i.imgur.com/ng3gq9W.png)
- 開新的 terminal 
- `mount -t tmpfs`
- `cat /mnt/time`
- 在本機找不到剛剛創建的檔案系統及 time 這個檔案，因為他們不在同一個 mount namespace
- ![](https://i.imgur.com/H7TeCKd.png)


 


:::

### network namespace
-  網路資源的隔離， 這樣每個 Container 就有獨立的網路資源可以用
    -  例如 : 網路設備、IPv4、IPv6 、IP 路由表、防火牆等資源的隔離
-  如果你在 Container 內執行一個 apache ，Host 上也執行 apahce，你很可能會得到 80 Port 已經被佔用的錯誤
    -  Container 和 Host 都使用不同的 network namespace ，才可使用相同的行程相同的 Port 不互相干擾

:::warning
### 小實作
- 輸入 `ip link` 和 `ip route`
    - ![](https://i.imgur.com/Ino1B6v.png)
- `sudo unshare -n`
    - 創造一個 network namespace
- 然後同樣輸入 `ip link` 和 `ip route`
    - ![](https://i.imgur.com/czaLRKX.png)
:::
### user namespace
- 主要隔離了 user 權限相關的 Linux 資源
- 包括 user ID、group ID、根目錄、以及特殊權限等，支持 process 在 container 內外擁有不同級別的權限
    - 讓本來在 container 是 root 權限，回去 host 變成一個普通的 user 身分
        - 這樣在 container 內，只會覺得仍是 root 身份，然後就算這個 container被駭了，它在 host 上也僅僅只是一個普通 user 的身份，大大提高了安全性

:::warning
### 小實作
- `unshare -Ur`
    - 開一個 user namespace ，並用 root 的身分開啟，然後用 `whoami` 確認身分
- ![](https://i.imgur.com/PCIQqKa.png)
- `date > /tmp/test`
- `ls -l /tmp/test`
- `cat /tmp/test`
- 我們用 root 身分，所以會顯示 root 創建的
- ![](https://i.imgur.com/EupSxlf.png)
- 離開 這個 user namespace ，去 host 開新的 terminal ， 輸入 `ls -l /tmp/test`，檢查文件
- ![](https://i.imgur.com/67SXaDo.png)

> [來源](http://redhatgov.io/workshops/containers_the_hard_way/exercise4/)

:::
> [參考](https://blog.quarkslab.com/digging-into-linux-namespaces-part-1.html)

::: info
### 除了用 Namespace 來達到隔離的效果之外 </br>也用了 chroot 來更改容器根目錄的位置
- ![](https://i.imgur.com/78Ue97Y.png)
    - 在 host 的 `c` 目錄中放了 container 執行所需的設定檔，以及相關的 binary檔
- 因此透過 Namespace，再加上 `chroot` 更改 container 根目錄的位置，當你登入 container 時，就會像是真的在一台實體主機上
:::



## cgroups (控制組)
- 全名 : Control Groups
- 管理使用資源的權限，防止 Container 使用過多的資源
    - 例如 : 記憶體、檔案快取、CPU 使用、磁碟 I/O
### 主要有四個功能
- 限制資源上限
    - 限制了 task 可以使用多少資源，像是可以設定 Memory 的使用上限
- 優先級分配
    - 不同的 Container 可以擁有不同的 CPU 跟 Disk I/O 使用優先順序
- 計算資源使用情況
    - 計算 Container 的資源使用量，如 CPU、記憶體等使用情況
- 控制
    - 可以暫停 Container 中的 process

### 四個元素所組成
- task
    - 運行於作業系統內的 Process，在 cgroups 內被稱為 Task
- Subsystem (子系統)
    - 一個 Subsystem 負責管理一種資源
        - 例如 : CPU 或是 Memory
    - `cat /proc/<Container 在 host 的 pid>/cgroup` 
        - 可以看當前的 pid 有哪些子系統
        - ![](https://i.imgur.com/0ZS0mKK.png)
:::info
### 各個子系統的根目錄
- `cd /sys/fs/cgroup`
- ![](https://i.imgur.com/9av1xzc.png) 
- `blkio` : 限制 Task 對於儲存裝置的讀取，例如 Disk, SSD 和 USB… 等
- `cpu` : 透過 Scheduler 安排 cgroup 內 Task 存取 CPU 資源
- `cpuacct` : 自動產生 cgroup 內的 Task 使用 CPU 資源的報告
- `cpuset` : 為 cgroup 內的 Task 分配一組單獨的 CPU 核心 (多核心 的 CPU 系統) 跟 Memory
- `net_cls` : 對網路封包標記上 Class ID，進而讓 Linux Traffic Controller 根據這些 Class ID 得知網路封包是來自於哪一個 cgroup 中的 Task
- `net_prio` : 為每一個 Network Interface 提供動態設定網路流量優先權的方法
- `ns` :有關於 Namespace 的 Subsystem 
- `perf_event` : 用來辨別 Task 屬於哪一個 cgroup，而且可以拿來做效能分析用途
- `devices` : 控制 cgroup 中 Task 可以存取的裝置有哪些
- `freezer` : 暫停跟恢復位於 cgroup 內的 Task
- `memory` : 限制 Task 可以使用的 Memory，並且自動產生 cgroup 內 Task 使用 Memory 資源的報告
:::


- cgroup
    - 資源控制以 cgroup 為單位，用來定義 Task 的資源管理策略
        - 例如把一個 Task 加入到某個 cgroup 內，那麼這個 Task 使用資源時就必須遵守該 cgroup 中所定義的規範 
- hierarchy
    - cgroup 使用樹狀結構來管理資源
    - 預設會有一個根結點，每個節點都是一個 cgroup，可以有多個子節點，子節點會套用父節點的所有設置
    - 一個 hierarchy 會對應到一個或多個 subsystem ，然後在根節點設置 subsystem 的限制，那這些限制就會套用到這個節點內的所有的 task
- ![](https://i.imgur.com/wF7UTxa.png)
    - 兩個 cgroup 都是樹狀架構
    - cgroup A attach  cpu 子系統和 cpuacct 子系統
        - 對 cpu 的資源進行限制，且對 process 的 cpu 使用狀況進行統計
    - cgroup B attach  memory 子系統
        - 對 memory 的資源進行限制
    - 對資源做不同的限制比例
        - cgroup1 使用 60% 
        - cgroup2 使用 20% 
    > [來源](https://tech.meituan.com/2015/03/31/cgroups.html)
### 小規則 
- ![](https://i.imgur.com/a6nFiBb.png)
    - 可以有一個或多個 subsystem 
- ![](https://i.imgur.com/BA24MEE.png)
    - 如果 b 已經附加了一個不同的 subsystem (memory) ，則附加到 a 的   subsystem (cpu) 不能附加到 b
    - 但如果 A 跟 B 都只有一個 subsystem ，則 subsystem 可以附加到 A 跟 B
- ![](https://i.imgur.com/6XHN12O.png)
    - 一個 process (httpd)  可以在多個 cgroup 中，只是這些 cgroup 不能在同一個 hierarchy
    > `cpu_mem_cg`: 限制 CPU 時間和 memory 使用量
    > `net`: 限制傳輸速率
> [來源](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/resource_management_guide/sec-relationships_between_subsystems_hierarchies_control_groups_and_tasks)


:::warning
### 小實作
- 在具有 Memory Subsystem 新增一個資料夾
- `sudo mkdir /sys/fs/cgroup/memory/demo`
- demo 這個資料夾 (cgroup) ，已經自動產生好控制資源 (Memory) 時所需要的檔案，透過修改相關檔案內容來限制位於這個 cgroups 內的 Task 如何使用該種資源 (Memory)
- `ls /sys/fs/cgroup/memory/demo`
    - ![](https://i.imgur.com/LCH6Ts0.png)
    - 大部分檔案都是與該類型的 Subsystem (Memory) 設定相關
    - `tasks` : 把某個 Process 的 PID 加到這個檔案中的話，就等同於把該 Process 移到此 cgroup 底下
-  `sudo vim /sys/fs/cgroup/memory/demo/memory.limit_in_bytes` 
    - 將 memory 限制設為 50,000,000 bytes (50MB)

:::
> [參考](https://medium.com/starbugs/%E7%AC%AC%E4%B8%80%E5%8D%83%E9%9B%B6%E4%B8%80%E7%AF%87%E7%9A%84-cgroups-%E4%BB%8B%E7%B4%B9-a1c5005be88c)



## Docker 
:::info
### 安裝 Docker on Ubuntu

```
sudo apt-get update -y
sudo apt-get install -y curl
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get install -y docker-ce
```
>[資料來源](https://cutejaneii.gitbook.io/docker/docker-installation/an-zhuang-docker-on-ubuntu)
:::
- ![](https://i.imgur.com/bG6WinZ.png)
    - 碼頭搬運工 (Docker)
        - 是一個軟體平台
        - 一種建立 Container 的技術
        - 提供簡單的命令建立、啟動、停止 Container
    - 統一規格的貨櫃 (Container)
        - Container 具有相同的封裝方式、啟動方式、存取方式
        - 把軟體放進一個貨櫃 (Container)，透過 Docker 時就可以放到不同的運行環境
- ![](https://i.imgur.com/Zo5cXqE.png)

### Docker 架構
- ![](https://i.imgur.com/M6JIN37.png)
    >[取自](https://docs.docker.com/get-started/overview)
#### Docker client
- docker command uses the Docker API
- Docker client 可以跟多的 Docker daemon 溝通

#### Docker daemon (Dockerd)
- listens for Docker API requests
- 管理 Docker object 
    - images, containers, networks, and volumes
- 可以與其他的 Dockerd 溝通，管理 Docker 整體的服務
#### Docker repository (倉庫)
- 放置 image 的地方
- 有公開的 ([dockerhub](https://hub.docker.com/)) 跟私有的 (公司)
- ![](https://i.imgur.com/VBUcRxZ.png)
    - `DOCKER OFFICIAL IMAGE`
        - 官方提供的 image
    - `VERIFIED PUBLISHER`
        - 為開發者提供官方的驗證
        - 前綴: 代表的是 DockerHub 的暱稱(右上角的名字)
- `docker pull <image>`
    - 下載 image 
- `docker images` OR `docker image list` 
    - 查看現在有的 image

:::info
### 執行 Docker 前面不用加 sudo 的方法
- 創建 docker group
`sudo groupadd docker`
- 將 $USER(輸入自己的名子) 加入到 docker group 裡面
`sudo usermod -aG docker $USER`
- 啟動對 group 的更改
`newgrp docker`
- 就完成囉 ~
:::

### Docker 執行過程
- Docker client 呼叫 Docker daemon，然後 daemon 透過 libcontainer 呼叫 Linux 的核心模組來完成建立 Container 的步驟
- ![](https://i.imgur.com/l6TxOa2.png)

    1. Docker Client 通過 Unix Socket 向 Docker daemon 發送命令，進而控制 Docker Container 的運行
        - 預設使用的通訊協定是 `Unix Socket`
    2. daemon 透過 `libcontainer`要求 Linux 核心建立 Container
    3. Kernel 收到指令，即啟動核心的 namespace 建立一個獨立的空間，daemon 根據 client 的參數定義來分配 CPU、記憶體或磁碟 IO 等
        - **此時 Container 中沒有 (Ubuntu 12, apache 2.0)，還沒啟動完成**
    4.  damone 檢查本機裡面有沒有 Image
    5.  有的話，直接從本機載入 image 至 Container ，沒有的話 daemon 到預設的 Docker Registry， 根據 client 的參數，下載適當的 Image
        - 載入 image (Ubuntu 12, apache 2.0) ，**Container 才啟動完成**
- ![](https://i.imgur.com/2LXByyw.png)
    - 假如沒有使用 `--name <名稱>` ，Docker 會自己幫你取
    >[來自](https://joshhu.gitbooks.io/docker_theory_install/content/DockerBible/dockersteps.html)
:::info
### Socket 
- 是一個網路上的通訊端點（IP number + TCP port），使用者或應用程式只要連接到 Socket 便可以和網路上任何一個通訊端點連線，實現不同主機之間的傳輸
- ![](https://i.imgur.com/WUx92ys.png)
    - 透過 Socket 之間通訊，使用者不用理會網路實體架構
    > [來自](http://www.tsnien.idv.tw/Internet_WebBook/chap8/8-1%20Socket%20%E7%B0%A1%E4%BB%8B.html)
- Docker daemon 通過三種不同類型的 **Socket** (`unix`、`tcp`、`fd`) 來 listens for Docker API requests 
    - 預設是使用 `unix domain socket` 
- Docker daemon 平常會 listen  `/var/run/docker.sock` 
    - 需要 root permission, or docker group membership
    - Container 如果掛載 `/var/run/docker.sock` ，就可以與 host 上運行的 Docker daemon 進行溝通，以便在 Container 內啟動、停止、管理其他 Container 
- ![](https://i.imgur.com/gzJy3tv.png)
    >[來自](https://www.educative.io/answers/var-run-dockersock)

#### 三種不同的 Socket
- unix Socket
    - 用於在同一台電腦的 process 之間通訊
    - 不需要 hostname 和 port number 
    - 通常會被掛載在 `/var/run/docker.sock` 文件上
    - Docker Client 可以通過 unix Socket 向 Docker daemon 發送 command，盡而控制 Docker Container 
- tcp Socket
    - 需訪問遠程的 Docker daemon，則需要開啟
    - 可用於不同電腦的 process 之間通訊
    - 需要 hostname 和 port number 
- fd Socket
    - 通常不直接使用
    - 可以通過文件描述與 Docker daemon 進行通訊，盡而控制 Docker Container 的運行
:::


### Docker Object
#### Docker image (映像檔)
- 設計藍圖 (房子的設計圖) 
- 主要目的就是產生 Container
- image 包含了創建 Container 的必要資訊
- ![](https://i.imgur.com/Gl5R0sj.png)
    - `image` 
        - **唯讀**
        - 疊加
        - 有多個 image 都從相同的 base image 建構而來， docker host 只需在保存一份 base image 即可（同時 memory 也只需加載一份）供所有 Container 使用
            - ![](https://i.imgur.com/rQmTr5e.png)
                - 例如 : 有兩個 image 都需要 PHP 這個執行環境，就不用分別建立，而是可以共同建立在 base image 上面
    - `Container layer ` 
        - ![](https://i.imgur.com/BFJ4ABZ.png)
            > [來自](https://ithelp.ithome.com.tw/articles/10304292)
        - Container 啟動時，會新增 Container layer 到 image 頂部
        - **可讀可寫**
        - 所有更改(寫入 or 修改 or 刪除文件)都會寫進去，而不會更動到 image
        - 被刪除時，Container layer 會被刪除，但 image 不會 
    - `bootfs`
        - 用來載入 linux kernel
- `docker image history <image>`
    - ![](https://i.imgur.com/7QjaimL.png)
        - image 在建構時的歷史紀錄，每一層都帶有不同的指令，有些是執行指令，有些是加入檔案，所以才會有 0B 的層級，也有 77.8MB 的層級
        - `missing` : 表示這些都是屬於同一個 image 的一部分
- 取得 Docker image 大致有三種方式：
    1. 從 Docker Repository `pull` 下來
        - 例如：Docker Hub
    2.  使用 `docker commit`，可以將正在運行的 Container 保存為一個新的 image
        - 例如 : 可以先運行一個基本的 docker image，然後在 Container 中進行操作，最後使用 `docker commit` 保存為新的 docker image
    4.  使用 Dockerfile 自行配置 image
    >[來自](https://hackmd.io/@ncnu-opensource/book/https%3A%2F%2Fhackmd.io%2F%40108213034%2FB1_qNP2xc#Docker-%E6%9E%B6%E6%A7%8B)
:::warning
### 小實作 - image layer
#### 今天建造兩個 image `nginx`、`newnginximage` </br>image 會把相同的部分取出來共用
![](https://i.imgur.com/dUDtBUW.jpg)
- `docker pull nginx`
- **查看 `nginx` image 的細節**
    - `docker image inspect nginx`
    - ![](https://i.imgur.com/X83NUJx.png)
        - 6 層
    - ![](https://i.imgur.com/vlDF9kf.png)
        - 特別注意 `LowerDir` 與 `UpperDir`，他們是 Host 上的檔案夾路徑
- 利用 `nginx` 這個 image 啟動一個 Container 叫做 `nginxcontainer`，並在 Container 裡面新增一個文字檔
    - ![](https://i.imgur.com/USwsBZP.png)
- 開新的 terminal ，將 `nginxcontainer` 變成一個新的 image 叫 `newnginximage`
    - ![](https://i.imgur.com/HTgqEZV.png)
- **查看 `newnginximage` image 的細節**
    - `docker image inspect newnginximage`
    - ![](https://i.imgur.com/CAoYMdN.png)
        - 跟 `nginx` 比多了一層 layer
        - 前面的 6 層 layers 跟 `nginx` 一模一樣
    - ![](https://i.imgur.com/CIHeoDw.png)
        - `Lowerdir` 第一個資料夾是 `nginx` 的 `UpperDir`
- ![](https://i.imgur.com/WwKU3Ke.png)
- ![](https://i.imgur.com/l7Ld0aj.png)
    - `nginx` 的 `UpperDir`+ `Lowerdir` = `newnginximage` 的 `Lowerdir`
    - `nginx` 是 `newnginximage` 的 base image
- 查看 `newnginximage` 的 `UpperDir` ，**為什麼會有 `a.txt`?**
    - ![](https://i.imgur.com/uBntrTs.png)
    - 步驟 :
        1. 在 `nginx` image 建一個 Container `nginxcontainer`
        2. 在此 Container `touch a.txt`
        3. 把這個 Container 變成一個新的 image `newnginximage`
    - 因為 `newnginximage` 的 `UpperDir` 會記錄前面做的動作 (`touch a.txt`)
#### 結論
- ![](https://i.imgur.com/jHhU491.png)
    - **docker image 其實是由多層 layers 組成的**
    - 有幾層 image 就會有幾個資料夾
    - `newnginximage` 是建立在 `nginx` 上面
>[參考](https://ithelp.ithome.com.tw/articles/10294310)
:::
:::info
### Layer
- Image 透過以層層堆疊的方式建構出來，最多可以有 127 層
- 會儲存該次建構所需要的文件以及與上一層之間產生的變化
- Dockerfile 的每一行指令都會建立一個新的 Layer
:::


##### overlay2
- 一種 UnionFS (聯合檔案系統)
- 將多個檔案夾「聯合」起來使其看起來像是只有一個檔案夾
- `docekr info`
    - ![](https://i.imgur.com/Txxfg98.png)
- 儲存 image layers 和 container 的可寫層
- OverlayFS 內部使用的資料夾
    - ![](https://i.imgur.com/vlDF9kf.png)
    - 底層檔案夾 : `LowerDir`
    - 高層檔案夾 : `UpperDir`
    - `LowerDir` + `UpperDir` = `MergedDir`
    - `WorkDir`
---

:::warning
### 小實作 - 查看 OverlayFS 是如何操作的
#### 利用 OverlayFS 方式 `mount` 出 `merged` 資料夾
- 準備環境
    - 建立 5 個檔案夾: `lower1`, `lower2`, `upper`, `merged`, `work`
    - 在 `lower1` 中建立 `a.txt` 與 `x.txt`  (`A`)
    - 在 `lower2` 中建立 `b.txt` 與 `x.txt`  (`B`)
    - 在 `upper` 中建立 `c.txt`
    - `merged` 與 `work` 保持空檔案夾
- ![](https://i.imgur.com/s9qONrE.png)
- 執行 `mount` 
    - `sudo mount -t overlay overlay -o lowerdir=lower1:lower2,upperdir=upper,workdir=work merged`
- ![](https://i.imgur.com/fBmU2hw.png)
- ![](https://i.imgur.com/9CSQA99.png)
    - `merged` 的 `x.txt` 的內容是 `A` (來自 `lower1` 的 `a.txt`)
    - 因為 OverlayFS 是用 layer 的方式堆疊，上層的 layer 會蓋掉下層的 layer
- ![](https://i.imgur.com/326AV1f.png)
    - 如果檔案同時在 `upperdir` 和 `lowerdir` ，會讀取 `upperdir` 的檔案

#### 修改檔案
- 修改 `merged/a.txt` 加上 `merged`
- ![](https://i.imgur.com/vh5sCPr.png)
    - `upper` 多了 `a.txt`
- ![](https://i.imgur.com/EhMl5AR.png)
    - 用 `copy-on-write (COW)` 策略
    - 會從 `lowerdir` 複製 `a.txt` 到 `upperdir` ，然後再對`upperdir` 的 `a.txt` 進行讀寫
    - 之後就會直接對 `upperdir` 的 `a.txt` 作修改
#### 刪除檔案
- 刪除 `merged` 的 `b.txt`
- ![](https://i.imgur.com/t0pdfNg.png)
- ![](https://i.imgur.com/jz7Gx4Q.png)
    - `whiteout` 檔案會讓這個檔案 (`b.txt`)在聯合目錄中不會被存取到
        - 讓 `mergeddir` 不會存取到 `lowerdir` 的 `b.txt`
#### 重新命名檔案
- 將 `merged` 的 `x.txt` 改名叫 `newx.txt`
- ![](https://i.imgur.com/E2HRfGP.png)
- ![](https://i.imgur.com/c8HhsUa.png)
    - `copy_up`+ `whiteout`


> [參考]( https://ithelp.ithome.com.tw/articles/10295484?sc=iThelpR) 
:::

###### 總結
-  image 是把應用程式、相依的函式庫 / 套件，以及應用程式執行時所需的系統環境給打包起來
-   image 是以 layer 的方式設計的，並且用 UnionFS 的方式讓這些不同的 layers 看起來像是一個同一個檔案目錄
    - `docker image inspect newnginximage`
        - 查看`UpperDir`
            - ![](https://i.imgur.com/lG9nZHi.png)
            - `commit` 前，對 `nginxconteainer` 所做的「異動」
        - 查看 `MergedDir` 
            - ![](https://i.imgur.com/z5T1s0j.png)
            - 為什麼不存在 ? (等等會做解答)
- 當用 `nginx` 建 `nginxconteainer` 時，會在上面加一層 **container layer** 
    - `docker container inspect nginxcontainer`
    - ![](https://i.imgur.com/Dv2NXN4.png)
        - 6 個資料夾
    - 會將 `nginx` 每一層 layer 都作為 `lowerdir` 
        - 稱 `image layer` ，唯讀
    - 在 `nginx` 上加一層 layer `upperdir`
        - 稱 `container layer` ，可寫可讀 
        - 所有操作都會在 `container layer` 這層執行
            - 修改、刪除
        - 查看`UpperDir`
            - ![](https://i.imgur.com/L8XKP5d.png)
       - **存放所有的變化**
    - 將 `lowerdir` 與 `upperdir` 聯合起來在 `merged` 中呈現
        - 查看 `MergedDir` 
            - ![](https://i.imgur.com/BSH0cxb.png)
        - **完整的目錄**
- ![](https://i.imgur.com/7FUusCG.png)
    - `Container layer` 是 image 跟 container 最大的差異
        - 所以 image 的 `MergedDir` 才會是不存在
            - 因為 image 是保存資料，而不會被操作
    - 移除 `Container layer` Container 也會跟著消失
        - `commit` 會把這層可寫層給持久化保留下來

#### Docker container (容器)
- 實際的程式 (房子)
- 可以被啟動、開始、停止、刪除
- 一個 image 可以啟動多個互相隔離的 Docker Container
    - ![](https://i.imgur.com/uPyMHFq.png)
    >[來自](https://docs.docker.com/storage/storagedriver/#images-and-layers:~:text=in%20different%20situations.-,Container%20and%20layers,-%F0%9F%94%97)
#### Volume
- 主要用來保存 Container 內的資料，把資料存在 local storage，因為 Container 被刪除時，Container 裡面的資料也會被刪除
- ![](https://i.imgur.com/J6gDldq.png)
    - 當使用 Volume 時，docker 會在本機上隨機新增一個資料夾（Local storage area），大部分會在 `/var/lib/docker/volumes` 底下，然後讓這個資料夾跟 container 裡面的某個資料夾互通
        - 當 container 裡面那個資料夾有任何變更時，本機的資料夾也會跟著變，當 container 被刪掉時，那個本機資料夾還會原封不動保留在那邊
    > [來自](https://larrylu.blog/using-volumn-to-persist-data-in-container-a3640cc92ce4)
:::warning
### 小實作- 新增一個 volume 存 Container 的資料
#### named volume
- 在本機先 create volume 再使用 
- 新增一個 volume 叫 `storedata1`
    - `docker volume create --name <volume要叫什麼名子>`
        - `docker volume create --name storedata1`
    - `docker volume ls`
    - ![](https://i.imgur.com/cHZvOXK.png)
    - ![](https://i.imgur.com/MDtTEDK.png)

- 指定 volume 要跟 Container 內哪一個資料夾連通
    - `docker run -v <volume name>:</資料夾名稱> -it --name <幫這個container取的名子> <image>`
        - `docker run -v storedata1:/db -it --name volume1 ubuntu`
    - 然後在此 Container 的 `db`資料夾下新增一個檔案`testdata`
    - ![](https://i.imgur.com/bc7W0GK.png)
- 接著再新增一個 Container ，然後資料夾叫`rr`，確認一下剛剛的檔案`testdata`
    - `docker run -v storedata1:/rr -it --name volume3 ubuntu`
    - ![](https://i.imgur.com/C7WTXFO.png)
#### Host Volume
- 直接指定本機某個資料夾跟 Container 內的資料夾連通
- ![](https://i.imgur.com/brJMJPh.png)
- 指定本機的 `app`跟 Container 的 `app` 連通
    - `docker run -v ~/app:/app -it --name volume4 ubuntu`
    - ![](https://i.imgur.com/qFdpfbC.png)
    - ![](https://i.imgur.com/7x8ssNz.png)
### 讓兩個 Container 的資料夾共享
- 啟動第一個 Container 
    - `docker run -v /data -it --name sharecontainer1 ubuntu`
    - 在 `data` 新增資料
- 啟動第二個 Container
    - `docker run --volumes-from sharecontainer1 -it --name sharecontainer2 ubuntu`
        - `--volumes-from <要共享的 Container>`
- ![](https://i.imgur.com/Bwms9G8.png)
> [參考](https://larrylu.blog/using-volumn-to-persist-data-in-container-a3640cc92ce4) 、[參考](https://ithelp.ithome.com.tw/articles/10192703)
:::
##### Dockerfile
- ![](https://i.imgur.com/dbw0n8D.png)
    > [來自](https://bikramat.medium.com/docker-objects-e561f0ce3365)
- Docker Hub 中下載 Image 來建立 Container ，這些 image 可能是軟體開發商所釋出，或者是第三方人士加值過的版本 
    - 優點 : 方便
    - 缺點 : image 包含的功能、工具或版本無法滿足自己的需求
- 文件裡描述所需之套件及預先要包含的程式等步驟
- 純文字檔案，檔案很小，易分享
- 由一行一行的指令列所組成，一行指令對 Image 來說就是一層的資料層 (Layer)
:::warning
### 小實作 - 透過 Dockerfile 建立 Docker image </br> 執行 Container 可以印出 "hi~~"
#### 流程
```
dockerfile -> Docker build -> Docker image -> Docker run image -> Docker container 
             |----------------------Docker Compose process-----------------------|
             可定義在 docker-compose.yml 統一由 Docker Compose 處理
```
#### `ENTRYPOINT`
- 新增一個檔案並命名為 `Dokrfile`
```
FROM ubuntu
# 當 Container 啟動時要執行的程式
ENTRYPOINT ["/bin/echo"]
```
- 建一個 `file` 的 image
    - `docker build -t file . `
- 查看 image 
    - `docker image ls` 
- 利用此 image 執行 Container 
    - `docker run file hi~~`

**當 command 執行完， Container 便會停止** 
#### `CMD`
```
FROM ubuntu

CMD ["/bin/echo", " hi~~"]
```
- `docker bulid -t file2 .`
- `docker run file2`
- `docker run file2 /bin/date`
    - 可以用其他 command 覆蓋掉 CMD 原先的設定
#### `ENTRYPOINT` + `CMD` 
```
FROM ubuntu

ENTRYPOINT ["/bin/echo"]

CMD ["hi~~"]

```
- `docker bulid -t file3 .`
- `docker run file3`
:::
  

#### Docker network
- 因應不同需求發展出了多種類別的網路模式
- `--net=<網路模式>`
    - `--net=bridge`
- `docker network ls`
    - ![](https://i.imgur.com/wPjs4qj.png) 
##### Bridge networks
- 預設的網路模式
- ![](https://i.imgur.com/jJ9GWK6.png)
    - 創造一個 network namespace 
    - Container 會在自己的 network namespace 創造一張網卡
    - host 創建一個  bridge，並且透過 veth (Virtual Ethernet) 把 container 與 host 不同的 network namespace 連在一起
- bridge
    - 作為 Container 對外出口，與 host 網路溝通
    - 預設名稱為 `docker0`
    - 可以再新增 bridge，但不同 bridge 的 Container 不能互相溝通
:::info
### bridge(橋接器)
- 是一種網路裝置，主要用於將兩個獨立的網路連接起來，就如同單一網路，讓他們能夠通訊
:::
##### Overlay networks
- ![](https://i.imgur.com/FPSD6BZ.png)
    - **不同的實體主機**內的 Container 之間可以互相的溝通
   
##### Host networking
- ![](https://i.imgur.com/iOZsjpO.png)
- 不會有 network namespace
- 跟 host 共用相同的網路
- port 會共用


##### Macvlan networks
- ![](https://i.imgur.com/GuTLqc5.png)
- 直接分配實體網卡的 MAC address 給特定的 Container，讓 Container 可以透過實體的網卡使用網路，就像一個實體裝置一樣


##### Container networks
- ![](https://i.imgur.com/AsWePoc.png)
- 加入現有的 network namespace 
    - `docker run --network=container:$(docker ps --filter name=< A container name> -q) -d --name < B container name> <image>`
        - 將 B 加入到 A (用 bridge 創建)

##### none
- 只建立一個 network namespace 都沒做任何設定

#### 使用情境 

| Network |使用情境 | 
| -------- | -------- | 
|   Bridge  |  同一台host 的 Container 之間可以透過 IP 的方式互通  | 
|   Overlay  |  不同 host 上的 Container 互相溝通   | 
|   Host  |  Container 需要對 host 的網路環境進行操作或監控時  | 
|   Macvlan  | Container 有自己的網卡跟對外溝通 | 
|   Container   | 可以使用 localhost 來存取彼此服務  | 
|  none   |  想要開發網路模型  | 
> [來源](https://hackmd.io/@joshhu/r1Yj6_bPK#docker-network%E6%8C%87%E4%BB%A4%E7%B8%BD%E8%A6%BD)、[來源](https://www.hwchiu.com/docker-network-model.html )

## Docker DEMO
### 下載 docker image 
- 使用 `docker pull`，從 [Docker Hub](https://hub.docker.com/_/ubuntu/tags?page=1&name=12.04) 下載 Ubuntu tags(版本):12.04 作業系統的 Image 
    - ![](https://i.imgur.com/ICUa6yV.png)
    - `docker pull ubuntu:12.04`
- 顯示本機已有的 image(映像檔)
    - `docker image list`
    - ![](https://i.imgur.com/gVHtQRV.png)
        - `REPOSITORY` : 來自於哪個倉庫
        - `TAG` : 映像檔的標記，可以指定版本
            - 預設使用 `latest`:最新的版本
        - `IMAGE ID` : ID （唯一）
        - `CREATED ` : 建立時間
        - `SIZE` : 映像檔大小
- 更改 image 名稱
    - `docker image tag <image> <要改的名子>`
    - `docker image tag ubuntu:12.04 ubuntu12.04test`
    - ![](https://i.imgur.com/HrhPfHZ.png)

### 啟動、顯示、連線 Container
- 啟動 Image 產生 Container 
    - `docker run -it --name <<container_name or id>> <<image_name>>`
        - `docker run -it --name testubutu04 ubuntu:12.04`
        - `-i` : 當需要與 Container 做互動 (輸入指令給 Container，Container 會回傳指令結果），沒有 -i 的話 container 就收不到你打的字
        - `-t` : 透過 terminal 模式進入 Container
        - `--name`：配置一個名稱給 container
        - `image_name`：映像檔的名稱
        - 假如這個 image 不在本機， Docker 會自動幫你執行 `docker pull <image>`
- 當你使用 `exit` 離開之後，這個 Container 就關閉了，但不會被移除
- 顯示**目前啟動**的 Container 
    - `docker ps`
    - `docker container ls`
- 顯示已經存在但**沒有啟用**的 Container 
    - `docker ps -a`
    - `docker container ls -a`
    - ![](https://i.imgur.com/NlCknX0.png)
- 啟動剛剛關閉的 Container
    - `docker start <<container_name or id>>`
    - ![](https://i.imgur.com/ABVej3Y.png)
#### 連線到已經啟動的 Container 裡 
- `docker attach <container_name or id>`
    - 退出時， Container 也會跟著被關閉
- `docker exec -it <container_name or id> bash`
    - 以終端機模式進入 Container，且退出時也不會使 Container 關閉
#### 在外部向執行中的 Container 內部下指令
- `docker exec <container_name or id> <command>`
- ![](https://i.imgur.com/jJVd1wW.png)
### 關閉與刪除 Container 、 image
- 刪除 Container
    - `docker rm -f <<container_name or id>>`
    - `-f`：強制刪除 Container
    - ![](https://i.imgur.com/z3TIdEh.png)
- 關閉 Container 
    - `docker stop <<container_name or id>>`
    - ![](https://i.imgur.com/XXarb9p.png)
- 檢查有沒有刪除成功
    - `docker ps -a ` 
- 刪除 image
    - `docker rmi <image>`
- 指令
    - ![](https://i.imgur.com/MyPdOB9.png)

> [來自](https://functional.style/docker/ubuntu/)
### 限制 Container 資源
- 查看 Container 資源使用量
    - `docker run --memory 512MB --name nginx1 -d nginx`
    - `docker stats <Container>`
- 限制 CPU 的使用量，分別執行 `while.sh`
    - 沒限制
        - `docker run --name cputest1 -it centos /bin/bash`
    - 有限制
        -  `docker run --cpu-period=1000000 --cpu-quota=500000 --name cputest2 -it centos /bin/bash`
            -  最多只能使用 50% 的 CPU 資源

    - 執行指令並查看執行時間
        - `time bash while.sh`
   - `while.sh`
    ```python=
    #!/bin/bash
    x=1
    while [ $x -le 1000000 ]
    do
      x=$(( $x + 1 ))
    done
    ```


###  在 container 裡面安裝和啟動 apache 的 http service
- 利用 `ubuntu` image 建一個 container 
    - docker run -it --name <<container_name or id>> <<image_name>>
    - `docker run -it --name apachecontainer ubuntu`
- 安裝 apache2 並啟動
```
apt-get update
apt-get install -y apache2
service apache2 start
```

- 利用 `ifconfig` 查詢 container 的 IP 
```
apt-get install -y net-tools
```
- 在瀏覽器輸入 `$(查詢到的IP)/helloworld.html`
- 寫一個 helloworld.html 檔案放在 `var/www/html` 裡面
`echo "HelloWorld" > /var/www/html/helloworld.html`
- 在 terminal 輸入 `exit` ，此container就會關閉，所以 apache2 也會關閉

> [參考資料](https://ithelp.ithome.com.tw/articles/10190921)

### Docker compose
- 運行多個 docker container 的工具
- 搭配 `docker-compose.yml` 文件使用
- 使用步驟：
    1. 先安裝 Docker-Compose
    2. 寫一個 `docker-compose.yml` 
    3. 再利用 `docker-compose up` 開啟
- 安裝
```
sudo apt-get update
sudo apt-get install docker-compose-plugin
sudo apt install docker-compose
docker compose version
```
- 寫一個 `docker-compose.yml` 
    - [Compose參考來源](https://hub.docker.com/_/mariadb)
```
version: '3.1'

services:

  db:
    image: mariadb
    restart: always
    environment:
      MARIADB_ROOT_PASSWORD: example

  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080
```
- 執行`docker-compose.yml` 
    - `docker-compose up -d`
- 查看透過 compose 啟動的 Container
    -  `docker-compose ps` 
- 在瀏覽器輸入 `127.0.0.1:8080`
    - ![](https://i.imgur.com/xn6GEDN.png)
    - Usernaeme : root 
    - Password : example
- ![](https://i.imgur.com/ZMhKJ6x.png)
- 停止 Container
    - `docker-compose stop`
 >[來源](https://ithelp.ithome.com.tw/articles/10194183)





----


## 參考資料
:::spoiler
### 虛擬化
- https://aws.amazon.com/tw/what-is/virtualization/
### VM 、 Container 、 Hypervisor
- https://www.nutanix.com/tw/info/hypervisor 
- https://medium.com/mr-efacani-teatime/%E6%B7%BA%E8%AB%87%E8%99%9B%E6%93%AC%E5%8C%96%E6%8A%80%E8%A1%93-%E8%99%9B%E6%93%AC%E6%A9%9F-vm-%E8%88%87%E5%AE%B9%E5%99%A8-container-%E4%B9%8B%E6%8A%80%E8%A1%93%E5%83%B9%E5%80%BC%E8%88%87%E6%AF%94%E8%BC%83%E5%88%86%E6%9E%90-5c10457aad62
- https://ithelp.ithome.com.tw/articles/10224562
- https://www.vmware.com/tw/topics/glossary/content/virtual-machine.html
- https://kopu.chat/%E9%9B%B2%E7%AB%AF%E9%81%8B%E7%AE%97%E7%9A%84%E9%97%9C%E9%8D%B5%E5%9F%BA%E7%A4%8E%EF%BC%9A%E8%99%9B%E6%93%AC%E6%A9%9F/
- https://zh.wikipedia.org/wiki/Hypervisor
- https://www.ibm.com/topics/hypervisors?mhsrc=ibmsearch_a&mhq=hypervisor
- https://www.techtarget.com/searchitoperations/tip/Whats-the-difference-between-Type-1-vs-Type-2-hypervisor
- https://hackmd.io/@ncnu-opensource/book/https%3A%2F%2Fhackmd.io%2F%40108213034%2FB1_qNP2xc#Hypervisor
- https://hackmd.io/@ncnu-opensource/book/https%3A%2F%2Fhackmd.io%2F3EevJHwRSnep8pdlXd7YrA#Hypervisor
- https://philipzheng.gitbook.io/docker_practice/underly/namespace
- https://blog.quarkslab.com/digging-into-linux-namespaces-part-2.html
### Docker
- https://www.youtube.com/watch?v=0fFO2ez1dWA&t=380s
- https://kopu.chat/ibm-redhat/
- https://www.docker.com/resources/what-container/
- https://cbb104002.medium.com/docker-%E7%AD%86%E8%A8%98-5d1e0c8c3169
::: 
