# Docker入門 ###### tags: `Container` `Docker` ## 簡介 Docker用比較熟知的東西來介紹的話,就是傳統虛擬機(VMware之類的)的概念。 跟傳統虛擬機的具體差別在於: 1. 虛擬機會基於原有的OS再安裝一個Guest OS,並且共同使用本機的硬體資源,所以使用會占用很多資源。 2. Docker是直接在原有的OS上形成一個「容器Container」,並將需要模擬的東西全都放在這裡面執行,不需要多加一個Guest OS吃硬體資源。 基於以上,同樣的裝置可能只跑10個虛擬機就會卡到往生,但可以跑數百甚至數千個Docker。 ### Docker特點 1. 部署容易: 可以建立一個固定的映像檔重複使用,統一Docker Container中的內容,實現「標準化」。 2. 兼容性高: Docker可以在各式各樣的平台上執行,所以很容易遷移到不同端點→可以在這邊開發,最後實用在那邊。 ### Docker vs. Virtual Machine | 特性 | Docker | Virtual Machine | | -------- | -------- | -------- | | 啟動時間 |  秒級  |  分鐘級 | | 佔用空間 | MB   |   GB  | |  效能  | 接近原生 | 弱於原生 | | 驅動數量 |  數千  |  數十  | | 隔離級別 | 系統級  |  進程級 | ## Docker的組成 1. 映像檔(Image) 2. 容器(Container) 3. 倉庫(Repository) > **倉庫註冊伺服器**中有若干**倉庫**,倉庫中又有若干**映像檔**。 > (Registry包著Repository然後包著Image) ### 映像檔 Image * 用來**建立容器** * 如同虛擬機要灌作業系統的iso檔 > 註:映像檔是<font color = "red">唯讀</font>的。 ### 容器 Container * 如同灌在虛擬機的**作業系統**的用途 * 彼此間**完全隔離,不互相干擾** ### 倉庫 Repository * 存放映像檔的地方 * 分為<font color = "green">公有Public</font>跟<font color = "green">私有Private</font> * 概念與Github相似,都是用push上傳、pull下載 * 最大的公有倉庫是[Docker Hub](https://hub.docker.com/) ## 映像檔 Image 映像檔是建立容器的必要條件。 需要用到的映像檔必須存在本機上;如果在本機端找不到,會從Repository中找尋並下載(預設是Docker Hub)。 ### 取得映像檔 `docker pull 註冊伺服器位址/倉庫名稱:TAG` 若無特別指定註冊伺服器位址,則預設是從Docker Hub抓取映像檔。 ### 列出已有映像檔 `docker images`可以列出本機現有的映像檔。 ![](https://i.imgur.com/5bHfGMZ.png) * REPOSITORY:倉庫名稱 * TAG:該映像檔的標籤 * IMAGE ID:該映像檔的ID(唯一) * CREATED:下載映像檔的時間 * VIRTUAL SIZE:映像檔的大小 > 註:映像檔的ID是唯一的,如果看到重複的ID表示兩者是一樣的映像檔,彼此間以TAG區分。建立/下載映像檔時,若沒有特別寫明TAG,預設以lastest表示。 ### 修改映像檔 先啟動,然後對它作想修改的事情後,輸入`exit`退出。 > [color=#FF0000] 啟動後,會出現root@ID,要記住這個ID才可以在之後commit時順利更新,不然就要用`docker image`自己找了。 接著用`docker commit`更新。 舉例:`docker commit -m "說明文字" -a "使用者資訊" ID 倉庫名稱:TAG` > 前面有提到映像檔是<font color="red">唯讀</font>的,所以所謂的修改其實應該是指「增加功能」。 ### 建立映像檔 要建立一個映像檔必須先有Dockerfile,因為裡面有建立時所需要用到的指令。 ```bash mkdir 資料夾名稱 #先創立一個資料夾 cd 資料夾名稱 #進入創立的資料夾 touch Dockerfile #建立Dockerfile ``` Dockerfile中,每一行都是一個指令。 建立好Dockerfile後,用編輯器打開來增修內容(`vi Dockerfile`或`vim Dockerfile`等)。 舉例: ```dockerfile FROM 倉庫名稱:TAG #基底映像檔 MAINTAINER 維護者/開發者資訊 RUN apt-get -qq update #執行這個映像檔時要做的事情 RUN gem install sinatra ``` > 註:執行Dockerfile的期間,每一個指令都會建立一個容器,並做出對應的修改,等到全部執行完之後,會把過程中建立的容器清除。 好了之後用`docker build`建立映像檔。 舉例:`docker build -t="倉庫:TAG" 路徑` * -t:增加TAG * 路徑:用 .表示原本的路徑,也可以直接指定絕對路徑 ### 上傳映像檔 `docker push 倉庫名稱` 如此可以把指定倉庫的映像檔全都推上註冊伺服器。 ### 刪除映像檔 先用`docker rm`刪除依賴於欲刪除之映像檔的容器,再用`docker rmi 倉庫名稱`把本機端的指定倉庫刪除。 因為容器是基於映像檔建立的,所以有依賴性,不能直接刪掉映像檔。 ### 小結 從修改、更新、上傳映像檔的功能來看,可以理解為何docker的擴充性很好。 ## 容器 Container ### 啟動容器 `docker run -it ubuntu /bin/bash` * -英文字母:有的沒的功能 -i:交互式操作(互動模式,反正就是可以用終端下指令) -t:Docker分配一個虛擬終端至容器上 * ubuntu:映像檔名稱 * /bin/bash:命令。因為用-i需要有交互式Shell,因此用的是 /bin/bash 使用`docker run`的指令時,內部存在以下行為: 1. 檢查本地是否存在指定的映像檔,不存在就從公有倉庫下載 2. 利用映像檔建立並啟動一個容器 3. 分配一個檔案系統,並在唯讀的映像檔層外面掛載一層可讀寫層 4. 從宿主主機設定的網路橋界面中橋接一個虛擬埠到容器中去 5. 設定一個 ip 位址給容器執行使用者指定的應用程式 6. 執行完畢後容器被終止 (這一步也可以用`docker stop`自己來) 容器的核心為所執行的應用程式,所需要的資源都是應用程式執行所必需的。除此之外,並沒有其它的資源。可以在虛擬終端中利用 ps 或 top 來查看程式訊息。 ### 後台執行容器 有時候容器不需要在前台一直運作,只要在後台就可以了,這時候只要加入`-d`參數就能達到。 `docker run -d 倉庫:TAG` * -d:表示Daemonized(守護態),亦即在後台執行 如果需要查看相關資訊,可以用以下指令: * `docker ps`列出容器資訊,包含<font color="brown">ID、基於什麼映像檔而成、命令、創建時間、現在狀態、Port、名稱</font>等。 * `docker log`可以看後臺執行的容器的輸出。 ### 進入後台執行中的容器 有以下幾個方式: * 命令 1. `docker exec`用法相當於`docker run`,不過是針對容器 如`docker exec -it 容器名稱 bash`就是以bash方式跟指定容器溝通。 2. `docker attach`是直接進入容器 可以多個窗口同時叫出同一個容器,但每個窗口會同步 (有一個窗口死掉的話,其他的也會同時死掉) * 工具 - nsenter 具體使用方法[參考這裡](https://www.awaimai.com/737.html)。 ### 終止容器 `docker stop 容器ID`可以停掉整個容器。 如果是只包含一個終端機的容器的話,輸入`exit`或按`ctrl+D`也會終止。 一般而言,被終止的容器用`docker ps`是看不到相關資訊的,如果還想看的話必須加上參數`-a`。 想要啟動停止的容器的話,可以使用`docker start`。 想要重新啟動正在運作的容器的話,可以使用`docker restart`。 ### 匯出匯入 * 匯出 1. `docker export 容器ID > 指定檔名.附檔名` 這個指令會將<font color="red">容器**快照**</font>匯出,存成指定檔案。 > 快照:僅保存容器**當下**的狀態,不包含歷史訊息。 2. `docker save 指定檔名.附檔名 > 倉庫:TAG` 可以發現存的東西是映像檔的TAG,所以儲存最原始的、沒被改過的映像檔。 基本上這個對存容器沒什麼用,應該也不會用到...,畢竟映像檔可以直接從倉庫抓。 近年來幾乎不太用`save`跟`export`了,都直接用Dockerfile做。 * 匯入 1. 容器快照 `docker import 檔案 倉庫:TAG` 此指令會讓容器連著映像檔一起匯入。 2. 映像檔 `docker load 檔案` 單純匯入映像檔,跟上倉庫抓一模一樣。 ### 刪除容器 1. 刪除終止的容器 `docker rm` 2. 刪除執行中的容器 `docker rm -f` (-f是force的意思,Docker會發送`SIGKILL`信號給容器。) ## 倉庫 Repository 倉庫是存放映像檔的地方,容易混淆的概念是註冊伺服器。實際上註冊伺服器是管理倉庫的具體伺服器,每個伺服器上可以有多個倉庫,而每個倉庫下面有多個映像檔,所以可以將倉庫認為是一個具體的專案或目錄。 倉庫分為公有及私有,最大的公有倉庫是Docker Hub,基本上任何需求的映像檔都可以直接從上面抓取。 ### 登入Docker Hub `docker login 位址` 位址是選填的,可以不寫,預設為Docker Hub。 ### 搜尋公有倉庫中的映像檔 先登入公有倉庫後,輸入`docker search 作者/映像檔名稱` 作者為選填,可以不寫,就會列出所有對應名稱的映像檔;如果寫了作者就只會列出該作者的對應映像檔。 Docker Hub就像Github一樣,可以給星星,所以如果想要找「幾顆星以上」的映像檔的話,可以加入參數`-s N`,N為星星數量。 ### 建立私有倉庫 使用官方提供的docker-registry工具,建立私有的映像檔倉庫。 1. 安裝docker-registry工具 以Ubuntu為例: ```shell apt-get install -y build-essential python-dev libevent-dev python-pip liblzma-dev swig pip install docker-registry ``` 或是直接clone Github上的對應專案: ```shell apt-get install build-essential python-dev libevent-dev python-pip libssl-dev liblzma-dev libffi-dev git clone https://github.com/docker/docker-registry.git cd docker-registry python setup.py install ``` 直接clone的話要記得做[一些設定](https://philipzheng.gitbook.io/docker_practice/repository/config)。 2. 開始建立私有倉庫 `docker run -d -p 1234:5678 -v 路徑 --restart=always --name 指定倉庫名稱 registry` * 參數說明: * -d:在背景執行(=守護態模式)(非必要) * -p:主機的port mapping到容器的port(必須,數字自訂) * -v:指定私有倉庫的路徑(非必須,未指定則預設在容器的/tmp/registry下) * --restart:當Docker重新啟動或停止時,這個本地倉庫是否要重新啟動。 * --name:想要給這個私有倉庫的名稱。 ### 上傳映像檔至私有倉庫 1. 先使用`docker tag 欲推映像檔 私有倉庫位址:PORT/(USERNAME/)名稱:TAG`給欲上傳的映像檔標記。 2. 接著用`docker push 私有倉庫位址:PORT/(USERNAME/)名稱:TAG`,這樣就會把映像檔推到指定位址的私有倉庫上了。 3. 之後在別的機器上用`docker pull 私有倉庫位址:PORT/(USERNAME/)名稱:TAG`就可以把剛剛推上去的映像檔給拉下來。 > <font color="red">注意:推上倉庫的容器中的資料不會保存,只會存容器本身的設定(基底映像檔、有何app...),若要儲存執行中所經手的資料,就要用到別的工具,如**Volumes**。</font> ## 參考文件 1. [Docker Docs - Product Manual](https://docs.docker.com/engine/) 2. [Docker - 從入門到實踐](https://philipzheng.gitbook.io/docker_practice/) 3. [雲原生的基石,一文讀懂容器](https://blog.csdn.net/jdcdev_/article/details/105083933) 4. [全面易懂的Docker指令大全](https://joshhu.gitbooks.io/dockercommands/content/index.html) 5. [Docker教程](https://www.runoob.com/docker/docker-tutorial.html) 6. [比較save, export對於映象檔操作差異](https://blog.hinablue.me/docker-bi-jiao-save-export-dui-yu-ying-xiang-dang-cao-zuo-chai-yi/) 7. [用30天來介紹和使用 Docker](https://ithelp.ithome.com.tw/users/20103456/ironman/1320) 8. [Docker 基本教學 - 從無到有 Docker-Beginners-Guide](https://github.com/twtrubiks/docker-tutorial)