--- title: 'Docker 安裝、映像檔使用' disqus: kyleAlien --- Docker 安裝、映像檔使用 === ## OverView of Content 如有引用參考請詳註出處,感謝 :cat: [TOC] ## Docker 概述 ### Docker vs. 虛擬機 | 特性 | 容器 | 虛擬機 | | -------- | -------- | -------- | | 啟動速度 | 秒 | 分鐘 | | 性能 | 接近原生 | 較弱 | | 記憶體花費 | 少 | 多 | | 硬碟耗費 | MB | GB | | 運行數量 | 單個 PC 就可以運作上千個 | 單個 PC 大概幾十個 | | 隔離姓 | 安全隔離 | 完全隔離 | | 遷移性 | 佳 | 一般 | * Docker 與虛擬機的一大差異就是 **Docker 不需要 VMM (Virtual Machine Manager)、Hypervisor 支援**,Docker 是作業系統內核層級的虛擬化,**性能更高** ### Docker 虛擬化 * 虛擬化是一種資源管理技術,會將硬體的特性隔離出來,並透過抽象、Adapter 來完成實作的呼叫 (打破硬體差異的屏障) * 虛擬化有兩個大方向 1. 硬體虛擬化 2. 軟體虛擬化 (Docker),在軟體虛擬化的範疇中又有在細分為 | 虛擬化策略 | 說明 | 舉例 | | - | - | - | | 完全虛擬化 | 虛擬機完整模擬底層硬體環境、特權指令,使用者作業系統無須進行修改 | IBM p 和 z 系列虛擬化、VMware、Workstation、VirtualBox、QEMU | | 硬體補助虛擬化 | 利用硬體 (主要是 CPU) 支援控制敏感指令,來實現完全虛擬化,**使用者也不需要修改** | VMware Workstation、Xen、KVM | | 部分虛擬化 | 只針對部分硬體資源進行虛擬化,**使用者作業系統需要修改** | | | 準虛擬化 | 部分硬體介面以軟體的方式提供給客戶作業系統,**使用者作業系統需要修改** | 早起 Xen | | 作業系統虛擬化 | 核心透過建立多個虛擬的作業系統 (建立後會包含該系統所需的 Library),用來隔離不同的程序 | Docker、容器技術 | Docker 的虛擬化就是 **作業系統虛擬化** (透過核心建立,不需要 VMM、Hypervisor 效率更高) ## Docker 基礎 ### Docker 安裝 - Ubuntu * 這裡示範如何在 Ubuntu 安裝 Docker,但主要的安裝過程還是請參考 [**Docker 官方文檔**](https://docs.docker.com/engine/install/ubuntu/) 最準確 * **基礎工具、準備** ```shell= # 如果有舊的安裝,請先移除 sudo apt-get remove docker docker-engine docker.io containerd runc ``` >  1. 透過 apt 安裝必要 library ```shell= sudo apt-get update sudo apt-get install \ ca-certificates \ curl \ gnupg \ lsb-release ``` 2. 下載 && 設定 GPG Key ```shell= curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg ``` 3. 設定 stable repository (這樣才能安裝 Docker 引擎) ```shell= echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null ``` * **安裝 Docker Engine** ```shell= sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin ``` :::danger * **Window 子系統 Ubuntu `Network Unreachable`** ? Window cmd 中關閉 wsl,重新啟動 ```shell= wsl --shutdown ``` ::: * **在 Ubuntu 中啟動 Docker 服務** 1. 首先將 Docker 加入自身群組,並重新登入 ```shell= # 查看自身 whoami # sudo usermode -aG docker <自身> sudo usermode -aG docker alien # 檢查群組 cat /etc/group | grep docker ``` 2. 啟動 docker 服務 ```shell= service docker status sudo service docker start ``` >  :::info * 查看 系統所有服務 ```shell= ls -laF /etc/init.d ``` >  ::: ### Docker 測試 hello-world * **測試 Docker 運行是否正常** 1. Docker version ```shell= docker version ``` >  2. 嘗試跑 docker run hello-world ```shell= docker run hello-world ``` >  :::warning * **Window WSL 子系統 Ubuntu 安裝 Docker,無法 run Docker 容器 !?** > docker: Error response from daemon: OCI runtime create failed: container_linux.go:346: starting container process caused "process_linux.go:319: getting the final child's pid from pipe caused \"EOF\"": unknown. > ERRO[0012] error waiting for container: context cancele 最好的方法是升級 Window 的 WSL 版本到 2,[**參考**](https://www.omgubuntu.co.uk/how-to-install-wsl2-on-windows-10) ::: * **Docker 運作 Log** ```shell= tail /var/log/docker.logtail /var/log/docker.log ``` >  ### Docker 核心概念 * Docker 大部分操作都圍繞著**三個核心** 1. **Docker 映像檔** Docker 映像 (Image) 類似於虛擬機,可以理解為一個 **唯讀 (read only) 模板**,一個映像檔可以包含一個基礎作業環境 + 一個應用程式 > Apache 映像檔 = 基礎作業系統 + Apache 2. **Docker 容器** 容器就是一個沙箱 (看不見彼此),用來 **運行、隔離** 不同應用,容器也是 Docker 運行映像檔後的實體 (Instance) :::info * 映像檔本身是唯獨,容器從映像檔啟動後,Docker 會在映像檔的上層建立一個可寫入層 ::: 3. **Docker 倉庫** Docker 有提供一個 映像檔 Hub,裡面有很多映像檔;可以依據需求下載區要的映像檔 ## 映像檔操作 以下來學習使用指令操作映像檔 ### 下載 Docker 映像檔 * 下載映像檔關鍵指令 | 指令關鍵 | 說明 | 其他 | | -------- | -------- | -------- | | docker search <關鍵字\> | 透過關鍵字,搜尋到倉庫中相關映像檔 | 可以指定搜尋倉庫 | | docker pull NAME[:TAG] | 下載映像檔 | 如果沒有設定 tag 就會使用最新的映像檔 | | docker images | 查看本地已經有的應向檔 | 同 image list | | docker tag <NAME\> <TAG\> | 為已有的映象檔創建添加一個 TAG 標籤 | 但仍相同 image id | | docker inspect <映像檔\> | 檢查映像檔資訊 | | | docker history <映像檔\> | 檢查映像檔的建立紀錄 | 應該是該 image 的 commit 紀錄 | | docker rmi <映像檔 or id\> | 刪除映像檔 | 有另外一個很像的 `docker rm` 是拿來移除容器 | ```shell= # 搜尋 ubuntu docker search ubuntu # 下載最新 ubuntu docker pull ubuntu # 透過 tag 下載指定版本 ubuntu docker pull ubuntu:14.04 ``` >  * 可以透過指定 Registry url 來選定要搜索、pull 的倉庫,假設我要搜尋 Google 的 Registry (請先安裝 [**Google gcloud**](https://cloud.google.com/sdk/docs/install#deb)) ```shell= docker pull gcr.io/google-samples/hello-app:1.0 docker images ``` >  * 對已有的 image 檔創建自己的 TAG (觀察一下,兩者是有相同的 IMAGE ID) ```shell= # 給 'python:latest 添加 py tag' docker tag python:latest py docker images ``` >  ### 建立 Docker 映像檔 | 指令關鍵 | 說明 | 其他 | | -------- | -------- | -------- | | docker commit | 依據已有的容器創建 | 可以記錄你對 container 的操作紀錄,方便以後重複使用 | | docker import | 透過下載、現有檔案創建 | | * 建立映像檔的方法有三種 1. 基於 **==現有映像檔產生的 ++容器++==** 建立:使用 **commit** 指令對現有的 container 建立 :::info * 格式:`docker commit [OPTIONS] <Container id | name> [Repository[:TAG]]` ::: 使用 commit 指令 (有點類似 git commit),對現有 container 進行提交,**提交後 container 就會產生新 sha id** > Respository 取名必須小寫 > >  ```shell= # 查看所有 container docker ps -a # 透過 指定 container id e35 來提交 docker commit -m "First commit for container by id" -a "alien" e35 alien_image:0.1 # 透過 指定 container name determined_hellman 來提交 docker commit -m "First commit for container by name" -a "alien" determined_hellman alien:0.2 ``` >  2. 基於 Linux 容器 (LXC) 範例匯入:使用 **import** 指令,直接從一個作業系統範本匯入一個映像檔 :::info * 格式:docker import [OPTIONS] <Url | file | -\>-[Repository[:TAG]] ::: 這裡示範下載 [**ubuntu**](http://cdimage.ubuntu.com/ubuntu-base/releases/22.04/release/) ```shell= # import by url docker import http://cdimage.ubuntu.com/ubuntu-base/releases/22.04/release/ubuntu-base-22.04-base-amd64.tar.gz ubuntu_import:22.04 ``` >  ```shell= # 先下載到 download 資料夾 wget -P download/ http://cdimage.ubuntu.com/ubuntu-base/releases/22.04/release/ubuntu-base-22.04-base-amd64.tar.gz # import by file cat download/ubuntu-base-22.04-base-amd64.tar.gz | docker import - ubuntu_image_2:22.04 ``` >  3. 基於 Darkfile 建立 (這先跳過,以後再說) ### 儲存 or 載入 印象檔 | 指令關鍵 | 說明 | 其他 | | -------- | -------- | -------- | | docker save -o | 儲存現有 image | - | | docker load -input | 加載本地 image | - | 1. save:儲存 hello-world image 到 `~/images`,壓縮成 `hello-world.tar` ```shell= mkdir images docker save -o ~/images/hello-world.tar hello-world ``` >  2. load:加載本地 tar ```shell= docker load --input ~/images/hello-world.tar ``` >  ## 容器操作 有點類似虛擬機的創建,但是 Docker 所創建的容器需要的資源很少、創建速度快 * Container 的創建基於 Image,所以要先確保有 Image 再創建 ```shell= docker images ``` >  ### 創建運行 Container | 指令關鍵 | 說明 | 其他 | | -------- | -------- | -------- | | docker create | 依據 image 創建 Container | 創建出的 Container 狀態是 **==Created== (尚未運行),可透過 start 指令運行 container** | | docker start | 運行特定 container | 透過 id 指定 container,**啟動後狀態為 ==UP==** | | docker run | 創建 + 運行 container,可以看做 create + start 指令的結合 | 如果沒有 image 也會從倉庫自動下載 | 1. create:依照 `ubuntu:22.04` 映像檔創建 Container ```shell= # docker create [OPTIONS] IMAGE [COMMAND] [ARG...] # 創建 container docker create -it ubuntu:22.04 # 查看所有 container docker ps -a ``` >  由於 create 指令的 option 相當多,這裡不會都提及 (有用到才會說明),以需要可以透過 `docker create --help` 查詢 2. start:運行指定 container ```shell= # 查看所有 container docker ps -a # 啟動 id 38 (id 不用全部輸入) 的 container docker start 38 docker ps -s ``` >  3. run:建立 & 運行 container ```shell= # 依照 ubuntu:20.04 image 創建 container # 並運行 bin/echo 'Hello World' docker run ubuntu:20.04 /bin/echo 'Hello World' ``` >  docker run 常見的 OPTION 指令,完整請查看 `docker run --help` | Run's OPTIONS | 說明 | 其他 | | -------- | -------- | -------- | | -d | 背景運行 | 可透過 `docker attach <container id>` 進入前景 (id 透過 pa -a 查詢) | | -i | 可以使用者戶交 (可輸入指令) | - | | -t | 分配一個虛擬終端機 (pseudo-tty) | - | ```shell= # 啟動 run docker run -it -d ubuntu:20.04 docker ps -s docker attach acb ``` >  ### 停止、重啟 Container | 指令關鍵 | 說明 | 其他 | | -------- | -------- | -------- | | docker kill <id\> | 直接關閉容器 | 暴力 | | docker stop <id\> | 會對容器發送 SIGTERM 信號,約略 10s 後發送 SIGKILL 信號 | | | docker restart | 重新啟動容器 | | ```shell= # 先查看有哪些容器 docker ps -a # 啟動指定 容器 (ac 是 id) docker start ac # 查看正在運行的容器 docker ps -s ``` >  ### 進入已運行 Container | 指令關鍵 | 說明 | 其他 | | -------- | -------- | -------- | | docker attach <id\> | 將 Container 回到前景 | 當多個視窗訪問同一個容器時,所有視窗都會一起顯示 | | docker exec [OPTIONS] <id\> <COMMAND\> | 在已經啟動的容器中,執行任意命令 | 就像是對該容器重新創建了一個 tty 終端機 | :::warning 這兩個命令只能用在已啟動的部分 ::: * attach:將已啟動的 container 回到前景時,若有多個終端機訪問同一個 Container 則會 **++同步++ 顯示** >  * exec:執行一個新的命令,兩個不同視窗的命令不會相互影響 ```shell= # 啟動兩個視窗 # 以下的「ac」是 container id 的簡稱 docker exec -it ac /bin/bash ``` ### 刪除 Container | 指令關鍵 | 說明 | 其他 | | -------- | -------- | -------- | | docker rm <id\> | 移除容器 | 當容器正在運行中則無法刪除 (可用 -f) | ```java= # 查看當前有的容器 docker ps -a # 移除 id 為 33 的容器 docker rm 33 # 再次檢查容器是否已被刪除 docker ps -a ``` >  :::warning * 當容器正在運行時,則無法刪除,可以使用 `-f` 來強制關閉 (但不太好) >  ::: ### 匯出、匯入容器 | 指令關鍵 | 說明 | 其他 | | -------- | -------- | -------- | | export -o <輸出檔案> <id\>| 將容器輸出到本地 | 提醒:映像檔是 save `-o` | | import file \| Url - [Respository[:TAG]] | 用法同 **IMAGE 匯入** | 也就是匯入 image,container 要手動啟動 | 1. 輸出指定 container ```shell= # 創建一個 container 資料夾 mkdir -p container # 輸出 container 到 ~/container 資料夾中 docker export -o ~/container/myContainer.tar e3 ``` >  2. 輸入指定 tar 檔案,再查看 image 檔 ```shell= cat ~/container/myContainer.tar | docker import - my_container:0.3 # 查看 images docker images ``` >  ## Appendix & FAQ :::info ::: ###### tags: `Docker`
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up