# Docker 使用容器(Container) ++docker 程序是否存在,功能是否正常++ `docker info` ++新建並啟動++ ``` docker run hello-world docker run ubuntu /bin/echo 'Hello world' ``` ++啟動一個 bash 終端,允許使用者進行互動++ `docker run -i -t ubuntu /bin/bash` * -t 選項讓 Docker 分配一個虛擬終端(pseudo-tty)並綁定到容器的標準輸入上。 * -i 則讓容器的標準輸入保持打開。 ++查看系統中的容器列表++ `docker ps -a` 只看執行中的 `docker ps` ++指定容器名稱++ 有名稱方便重覆使用 `docker run --name my_ubuntu -i -t -v $PWD/website:/var/www/html/website ubuntu /bin/bash` * –name <指定名稱> : 可用字元 [a-zA-Z0-9_.-]。 * -v:掛載本地的目錄到容器中的目錄 - 重要的能力。在 Docker Toolbox 中只有 Users 目錄有權限。 * ++啟動已終止容器++ `docker start my_ubuntu` 用 ID 也可以 `docker start ac3f3b5f0f4e` ++進入已啟動的容器++ 重新啟動後,要 再進入 才能進行操作 `docker attach my_ubuntu` * attach 會接到啟動時指定的 /bin/bash 實例。所以多個視窗同時 attach 到同一個容器的時候,所有視窗都會同步顯示。 * 從 stdin 中 exit, 會導致容器停止。 `docker exec -i -t my_ubuntu /bin/bash` * 如果啟動時沒有下 /bin/bash,就要用 exec 去建立 bash 的實例。 * 從 stdin 中 exit, 不會導致容器停止。 ++以守護態(Daemonized)執行++ `docker run -d --name my_ubuntu2 ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"` * -d 參數 : 以守護態執行。 * -c 要執行的命令串。 * 只返回 ID。 * 輸出訊息不輸出到 Stdout 了。 * -p : 將容器內應甪程式的對外 port 對應到主機的 port,如 Oracle 為 -p 1521:1521 ++取得容器的輸出訊息++ ``` docker logs my_ubuntu2 docker logs -t -f --tail 10 my_ubuntu2 ``` * -t : 加上時間。 * -f : 持續列出最新。 * –tail 10 : 只列最後 10 筆。 ++停止容器++ `docker stop my_ubuntu2` ++查看容器內的進程++ `docker top my_ubuntu` ++容器的統計信息++ `docker stats my_ubuntu my_ubuntu2` * 可以列表方式看到多個內容。 ++取得容器的詳細資訊++ `docker inspect my_ubuntu` * 配合 -f 或 –format 來選定結果,如以下取得 ip address `docker inspect --format '{{ .NetworkSettings.IPAddress }}' my_ubuntu` * –format 支持完整的 Go 語言模板。 ++刪除容器++ `docker rm my_tmp_ubuntu` * 加上 -f 參數 : 刪除執行中的容器。 ++刪除全部容器++ > docker rm `sudo docker ps -a -q` * -q : 只回容器 ID。 ## 映像檔(Image) 及 倉庫(Repository) ++倉庫++ 包括映像檔,層及關於映像檔的資訊(metadata)。 每個倉庫可以存放很多映像檔(不同版本),如 ubuntu 12.04 16.04 18.04,利用 TAG 功能就可以指定到特定映像檔,如 ubuntu:16.04。 Docker Hub 的用戶倉庫命名由用戶名和倉庫名組成,如 john/shoppingweb; 頂層倉庫則只包含倉庫名,如 ubuntu。 列出映像檔 docker images 列出特定映像檔 docker images ubuntu 拉取映像檔 docker pull httpd 當 run 的時候本機還沒有所需的映像檔就會執行拉取。 查詢 Docker Hub 上可用映像檔 docker search aspnetcore 建立映像檔 用 docker commit 建立異動過的映像檔 如,在 my_ubuntu 中加入 apache2 後 docker commit 4aab3ce3cb76 user1/apache2 4aab3ce3cb76 : 容器 ID。 user1/apache2 : 用戶倉庫名。 commit 提交的只是建立時的映像檔和現在況態有差異的部份。 docker commit -m "Added apache" -a "Docker Newbee" 4aab3ce3cb76 user1/apache2:v2 -m : 說明訊息。 -a : 更新的使用者訊息。 已不推薦使用 docker commit 方法,最好用 Dockerfile。 用 Dockerfile 來構建映像檔 建立一個目錄做為構建環境。 編寫 Dockerfile 文字檔 : Dockerfile 由一系列指令和參數組成。 以 docker build 基於 Dockerfile 進行構建。 -t : 映像檔名稱 例子: Dockerfile # Version: 0.0.1  FROM ubuntu:16.04 MAINTAINER John Wick "john@example.com" RUN apt-get update && apt-get install -y nginx  RUN echo 'Hi, I am in your container' > /usr/share/nginx/html/index.html  EXPOSE 80 docker build docker build -t="user1/static_web" . 最後的 . 指定 Dockerfile 在同目錄中。 Dockerfile 的路徑可以是 Git repository 根目錄 : git@github.com:user1/docker-static_web。 Dockerfile 可以在子目錄中且不用叫 Dockerfile : path/to/file。 錯誤處理 可以用 docker run 執行失敗的映像檔到已成功的部份,再手動執行出錯的命令做調試,找到正確的命令。 不使用暫存資料 構建過程中,沒問題的映像會被暫存下來以加快下次執行,如果要它重頭執行不用暫存資料,加上 --no-cache。 docker build --no-cache -t="user1/static_web" . Dockerfile Dockerfile 由一系列指令和參數組成。每條指令,如 FROM,都必須為大寫字母,且後面要跟隨一個參數:FROM ubuntu:14.04。 Dockerfile 中的指令會按順序從上到下執行,所以應該根據需要合理安排指令的順序。 每條指令都會創建一個新的文件層並對映像檔進行提交。Docker 大體上按照如下流程執行 Dockerfile 中的指令。 Docker 從基礎映像檔運行一個容器。 執行一條指令,對容器做出修改。 執行類似 docker commit 的操作,提交一個新的文件層。 Docker 再基於剛提交的映像檔運行一個新容器。 執行 Dockerfile 中的下一條指令,直到所有指令都執行完畢。 註解 以 # 開頭的就是註解內容 FORM 第一條指令必須是 FROM,也是唯一必填指令。 FROM 指定一個已經存在的映像檔,後續指令都將基於該映像檔進行,這個映像檔被稱為基礎映像檔(base iamge)。 FROM <image> FROM <image>:<tag> FROM <image>@<digest> 如: FROM ubuntu:14.04。 MAINTAINER 映像檔作者資訊 MAINTAINER <作者資訊> 如: MAINTAINER John Wick MAINTAINER John Wick “john@example.com” RUN 在映像檔中執行命令 RUN <command> RUN ["executable", "param1", "param2"] RUN \:後面的命令其實是由 /bin/sh -c 來負責執行,所以,在映像檔中必須要有/bin/sh。 RUN [“executable”,”param1”,”param2”]:可以執行映像檔中任意一個可執行檔或命令,[]中的內容都會按照 JSON 字串的格式進行解析,因此只能使用雙引號 “。如用 bash 來執行: RUN ["/bin/bash", "-c", "echo hello"] 命令產生的結果預設會被後續所有指令重用。 CMD 用來設定映像檔預設執行命令 CMD ["executable","param1","param2"] CMD ["param1","param2"] CMD command param1 param2 第 1 種用法:是推薦的用法,其設定的命令將作為容器啟動時的預設執行命令。 第 2 種用法:param 將作為 ENTERPOINT 的預設參數使用。 第 3 種用法:將後面的命令作為 shell 命令,依靠 /bin/sh –C 來執行。 可以有多個 CMD,但只有最後一個 CMD 會生效。 LABEL 用鍵值對的形式來向映像檔中添加元數據(metadata) LABEL <key>=<value> <key>=<value> <key>=<value> ... 如: LABEL version=”1.0” 執行完命令之後,同樣會產生一個新的文件層。 新值會覆蓋舊值。 可以用 Docker 的 inspec 命令查詢。 EXPOSE 通知 Docker 容器中哪些端口是應用程序開出來監聽 EXPOSE <port> [<port>...] 容器啟動時配合 -p 或 -P 參數外部網路才可以訪問到這個 port。 ENV 設定環境變量 ENV <key> <value> ENV <key>=<value> ... 第 2 種用法:value 中存在空格時,需要使用「\」來進行轉義,如:ENV myDog=Rex\ The\ Dog \。 可以用 Docker 的 inspec 命令查詢。 COPY 向容器中指定路徑下添加文件 COPY <src>... <dest> COPY ["<src>",... "<dest>"] src 指定的路徑必須存在於 Dockerfile 所在目錄 如果使用 STDIN 輸入 Dockerfile 內容,那麼 COPY 命令將失效 ADD 將 src 標記的文件,添加到容器中 dest 所標記的路徑中去 ADD <src>... <dest> ADD ["<src>",... "<dest>"] src 指定的路徑必須存在於 Dockerfile 所在目錄或指定外部 URL。 dest 是指向容器中的目錄,其路徑必須是絕對路徑,或相對於 WORKDIR 的相對路徑。 dest 有沒有以 “/“ 結尾會影響資料寫入的目的地。src 使用通配字元指定多個文件時,dest 必須以 “/“ 結尾的目錄。 ENTRYPOINT ENTRYPOINT ["executable", "param1", "param2"] ENTRYPOINT command param1 param2 設定容器運行時預設執行程序 第 2 種用法:將後面的命令作為 shell 命令,依靠 /bin/sh –C 來執行。 如,MySQL官方提供的Dockerfile : ... COPY Docker-entrypoint.sh /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] EXPOSE 3306 CMD ["mysqld"] 當 mysql 容器運行時,自動執行 /entrypoint.sh,而參數則是 mysqld VOLUMN 在容器內部創建一個指定名稱的掛載點 VOLUME ["/data"] 如果在 Dockerfile 中已經聲明了某個掛載點,那麼以後對此掛載點中文件的操作將不會生效。 因此,通常只會在 Dockerfile 的結尾處聲明掛載點。 USER 切換用戶身份。當執行完命令後,後面所有的命令都將以新用戶的身份來執行 USER daemon WORKDIR 切換當前工作目錄 WORKDIR /path/to/workdir 影響到後續的 RUN、CMD、ENTRYPOINT、COPY和ADD指令中的路徑。 可以在 Dockerfile 中出現多次,但最終生效的路徑是所有 WORKDIR 指定路徑的疊加 (使用相對路徑時)。 只可以使用 ENV 設定的環境變量值。 ONBUILD 建立觸發命令集 ONBUILD [INSTRUCTION] 觸發命令集在當前 Dockerfile 執行過程中不會執行,而當此鏡像被其他鏡像當作基礎鏡像使用時,將會被觸發執行。