Docker Operation
來自: http://wangzhezhe.github.io/blog/2016/01/29/docker-operation/
主要是記錄一些平時使用中常見的一些關于docker的小坑,就是所謂的docker operation吧,希望能通過現象看到本質才好,以后相關的問題都一點一點整理到這部分來。
dockero operation的一些基本的技巧:
批量刪除的常用命令
- 批量刪除停止運行的容器 docker rm $(docker ps -a -q) 不加-f的話 正在運行的容器就不會被強制刪除。
- 列出tag為none的相關鏡像 docker images |grep none |awk 'print{$1}'
參考: http://dockerone.com/question/197 容器鏡像本身問題比較大: 1)可能是container本身啟動就沒成功。這種情況下,通過docker ps | grep ${CONTAINER_ID}看到的container的status應該是非0,執行docker logs ${CONTAINER_ID}可以看到具體錯誤信息; 2)可能是container里根進程跑完退出了。這種情況下,通過docker ps | grep ${CONTAINER_ID}看到的container的status應該是非0。
關于打tag時候的一些說明
普通的情況下,容器的命名方式有兩種,一種是普通倉庫中構建出來的鏡像: 用戶名/倉庫名:標簽 如果在構建的時候不指定標簽的話,系統會默認指定標簽為latest,如果已經有了latest的標簽,則可以在 tag 的時候 使用-f 參數 將舊的容器覆蓋掉。 還有一種是頂層倉庫,就是在dockerhub中官方指定的,就需要再加上用戶名了,比如ubuntu:latest這種的。
當使用私有的registry的時候,需要在鏡像的名稱前面加上私有registry的ip以及端口的前綴,最后的鏡像名稱的完整的形式就是 私有registryip:端口/倉庫名/鏡像名:tag 這樣的形式,總之要把整個命名方式以及邏輯結構搞明白,之后再做一些事情的時候才能順手。
關于批量清理鏡像的相關問題(具體見博客中所說的): 這個命令可以列出當前 host 中所有的容器 后面可以跟 -a 或者是 -l -l表示僅僅顯示出最近的一個容器的 相關的信息 使用docker ps –n x 可以查看最后x個容器的信息,這個形式查看起來比較方便。 使用 –notrunc 命令可以查看出鏡像的全部的信息 使用-q參數可以僅僅列出id 批量刪除的時候會方便很多 比如使用幾個命令結合起來 docker kill $(docker ps -a -q) 這個命令可以刪除所有的正在正在運行和停止運行的容器,-a參數是列出全部的容器,-q參數是僅僅列出容器的id,kill命令會結束對應的容器的進程。 還有許多類似的批量清理的操作,比如 http://www.jb51.net/article/56051.htm ,可以參考網上的相關內容。 關于批量刪除none鏡像的命令 這個后續要好好調研一下 http://www.tuicool.com/articles/R7jMZfq
這個blog中說明了鏡像的存儲結構 具體涉及了 多個文件夾中存儲的內容 感覺還比較詳細: http://liubin.org/2014/03/10/about-docker-images-storage/
今天測試集群的時候 發現在從私有的registry中pull鏡像的時候報了一個奇怪的錯誤
開始的時候還真是白死不得其解 后來在老師的提醒下才發現 竟然是硬盤大小的原因 當然在資源不足的時候,registry并沒有很友善地提醒用戶 no space left on device的信息 ,而是直接在pull鏡像的過程中報一個 FATA[0000]Error: 鏡像名稱not foud的信息 這個還真是不太友好,要不是老師比較有經驗,還不知道要再這里多久。
關于v2的registry的digest(push鏡像時候的一個小trick): 在v2的registry支持degist的特性 如果 鏡像名相同的話 貌似之前已經傳好的鏡像就可以復用 不用重新上傳了 要是鏡像名不同的話 貌似即使是相同的鏡像層也會重新被push一下 被覆蓋掉
雖然鏡像的id 是一樣的 但是digist很可能是不一樣的 看一下 v2 registry的掛載的目錄 可以看到 是按照倉庫名來進行分類的 里面有每個倉庫中的鏡像的具體信息 _layers可能就是每個層的具體的信息???
https://blog.docker.com/2015/04/docker-release-1-6/ https://github.com/docker/docker/pull/11109
這個關于docker operation的操作很實用 里面有很多很好的技巧 http://segmentfault.com/a/1190000000482229
在構建image的時候,如果需要執行的直接是一個二進制的文件,就直接使用busybox作為基礎鏡像就比較好,不需要直接down一個ubuntu作為base image出來,busybox里面直接有linux的那些東西,體積比較小,適合那種二進制文件的直接運行。
版本升級的時候的一個bug 1.7.0剛開始的時候,bridge==none與net=host是有沖突的,之前卡了好久,還是jw翻源碼才解決的。具體的issue可以參考這個: https://github.com/docker/docker/issues/14106
docker 安裝指定版本: 雖然docker官方建議的安裝命令為sudo apt-get install lxc-docker(當然這之前還有不少的安裝和配置),
但是我一般都習慣于安裝指定版本,如安裝1.4.1時使用命令sudo apt-get install lxc-docker-1.4.1,安裝1.5.0的話就卸掉,直接使用命令sudo apt-get install lxc-docker-1.5.0
或許對你的問題幫助不大
如果你清楚了如何直接升級,也請留言通知哈
這里有一個版本: 采用不同的keys: http://stackoverflow.com/questions/27657888/how-to-install-docker-specific-version 這個可以安裝指定版本的docker就很簡單的幾步命令 https://get.docker.com/ubuntu/
今天又遇到幾個坑 首先一個是部集群的時候,發現有時候docker deamon無法正常啟動 常見的原因可能有幾個方面: 第一個是/etc/default/docker文件中,格式書寫錯誤,有的參數是空的,導致service docker restart之后,deamon仍然無法正常工作。
由于集群是自動部署的,在回復集群的腳本中,/etc/default/docker文件沒有被提前刪除掉,之后又把新的內容寫到了文件中。(刪除指令是寫在clean腳本中,使用ssh命令讓clean腳本執行,但有時總是刪不干凈,后來干脆先ssh 刪除一下,再執行)
還有一些及特殊的情況 docker 監聽的默認unix sock (默認位于/var/run/docker.sock)的文件屬性發生變化,有時會莫名其妙的變成一個目錄,這個時候,就會非常奇怪,雖然docker deamon進程是運行著的 但是docker 的命令并不能正常執行。此時要注意看docker deamon的日志文件 ,位于/var/log/upstart文件夾下,能看到一些信息。
關于docker deamon的 binaries 安裝方式 應該會有一點啟發 https://docs.docker.com/installation/binaries/
how to gracefully stop a container (valuabe) https://labs.ctl.io/gracefully-stopping-docker-containers/
questions: docker deamon died or forcely be killed 這個deamon所管理的那些容器 沒有被發送 kill 信號 這回導致它們嘗試 unmounting the device mappings created by volume shares with the docker host machine.
http://techblog.newsweaver.com/cleaning-up-device-mappings-after-docker-daemon-death/ delete the loop device : http://stackoverflow.com/questions/5881134/cannot-delete-device-dev-loop0
As a consequence, when we tried to restart the docker daemon it was not able to open /var/lib/docker/devicemapper/devicemapper/data because it was still mounted by the previous docker containers' volume shares (which do not show up with basic ls and lsof commands).
具體的解決方案是這個: 就是解除掛載再將掛載的文件刪除掉 就好了 for dm in /dev/mapper/docker-*; do umount $dm; dmsetup remove $dm; done
可以嘗試使用下面的命令 來找出所有掛載在指定目錄上的設備 之后 unmount 這些設備 之后就可以刪除新啟動的docker的文件夾了 mount |grep /var/lib/docker-bootstrap |awk ‘{print $1}’
關于mount命令以及unmount命令
采用 https://github.com/justone/dockviz 采用里面的二進制包就可以直接 使用 docker image -t 的功能
關于 docker 鏡像 docker history 可以查看鏡像的層次結構 每一層會執行了哪些操作
具體的目錄位置 以 /var/lib/docker/aufs 里面有三層個子目錄 : diff layers mnt 其中 diff中有每一層實際存儲進去的內容 layers中有每個鏡像所依賴的層次結構的id 最上面的一層 就是文件的名稱
鏡像的具體配置信息存儲在 /var/lib/docker/graph 目錄下 里面有三個文件 checksum json 以及layersize 其中layersize記錄了該層鏡像的總大小
在centos里面 重新配置docker0網橋的時候和在ubuntu中的不太一樣: https://github.com/docker/docker/issues/14425
遇到了一個docker -d 啟動是的時候網絡的錯誤 Error starting daemon: Error initializing network controller: Error creating default “bridge” network: failed to parse pool request for address space “LocalDefault” pool “” subpool “”: could not find an available predefined network 大概意思就是初始化網絡設備的時候,路由規則有沖突了。 解決方法就是 把eth0或者eth1關掉 再重啟docker就ok了 之后再把對應的網卡在啟動起來 貌似是那個路由規則沖突了 網上有些對應的阿里云啟動docker 第一次失敗的例子 也是類似的原因 主要就是 設置了某些路由規則 把docker0的那個pool給占用了 或者是使用了隧道之后也不行 要把對應的設備關掉 其實具體原因 還是不知道 只是知道大概怎么解決。。。
問題 df du 顯示結果不一致
df與du是查看磁盤占用空間常用命令,比如發現機器上的磁盤空間被占滿了,于是先用df看下整體的情況,之后看哪個盤占滿了,之后看哪個文件占了比較大的空間,于是從根目錄開始,每次向下遞歸一層,一次用如下命令查找: du -ah --max-depth=1 (--ah 表示all 以及 humanreadable)
df的時候發現磁盤空間是100%,du的時候,發現實際的文件并沒有占用那么大的空間。
最后lsof |grep delete發現好多docker的容器,之后把docker deamon重啟了一下,空間利用率就恢復正常了。df的時候也正常了。
df(disk free)與du(disk usage)的原理
du的時候往往會發現當文件夾下面的文件數目比較多的時候,速度會比較慢,因為du會逐個調用文件的fstat命令來查看文件的實際大小。
df使用的是statfs這個系統調用,會獲取到整個文件系統的狀態信息,相當于直接讀取的是元數據。
什么情況下會導致du與df顯示的結果不一致呢?
有進程占用了硬盤上的文件,而這些文件可能已經用rm刪除。實際上這些已刪除的文件 并未釋放硬盤空間 ,只是看不到而已,占用它的進程還在不停地往文件里寫,必須重啟這些占用進程才能釋放空間。 通常這種情況下可以使用 lsof |grep deleted 來看,之后再把對應的占用這些文件描述符的進程kill或者重啟,這樣這些空間就被釋放了。
比如在docker容器正常運行的時候,把它的某個很大的日志文件給刪掉,就會造成類似上面的情況。(事實上,在實際機器上,自己為了圖方便,常常執行這樣的操作),造成的后果就是df與du的結果不一致。
比如把一個正在運行中的容器的<容器id>.log文件強行刪除掉,這樣在lsof |deleted的時候會看到眾多的對于這個文件的寫操作。
如果想清空某個正在使用的文件,并且還保留之前的文件描述符,可以用O_TRUNC的標記來打開文件,這樣會把文件的長度設置為0并且丟棄文件中已有的內容。