<span style="font-size:70px">Docker 入門</span>
===
![](https://i.imgur.com/ke4hVwT.png =140x)
#### 郭柏均 (Titangene)
- E-mail: [titangene.tw@gmail.com](mailto:titangene.tw@gmail.com)
- GitHub: [titangene](https://github.com/titangene)
- Blog: titangene.github.io
---
## 什麼是 Docker?
Docker 字面上的意思是「碼頭工人」,碼頭上會有打包、運送...等服務,碼頭工人 (Docker) 可快速的用貨櫃 (Container) 將貨物 (Application) 裝上船。
![](https://i.imgur.com/Mr9AHqV.jpg =460x)<span style="font-size:16px">[Ref](https://twitter.com/Docker/status/913554944069791744)</span>
---
- Docker 是一種容器化技術 (輕量級的虛擬化技術),可以把你的應用程式連同環境一起打包,部署的時候不用擔心環境的問題
<!-- 後面會介紹什麼是容器化技術,什麼是虛擬化技術 -->
- 原始碼在 GitHub 上進行維護,專案名稱為 [Moby](https://github.com/moby/moby)
- 使用 Go 語言開發
- 不需要用到 Hypervisor,直接利用硬體效能
---
## Docker 能做什麼?
建置 image,然後使用 Registry 來管理 image,再使用 Docker Engine 將 container 和包含的 App 在任意平台 (不管是實體機、虛擬機還是雲端) 上執行
![](https://i.imgur.com/n3w1SOT.png =460x)<span style="font-size:16px">[Ref](https://blog.docker.com/2016/09/dockerforws2016/)</span>
<!--
可以簡化重建環境的過程、降低維運成本,並且讓開發、測試和正式環境無縫接軌。
從開發 (Dev) 到維運 (Ops) 端[^1],不管是在實體、虛擬還是雲端的環境下,都可以在 Windows 或 Linux 平台上,透過 dcoker 建立各種 App 服務環境 (Container),彼此不受影響。
[^1]: 環境佈署與開發通常是不同⼈來負責,而且通常正式環境與開發環境都不同
-->
---
### 為什麼要使用 Docker?
以 Node.js 為例,每個專案都需要有開發環境
![](https://i.imgur.com/LQjXf25.png =700x)
---
## 傳統架構缺陷
- 維護成本高 (機器硬體維修汰換)
- 建置機器複雜 (雖然有寫 Shell Script)
- 24 小時 on call (公司隨時都有人加班,有問題就要馬上修)
- 系統擴充困難
---
### 如果把架構換成 VM 呢?
<span style="font-size:30px">雖然較省錢,但每個專案都需維護 VM 檔案,以 VMware 為例,包括 虛擬磁碟 (.vmdk)、VM 的記憶體 (.vmem)、虛擬 BIOS (.nvram)、設定檔 (.vmx)、補充設定檔 (.vmxf)、紀錄檔 (.log)、快照 (.vmsd)、快照狀態資訊 (.vmsn)、紀錄 VM 暫停狀態 (.vmss) ... 等檔案</span>
```shell
D:\VM\Ubuntu $ ls -al
total 30558838
drwxr-xr-x 1 Titan 197609 0 一月 10 01:42 .
drwxr-xr-x 1 Titan 197609 0 八月 10 11:21 ..
-rw-r--r-- 1 Titan 197609 8684 一月 10 01:42 'Ubuntu.nvram'
-rw-r--r-- 1 Titan 197609 27544518656 一月 10 01:42 'Ubuntu.vmdk'
-rw-r--r-- 1 Titan 197609 0 八月 6 21:37 'Ubuntu.vmsd'
-rw-r--r-- 1 Titan 197609 2994 一月 10 01:42 'Ubuntu.vmx'
-rw-r--r-- 1 Titan 197609 383 八月 6 23:17 'Ubuntu.vmxf'
-rw-r--r-- 1 Titan 197609 3741319168 一月 10 00:59 'Ubuntu-f82919f4.vmem'
-rw-r--r-- 1 Titan 197609 6130557 一月 10 01:42 'Ubuntu-f82919f4.vmss'
-rw-r--r-- 1 Titan 197609 270160 一月 10 01:42 vmware.log
...
```
---
### VM 的缺點
- 吃系統記憶體資源
- 切換多重專案浪費時間
- 浪費主機硬碟空間
- ...etc
---
## 改用 Docker 後
- 不需要額外的機器及人力維護成本
- 各專案可透過 Dockerfile 將環境進行版本控制
- 可以利用 Dockerfile 把環境寫成一個檔案,在透過 Dockerfile 快速建立環境<!--(之後會介紹)-->
- 任何環境都可執行:不管是實體機、虛擬機、雲端,不管系統是 Windows、Linux 都可以
---
## 所以為什麼要使用 Docker?
- 容易部署
- 快速建置環境,可自動建立開發環境
- 開發與正式環境一致
- 環境 (資源) 隔離
- 資源有效利用 (直接使用系統資源)
- 降低維運成本
- 比虛擬化技術更輕量<!-- (容器化技術,後面會介紹) -->
---
### Virtualization vs Containerization
(虛擬化技術 vs 容器化技術)
![](https://i.imgur.com/onQLun8.png =800x)
---
## 名詞解釋
- Host OS:實體電腦的 OS。
- Guest OS:從 Host OS 裡面啟動的 VM,上面所跑的 OS 稱為 Guest OS。
- Hypervisor:Host OS 裡面負責管理 VM 的 Apps 稱為 Hypervisor 或 Virtual Machine Monitor (VMM,虛擬機器監視器),Hypervisor 是在硬體層虛擬化。
---
## 虛擬化技術 (Virtualization)
常見:VirtualBox、VMWare
以往的虛擬化技術是在 Host OS 上建立虛擬環境,透過 Hypervisor 模擬一套完整的硬體環境資源 (Guest OS),目標是建立一個可以用來執行整套 OS 的沙箱獨立執行環境,所以 VM 可以建立多個獨立的環境,使用者就能 Guest OS 上安裝其他應用程式
---
## 容器化技術 (Containerization)
而容器化技術則是透過在 Host OS 上執行 Container Engine 來建立各個 Container (虛擬執行環境,直接使用 Host OS 的系統資源),每個 Container 也都是彼此獨立,但 Container 是共用相同的核心,共享系統資源
Docker 為什麼會比傳統 VM 輕量?
因為少跑了 N 個完整的 Guest OS
---
其實 container (容器) 和 VM 的目標是相似的,都是為了將 APP 和其依賴分離成可以在任何環境上獨立執行。另外,container 和 VM 減少了對於實體硬體的需求,無論是在成本和效益上,都可以更加有效的利用運算資源。
---
#### Docker 為什麼會比傳統 VM 輕量?
<!--
因為少跑了 N 個完整的 Guest OS,下面就是 Virtualization 和 Containerization 的比較表:
-->
| | Virtualization | Containerization |
| ------------- | --------------- | ---------------- |
| 啟動 | 慢 (最快也要分鐘) | 快 (秒開) |
| 容量 | 大 (GB) | 小 (MB) |
| 效能 | 慢 | 快 |
| host 可支撐數量 | 數個~數十個 | 數個~數百個 |
| 複製相同環境 | 超慢 | 快 |
---
## Docker with VM
![](https://i.imgur.com/Fmz53QA.png)
---
- Docker 和 VM 不只可以單獨的使用,也可以搭配使用。
- 假如要確保整體系統完整的虛擬化,就要先用 VM 安裝 OS,然後在 VM 中的 OS 上使用 Docker 啟動需要執行的 container。
- 可以按照使用者的使用情境來決定要如何安排使用 VM 和 Docker。
---
#### Docker 部署在實體伺服器 vs 部署在 VM 中
原生硬體的效能遠遠超過 VM 的模擬硬體效能,將 Docker 直接安裝在實體伺服器的 Linux 中,一定比先安裝 VM Linux,再在此 VM 中執行 Docker 要快上許多。但企業考量的重點除了效能之外更有部署的便利性、現存系統的穩定度、整個系統的高可用性等重點,筆書建議還是將 Docker 部署在 VM 中,犧牲一點點效能,換來的是更方便的部署、更穩定的環境以及更彈性的設定,這是絕對值得的。
> 本頁摘至[最完整的 Docker 聖經](https://joshhu.gitbooks.io/docker_theory_install/content/DockerBible/macwindowsdocker.html)一文
---
## Docker 三個基本概念
---
## Image (映像檔)
- 唯讀模式 (R\O)
- 用來建立 Container 的模板
- 包含軟體執行所需的所有內容:code, runtime, system tools, system libraries, settings
- 可從 Repository 下載到別人做好的 image 來直接使用
---
## Container (容器)
- 讀寫模式 (R\W)
- 也是貨櫃的意思
- 可將軟體執行所需的所有資源打包到一個隔離的容器中
- 可解決環境不一致的問題 (例如:雲端、OS、套件版本...等環境)
- 一個 image 可以創造出多個不同的 container
- Docker 利用 Container 來執行應用
---
## Registry (倉庫)
- 集中存放 image 的地方
- Repository (倉庫,儲存庫) vs Registry (倉庫註冊伺服器)
- Registry:儲存和託管 image 的服務,Docker 預設的 Registry 是 Docker Hub
- Repository:提供不同版本 (tag) 的相同應用程式或服務的集合
<!-- 例如:[Ubuntu](https://hub.docker.com/r/library/ubuntu/) 官方提供不同 tag 的 Docker image,每個的 tag 都是對應到各個版本,而這些 tag 會以數字或英文的方式命名 (例如:14.04、stable、latest),會以 `ubuntu:latest` 的方式指定該 image -->
---
## Registry (倉庫)
- Registry 上存放著多個 Repository,每個 Repository 中又包含了多個 image,每個 image 有多個不同的標籤 (tag),標籤會以數字或英文的方式命名 ([舉例](https://hub.docker.com/_/mysql))
- Registry 分為公開 (Public) 和私有 (Private) 兩種形式
- 最大的公開 Registry 是 Docker Hub,存放了大量的 image 供使用者下載
- 使用者也可以在本地端內建立一個私有 Registry
---
## Docker 是怎麼運作的?
![](https://i.imgur.com/lmxEKpN.png)
<!--
Docker 就像是個有燒錄功能的光碟機,它可以幫你把要執行的東西自動化的燒成光碟片 (Image 檔) 並放到光碟櫃上 (Docker Hub / Docker Registry),然後,各個電腦上的光碟機可以自動的從光碟櫃上取回最新版或指定版本的光碟片來啟動最新的程式 ( `docker Run` )
-->
---
## 安裝 Docker
詳情請參考官方的 [Install Docker](https://docs.docker.com/engine/installation/) 文件
```shell
# 檢查版本
$ docker -v
Docker version 17.12.0-ce, build c97c6d6
```
---
## Play with Docker
如果你不想安裝 Docker,有另一種方式可以練習 Docker,那就是 Docker 官方提供的 [Play with Docker (PWD)](https://labs.play-with-docker.com/)
![](https://i.imgur.com/gftZ01A.png =460x)
---
進去後會看到一個倒數的時間,因為每次 PWD 會提供 4 小時的使用時間。接著只要按「+ ADD NEW INSTANCE」就可以建立一台新的 VM。
![](https://i.imgur.com/UHf3WEQ.png)
---
看到 shell 就可以開始練習 Docker
![](https://i.imgur.com/0jC17YU.png)
---
## Hello Docker
執行 `docker run hello-world` 指令後,會看到下面一大串輸出:
```shell
$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
ca4f61b1923c: Pull complete
Digest: sha256:66ef312bbac49c39a89aa9bcc3cb4f3c9e7de3788c944158df3ee0176d32b751
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://cloud.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/engine/userguide/
```
---
它會告訴你執行此指令都做了哪些事:
1. Docker client 直接跟 Docker daemon 溝通。
2. Docker daemon 從 Docker Hub pull `hello-world` 此 image 回來。
3. Docker daemon 從該 image 建立一個新的 container,該 container 執行執行檔來產生下面這堆輸出。
4. Docker daemon 將輸出串流傳輸到 Docker client,並將其發送到終端。
---
可以到 Docker Hub 看 [`hello-world` 這個 image](https://hub.docker.com/_/hello-world/),裡面有官方提供產生該 [image 的 `Dockerfile`](https://github.com/docker-library/hello-world/blob/master/amd64/hello-world/Dockerfile):
```dockerfile
FROM scratch
COPY hello /
CMD ["/hello"]
```
- `FROM scratch`:使用哪個 image 作為基底 (Base Image),[`scratch`](https://hub.docker.com/_/scratch/) 是官方提供的空白 image
- `COPY hello /`:將 `hello` 執行檔複製到 `/` 根目錄
- `CMD ["/hello"]`:執行 `hello` 此執行檔
---
簡單來說就是在 container 裡面執行 `hello` 這個執行檔來列印出這堆訊息。
---
### Docker 常用指令
![](https://i.imgur.com/DHTpUuz.png =720x)<span style="font-size:16px">[Ref](https://philipzheng.gitbooks.io/docker_practice/content/appendix_command/)</span>
---
# ...etc
接下來會講的方向:[titangene/docker-lamp](https://github.com/titangene/docker-lamp)
- Docker 基本指令
- Dockefile
- Docker Hub
- Docker Compose
---
## `info`:查看 Docker 系統資訊
```shell
$ docker info
```
---
## `pull`:取得 (拉取) image
- 如果 pull image 時沒有指定 tag,預設 pull 的 image tag 會是 `latset` 版
- 為甚麼會出現 `Already exists`?在 pull image 時,如果主機內已有的 image 中有某些地方相同,就不需要再 pull 一次
<!--
- 在 pull 時為什麼會一層一層跑?因為整個 Docker image 是一層一層的結構
- 很像 `git pull` 一樣,不會從頭到尾全部 pull,只會 pull 不同的地方
-->
```shell
$ docker pull [repository name]:[TAG|@DIGEST]
$ docker pull node:boron-slim
boron-slim: Pulling from library/node
ad74af05f5a2: Already exists
2b032b8bbe8b: Already exists
a9a5b35f6ead: Pull complete
3245b5a1c52c: Extracting [========> ] 54.03MB/131.9MB
afa075743392: Download complete
...
```
{"metaMigratedAt":"2023-06-14T21:46:35.969Z","metaMigratedFrom":"YAML","title":"Docker 入門 - 簡報","breaks":true,"contributors":"[{\"id\":\"453ca780-a4fc-4672-ac30-81675bf1cc0c\",\"add\":11011,\"del\":1716}]"}