乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      無(wú)標(biāo)題

       野貓愛(ài)魚(yú) 2021-04-03

      同任何相對(duì)復(fù)雜的軟件項(xiàng)目一樣,Docker有很多細(xì)節(jié)問(wèn)題和缺點(diǎn),如果想要讓用戶體驗(yàn)盡可能地流暢,知道這些很重要。

      本章講述的一些技巧將會(huì)向讀者展示其中更為重要的一些部分,而且會(huì)介紹如何使用一些第三方構(gòu)建的外部工具來(lái)解決自身問(wèn)題。不妨把它看作一個(gè)Docker工具箱。

      6.1 保持陣型

      如果你跟我們一樣(并且有心關(guān)注本書(shū)),那么你對(duì)Docker的依賴將會(huì)與日俱增,這也就意味著會(huì)在選定的宿主機(jī)上啟動(dòng)大量容器,然后下載更多的鏡像。

      隨著時(shí)間的流逝,Docker將會(huì)消耗越來(lái)越多的資源,一些容器和卷的清理需要擺上日程。我們將會(huì)展示怎么做以及為什么這樣做。我們也會(huì)介紹一些用來(lái)保持Docker環(huán)境干凈整潔的可視化工具,以便讓不喜歡敲命令行的用戶可以從中解脫出來(lái)。

      正在運(yùn)行的容器都很好,但是用戶很快會(huì)發(fā)現(xiàn)自己想要的不僅僅是在前臺(tái)啟動(dòng)一個(gè)單條命令。我們會(huì)一起來(lái)看看如何在不“殺死”該容器的前提下退出一個(gè)正在運(yùn)行的容器,還會(huì)看看如何在一個(gè)正在運(yùn)行的容器內(nèi)執(zhí)行命令。

      技巧41 運(yùn)行Docker時(shí)不加sudo

      Docker守護(hù)進(jìn)程以root用戶身份在機(jī)器的后臺(tái)運(yùn)行,這給了它莫大的權(quán)力,同時(shí)它又是對(duì)你,即終端用戶開(kāi)放的。需要使用sudo是一個(gè)結(jié)果,但是這樣做不太方便,而且也會(huì)造成一些第三方Docker工具無(wú)法使用。

      問(wèn)題

      想要無(wú)須sudo便可以執(zhí)行docker命令。

      解決方案

      官方解決方案是把自己加到docker組。Docker通過(guò)一個(gè)用戶組圍繞著Docker Unix域套接字來(lái)管理權(quán)限。為安全起見(jiàn),發(fā)行版默認(rèn)不會(huì)將用戶加到該用戶組里,因?yàn)檫@樣做會(huì)開(kāi)放系統(tǒng)完整的root訪問(wèn)權(quán)限。

      把自己加到該用戶組后,用戶便能以自己的身份使用docker命令:

      $ sudo addgroup -a username docker

      重啟Docker然后完全注銷并再次登錄,或者更簡(jiǎn)單點(diǎn),重啟機(jī)器。現(xiàn)在執(zhí)行Docker命令時(shí)不用再留意鍵入sudo或設(shè)置別名了。

      討論

      對(duì)于本書(shū)后面部分用到的一系列工具來(lái)說(shuō),這是一項(xiàng)極其重要的技巧。一般來(lái)說(shuō),任何想要和Docker通信的對(duì)象(無(wú)須在容器里啟動(dòng))都需要能夠訪問(wèn)Docker套接字,這需要使用sudo或者使用本技巧里提到的設(shè)置。技巧76里引入的Docker Compose是Docker公司的官方工具,也是這類工具的一個(gè)示例。

      技巧42 清理容器

      Docker新手經(jīng)常抱怨的一點(diǎn)便是,在短時(shí)間內(nèi),用戶可能在系統(tǒng)上殘留許多不同狀態(tài)的容器,而且沒(méi)有一個(gè)標(biāo)準(zhǔn)工具通過(guò)命令行管理這些容器。

      問(wèn)題

      想要清理系統(tǒng)上的殘留容器。

      解決方案

      設(shè)置一個(gè)別名來(lái)執(zhí)行清理舊容器的命令。這里最簡(jiǎn)單的辦法是刪除所有容器。顯然,這是一個(gè)有風(fēng)險(xiǎn)的方案,只應(yīng)在確定這是預(yù)期行為的時(shí)候使用。下列命令將會(huì)刪除宿主機(jī)上的所有容器。

      $ docker ps -a -q | \  ?--- 獲取所有容器ID的列表,包括正在運(yùn)行的以及已停止的,然后將它們傳給……
       xargs --no-run-if-empty docker rm -f  ?--- ……docker rm -f命令,被傳入的任意容器將會(huì)被刪除,即使它們還處于運(yùn)行狀態(tài)

      簡(jiǎn)單介紹一下xargs命令,它會(huì)獲取輸入的每一行內(nèi)容,并將它們?nèi)孔鳛閰?shù)傳遞給后續(xù)命令。為了防止報(bào)錯(cuò),我們這里傳入了一個(gè)額外參數(shù)--no-run-if-empty,這可以避免在前面的命令完全沒(méi)有輸出的情況下執(zhí)行該命令。

      如果有正在運(yùn)行的容器想要保留,但是又想刪除所有已經(jīng)退出的容器,那么不妨過(guò)濾一下docker ps命令返回的條目:

      docker ps -a -q --filter status=exited | \  ?--- --filter標(biāo)志會(huì)告知docker ps命令想要返回的容器。在這種情況下限制成狀態(tài)為已經(jīng)退出的那些容器。也可以選擇處于正在運(yùn)行中或者正在重啟狀態(tài)的容器 xargs --no-run-if-empty docker rm  ?--- 這次不用再?gòu)?qiáng)行刪除容器,因?yàn)楦鶕?jù)給定的過(guò)濾參數(shù),它們本身就不應(yīng)該處于運(yùn)行狀態(tài)

      事實(shí)上,刪掉所有已停止的容器是一個(gè)很常見(jiàn)的用例,為此Docker專門(mén)添加了一條命令:docker container prune。然而,這條命令僅限于該用例,要進(jìn)行任何更復(fù)雜的操作,仍然需要回過(guò)頭來(lái)參考本技巧里介紹的命令。

      作為更高級(jí)用例的示范,下列命令將會(huì)列出所有返回非零錯(cuò)誤碼的容器。如果系統(tǒng)上有許多容器,用戶想要自動(dòng)檢查并刪除那些異常退出的任意容器,就可能需要這樣做:

      comm -3 \  ?--- 執(zhí)行comm命令來(lái)比較兩個(gè)文件內(nèi)容的差異。加上-3 參數(shù)將不會(huì)顯示同時(shí)出現(xiàn)在兩個(gè)文件里的行內(nèi)容(這些容器的退出碼都是0),然后輸出其他不同的部分
       <(docker ps -a -q --filter=status=exited | sort) \  ?--- 找出退出的容器 ID,給它們排序,然后以文件形式傳給comm
      <(docker ps -a -q --filter=exited=0 | sort) | \  ?--- 找出退出碼為0的容器,給它們排序,然后以文件形式傳給comm
       xargs --no-run-if-empty docker inspect > error_containers  ?--- 對(duì)非0退出碼(comm命令管道的輸出)的容器執(zhí)行docker inspect,并將輸出結(jié)果保存到error_containers文件中

      提示

      也許你還沒(méi)看到過(guò)這種用法,bash里的<(command)語(yǔ)法被稱為進(jìn)程替換。它允許把一個(gè)命令的輸出結(jié)果作為文件,傳給其他命令,這在無(wú)法使用管道輸出的時(shí)候非常有用。

      上述示例相對(duì)比較復(fù)雜,但是它展示了將不同的工具命令組合在一起的威力。它會(huì)輸出所有已停止的容器的ID,然后挑出那些非0退出碼的容器(即那些以異常方式退出的容器)。如果讀者還在努力理解這個(gè)用法,不妨先單獨(dú)執(zhí)行每條命令,然后理解它們的含義,這樣有助于了解整個(gè)過(guò)程。

      像這樣的命令可以用來(lái)在生產(chǎn)環(huán)境里采集容器信息。用戶可能想要對(duì)它做些調(diào)整,改為執(zhí)行一個(gè)cron定時(shí)任務(wù)來(lái)清除正常退出的容器。


      將單行代碼包裝成命令

      可以給命令設(shè)置別名,以便在登錄到宿主機(jī)后更容易操作。為了達(dá)成這一點(diǎn),需要在~/.bashrc文件里添加如下代碼:

      alias dockernuke='docker ps -a -q | xargs --no-run-if-empty docker rm -f'

      然后,在下一次登錄時(shí),從命令行執(zhí)行dockernuke,將刪除在系統(tǒng)上找到的任何Docker容器。

      我們發(fā)現(xiàn)這樣做節(jié)省的時(shí)間是相當(dāng)可觀的。但是要小心!這種方式同樣也非常容易誤刪生產(chǎn)環(huán)境的容器,我們可以證明。即使足夠小心,不去刪除正在運(yùn)行的容器,仍然可能會(huì)誤刪那些沒(méi)有運(yùn)行但仍然有用的純數(shù)據(jù)容器。


      討論

      本書(shū)介紹到的許多技巧的最終目的都是創(chuàng)建容器,尤其是在技巧76介紹到的Docker Compose以及有關(guān)編排的章節(jié)里——畢竟,編排都是關(guān)于如何管理多個(gè)容器的。用戶也許會(huì)發(fā)現(xiàn)這里討論到的命令用于清理機(jī)器(本地或遠(yuǎn)程)很有價(jià)值,在完成每個(gè)技巧后可以獲得一個(gè)全新的環(huán)境。

      技巧43 清理卷

      盡管卷是Docker提供的一個(gè)強(qiáng)大功能,與之伴隨而來(lái)的也有一些顯著的運(yùn)維缺陷。由于卷可以在不同的容器之間共享,因此在掛載它們的容器被刪除時(shí)無(wú)法清空這些卷。試想一下圖6-1中描述的場(chǎng)景。

      圖6-1 當(dāng)容器被刪除時(shí)/var/db下會(huì)發(fā)生什么

      “簡(jiǎn)單!”你可能會(huì)這樣想,“在最后一個(gè)引用的容器被刪除時(shí)把卷刪掉不就行了!”事實(shí)上,Docker可以采取這種手段,這也是垃圾回收式編程語(yǔ)言從內(nèi)存中刪除對(duì)象時(shí)所采用的方法:當(dāng)沒(méi)有其他對(duì)象引用它時(shí),它便可以被刪除。

      但是Docker認(rèn)為這可能會(huì)讓人們不小心丟失重要的數(shù)據(jù),而且最好把是否在刪除容器的時(shí)候刪除卷的決定權(quán)交給用戶。這樣做帶來(lái)的一個(gè)不幸的副作用便是,默認(rèn)情況下,卷會(huì)一直保留在Docker守護(hù)進(jìn)程所在的宿主機(jī)磁盤(pán)上,直到它們被手動(dòng)刪除。

      如果這些卷填滿了數(shù)據(jù),磁盤(pán)可能會(huì)被裝滿,因此最好關(guān)注一下管理這些孤立卷的方法。

      問(wèn)題

      掛載到宿主機(jī)上的孤立Docker卷用掉了大量的磁盤(pán)空間。

      解決方案

      在調(diào)用docker rm命令時(shí)加上-v標(biāo)志,或者如果忘記了,使用docker volumes子命令來(lái)銷毀它們。

      在圖6-1描述的場(chǎng)景中,如果在調(diào)用docker rm時(shí)總是加上-v標(biāo)志可以確保/var/db最后被刪除掉。-v標(biāo)志會(huì)將那些沒(méi)有被其他容器掛載的關(guān)聯(lián)卷一一刪除。幸好,Docker很聰明,它知道是否有其他容器掛載該卷,因此不會(huì)出現(xiàn)什么意外尷尬的情形。

      最簡(jiǎn)單的方式莫過(guò)于養(yǎng)成在刪除容器時(shí)加上-v標(biāo)志這樣的好習(xí)慣。這樣可以保留對(duì)容器是否刪除卷的控制權(quán)。而這種做法的問(wèn)題在于用戶可能不想每次都刪除卷。如果用戶正在寫(xiě)入大量數(shù)據(jù)到這些卷,極有可能不希望丟失這些數(shù)據(jù)。此外,如果養(yǎng)成了這樣的習(xí)慣,很有可能就會(huì)變成自動(dòng)的了,而用戶將會(huì)在刪除某些重要東西之后才反應(yīng)過(guò)來(lái),但為時(shí)已晚。

      在這類情況下,用戶可以使用一個(gè)經(jīng)過(guò)許多人抱怨并且涌現(xiàn)出眾多第三方解決方案之后添加到Docker的命令:docker volume prune。這條命令將會(huì)刪除所有未使用的卷:

      $ docker volume ls  ?--- 執(zhí)行命令列出Docker所知的卷
       DRIVER             VOLUME NAME
       local              80a40d34a2322f505d67472f8301c16dc75f4209b231bb08faa8ae48f
      ? 36c033f  ?--- 
       local              b40a19d89fe89f60d30b3324a6ea423796828a1ec5b613693a740b33
      ? 77fd6a7b
       local              bceef6294fb5b62c9453fcbba4b7100fc4a0c918d11d580f362b09eb
      ? 58503014  ?--- 宿主機(jī)上存在的卷,無(wú)論是否在使用
      $ docker volume prune  ?--- 執(zhí)行命令刪除未使用的卷
       WARNING! This will remove all volumes not used by at least one container.
      Are you sure you want to continue? [y/N] y  ?--- 確認(rèn)刪除卷
       Deleted Volumes:
       80a40d34a2322f505d67472f8301c16dc75f4209b231bb08faa8ae48f36c033f  ?--- 
       b40a19d89fe89f60d30b3324a6ea423796828a1ec5b613693a740b3377fd6a7b  ?--- 已經(jīng)被刪除的卷
      
      Total reclaimed space: 230.7MB

      如果想要跳過(guò)提示確認(rèn)步驟,也許可以用一個(gè)自動(dòng)化腳本,在執(zhí)行docker volume prune時(shí)帶上-f選項(xiàng)來(lái)跳過(guò)這一步。

      提示

      如果想要恢復(fù)一個(gè)未被刪除但是已經(jīng)不再被任何容器引用的卷里的數(shù)據(jù),可以使用docker volume inspect來(lái)找出卷所在的目錄(像是/var/lib/docker/volumes下)。隨后可以用root用戶的身份瀏覽。

      討論

      刪除卷可能不是需要經(jīng)常執(zhí)行的操作,因?yàn)槿萜骼锏拇笪募ǔJ菑乃拗鳈C(jī)掛載的,并不會(huì)存放在Docker數(shù)據(jù)目錄里。但是值得大約每周清理一次,避免它們堆積,尤其是當(dāng)你使用技巧37里的數(shù)據(jù)容器時(shí)。

      技巧44 無(wú)須停止容器,從容器里解綁

      使用Docker時(shí),你常常會(huì)發(fā)現(xiàn)自己打開(kāi)了一個(gè)交互式shell,但是一旦退出shell,容器便會(huì)被終止,因?yàn)樗侨萜鞯闹鬟M(jìn)程。幸運(yùn)的是,有辦法可以做到和一個(gè)容器解綁(而且,如果愿意,還可以用dockerattach命令再連到容器里)

      問(wèn)題

      想要退出一個(gè)容器的交互會(huì)話,同時(shí)不停掉它。

      解決方案

      使用Docker內(nèi)置的按鍵組合從容器里退出。Docker很有建設(shè)性地實(shí)現(xiàn)了一個(gè)不太可能被其他應(yīng)用使用也不太可能被意外按到的按鍵組合。

      假設(shè)我們執(zhí)行docker run -t -i -p 9005:80 ubuntu /bin/bash命令啟動(dòng)了一個(gè)容器,然后用apt-get安裝了一個(gè)Nginx Web服務(wù)器。我們想通過(guò)一個(gè)快捷的到localhost:9005的curl命令來(lái)測(cè)試該Web服務(wù)器能否在宿主機(jī)上被訪問(wèn)到。

      先按組合鍵Ctrl+P然后再按組合鍵Ctrl+Q。注意,不是3個(gè)鍵一起按!

      注意

      如果運(yùn)行容器時(shí)帶上了–rm標(biāo)志,那么在解綁后一旦容器被終止仍然會(huì)被刪除,無(wú)論是命令執(zhí)行完畢還是手動(dòng)把它停掉。

      討論

      如技巧2所述,如果我們之前已經(jīng)啟動(dòng)了一個(gè)容器,卻忘了在后臺(tái)啟動(dòng),本技巧會(huì)很有用。如果想檢查容器的運(yùn)行情況或提供一些輸入,它還允許用戶和容器自由地綁定和解綁。

      技巧45 使用Portainer管理Docker守護(hù)進(jìn)程

      在演示Docker時(shí),很難表現(xiàn)出容器和鏡像之間的差異——從終端里的輸出看不出來(lái)。此外,如果想要從多個(gè)容器里殺掉并刪除一個(gè)特定的容器,Docker命令行工具對(duì)于這種場(chǎng)景也不太友好。創(chuàng)建一個(gè)即點(diǎn)即用的工具來(lái)管理宿主機(jī)上的鏡像和容器可以解決這個(gè)問(wèn)題。

      問(wèn)題

      想要不通過(guò)命令行管理宿主機(jī)上的容器和鏡像。

      解決方案

      試試Portainer,這是一款由Docker核心貢獻(xiàn)者之一開(kāi)發(fā)的工具。Portainer的前身是DockerUI。由于沒(méi)有先決條件,可以直接跳到執(zhí)行步驟:

      $ docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer -H unix:///var/run/docker.sock

      執(zhí)行上述命令將會(huì)在后臺(tái)啟動(dòng)一個(gè)portainer容器。如果現(xiàn)在訪問(wèn) http://localhost:9000 ,可以在看板上看到機(jī)器上運(yùn)行的Docker的簡(jiǎn)要信息。

      容器管理功能可能是這里面最有用的部分之一 ——轉(zhuǎn)到“Containers”頁(yè)面,我們會(huì)看到正在運(yùn)行的容器列表(包括portainer容器本身),還提供選項(xiàng)可以展示所有容器。在這里,你可以對(duì)容器執(zhí)行批量操作(如殺掉它們),或者點(diǎn)擊一個(gè)容器的名字,深入了解該容器的詳細(xì)信息,而且可以執(zhí)行該容器相關(guān)的一些單個(gè)操作。例如,可以看到刪除一個(gè)正在運(yùn)行的容器的選項(xiàng)。

      “Images”頁(yè)面看起來(lái)和“Containers”頁(yè)面非常相似,并且還允許選擇多個(gè)鏡像然后執(zhí)行一些批量操作。點(diǎn)擊鏡像的ID會(huì)提供一些有趣的選項(xiàng),比如基于該鏡像創(chuàng)建一個(gè)容器以及給鏡像打標(biāo)簽等。

      記住,Portainer可能會(huì)落后于Docker官方提供的功能——如果想要使用最新最強(qiáng)大的功能,那么可能不得不選擇命令行。

      討論

      Portainer是Docker眾多的圖形工具里的其中一款,也是這里面最受歡迎的,擁有眾多功能并且持續(xù)迭代的工具之一。舉個(gè)例子,你可以使用它來(lái)管理遠(yuǎn)程機(jī)器,也許會(huì)是技巧32里在這些機(jī)器上啟動(dòng)容器之后用到。

      技巧46 生成Docker鏡像的依賴圖

      Docker的文件分層系統(tǒng)是一個(gè)非常強(qiáng)大的理念,它可以節(jié)省空間,而且可以讓軟件的構(gòu)建變得更快。但是一旦啟用了大量的鏡像,便很難搞清楚鏡像之間是如何關(guān)聯(lián)的。docker images -a命令會(huì)返回系統(tǒng)上所有鏡像層的列表,但是對(duì)于理解它們之間的關(guān)聯(lián)關(guān)系而言,這不是一個(gè)友好的方式——使用Graphviz可以更方便地通過(guò)創(chuàng)建一個(gè)鏡像樹(shù)并做成鏡像的形式來(lái)可視化鏡像之間的關(guān)系。

      這也展示了Docker在把復(fù)雜的任務(wù)變得簡(jiǎn)單方面的強(qiáng)大實(shí)力。在宿主機(jī)上安裝所有的組件來(lái)生產(chǎn)鏡像時(shí),老的方式可能會(huì)包含一長(zhǎng)串容易出錯(cuò)的步驟,但是對(duì)Docker來(lái)說(shuō),這就變成了一條相對(duì)失敗較少的可移植命令。

      問(wèn)題

      想要以樹(shù)的形式將存放在宿主機(jī)上的鏡像可視化。

      解決方案

      使用一個(gè)我們之前創(chuàng)建的鏡像(基于CenturyLink Labs的一個(gè)鏡像)配合這項(xiàng)功能輸出一個(gè)PNG圖片或者獲取一個(gè)Web視圖。此鏡像包含了一些使用Graphviz生成PNG圖片文件的腳本。

      本技巧使用的Docker鏡像放在dockerinpractice/docker-image-graph。時(shí)間長(zhǎng)了該鏡像可能會(huì)過(guò)期然后停止工作,可以通過(guò)執(zhí)行代碼清單6-1中的命令確保生成最新的鏡像。

      代碼清單6-1 構(gòu)建一個(gè)最新的docker-image-graph鏡像(可選)

      $ git clone https://github.com/docker-in-practice/docker-image-graph
      $ cd docker-image-graph
      $ docker build -t dockerinpractice/docker-image-graph

      在run命令里需要做的就是掛載Docker服務(wù)器套接字,然后一切便準(zhǔn)備就緒,如代碼清單6-2所示。

      代碼清單6-2 生成一個(gè)鏡像的層樹(shù)

      $ docker run --rm \  ?--- 在生成鏡像之后刪除容器 -v /var/run/docker.sock:/var/run/docker.sock \  ?--- 掛載 Docker 服務(wù)器的Unix 域套接字,以便可以在容器里訪問(wèn)Docker服務(wù)器。如果已經(jīng)更改了Docker守護(hù)進(jìn)程的默認(rèn)配置,這將不會(huì)奏效 dockerinpractice/docker-image-graph > docker_images.png  ?--- 指定一個(gè)鏡像然后生成一個(gè)PNG圖片作為制品

      圖6-2以PNG圖片形式展示了一臺(tái)機(jī)器的鏡像樹(shù)。從這張圖片可以看出,node和golang:1.3鏡像擁有一個(gè)共同的根節(jié)點(diǎn),然后golang:runtime只和golang:1.3共享全局的根節(jié)點(diǎn)。類似地,mesosphere鏡像和ubuntu-upstart鏡像也是基于同一個(gè)根節(jié)點(diǎn)構(gòu)建的。

      讀者可能會(huì)好奇這棵樹(shù)上的全局根節(jié)點(diǎn)是什么。它是一個(gè)叫作scratch的偽鏡像,實(shí)際上大小為0字節(jié)。

      討論

      在構(gòu)建更多的Docker鏡像時(shí),也許作為第9章里持續(xù)交付的一部分,跟蹤一個(gè)鏡像的歷史以及它所基于的內(nèi)容可能會(huì)很麻煩。如果試圖通過(guò)共享更多層精簡(jiǎn)鏡像大小的方式來(lái)加快交付速度,這一點(diǎn)尤為重要。定期拉取所有鏡像并生成圖譜是一個(gè)追蹤的好辦法。

      圖6-2 一棵鏡像樹(shù)

      技巧47 直接行動(dòng):在容器上執(zhí)行命令

      在Docker早期,許多用戶會(huì)在他們的鏡像里添加SSH服務(wù),這樣一來(lái)便可以從外部通過(guò)shell來(lái)訪問(wèn)它們。Docker不主張這樣做,它認(rèn)為這相當(dāng)于把容器當(dāng)成一臺(tái)虛擬機(jī)(而我們知道,容器并不是虛擬機(jī)),并且這給本不應(yīng)該需要它的系統(tǒng)帶來(lái)了額外的進(jìn)程開(kāi)銷。很多人對(duì)此持反對(duì)意見(jiàn)的原因在于,一旦容器啟動(dòng)了,沒(méi)有一個(gè)簡(jiǎn)便的辦法進(jìn)到容器里面。結(jié)果便是,Docker引入了exec命令,它是一個(gè)更優(yōu)雅地解決干涉和檢索啟動(dòng)后的容器內(nèi)部問(wèn)題的解決方案。我們這里也將討論此命令。

      問(wèn)題

      想要在一個(gè)正在運(yùn)行的容器里執(zhí)行一些命令。

      解決方案

      使用dockerexec命令。

      下列命令會(huì)在后臺(tái)(帶上-d標(biāo)志)啟動(dòng)一個(gè)容器,然后告訴它一直休眠(不做任何事情)。我們把這條命令命名為sleeper。

      docker run -d --name sleeper debian sleep infinity

      現(xiàn)在已經(jīng)啟動(dòng)了一個(gè)容器,可以用Docker的exec命令對(duì)它執(zhí)行一些操作。該命令可以看成有3種基本模式,如表6-1所示。

      表6-1 Docker exec 模式

      我們先介紹一下基本模式。下列命令在sleeper容器內(nèi)部執(zhí)行了一個(gè)echo命令。

      $ docker exec sleeper echo 'hello host from container' hello host from container

      注意,該命令的結(jié)構(gòu)和dockerrun命令非常相似,但是把鏡像ID替換成一個(gè)正在運(yùn)行的容器的ID。echo命令指代的是容器里面的echo二進(jìn)制文件,而非容器外部的。

      守護(hù)進(jìn)程模式會(huì)在后臺(tái)執(zhí)行命令,用戶無(wú)法在終端看到輸出結(jié)果。這可能適用于一些常規(guī)的清理任務(wù),在這些任務(wù)中,你希望敲完即走,如清理日志文件。

      $ docker exec -d sleeper \  ?--- 執(zhí)行命令時(shí)加上-d標(biāo)志即可在后臺(tái)以守護(hù)進(jìn)程的形式運(yùn)行,類似dcoker run
       find / -ctime 7 -name '*log' -exec rm {} \;  ?--- 刪除所有在最近7天沒(méi)有做過(guò)更改并且以log結(jié)尾的文件
       $  ?--- 無(wú)論需要多長(zhǎng)時(shí)間完成這一操作,該命令都會(huì)立即返回

      最后,我們來(lái)試試交互模式。這種模式允許用戶在容器里執(zhí)行任何想要執(zhí)行的命令。要啟用這一功能,通常需要指定用來(lái)在運(yùn)行時(shí)交互的shell,在如下代碼里便是bash:

      $ docker exec -i -t sleeper /bin/bash root@d46dc042480f:/#

      -i和-t參數(shù)同我們所熟悉的dockerrun做著相同的事情——它們會(huì)讓命令成為可交互的,然后設(shè)置一個(gè)TTY設(shè)備,以便shell可以正常工作。在執(zhí)行該命令后,用戶便拿到了一個(gè)在容器里運(yùn)行的命令提示符。

      討論

      當(dāng)出現(xiàn)問(wèn)題或者想要弄清楚容器在做什么時(shí),跳到容器里是必不可少的調(diào)試步驟。往往不太可能使用技巧44里提到的綁定和解綁方法,因?yàn)槿萜鲀?nèi)的進(jìn)程通常運(yùn)行在前臺(tái),無(wú)法訪問(wèn)shell提示符。由于exec允許用戶指定想要運(yùn)行的二進(jìn)制文件,這便不再是問(wèn)題……只要容器文件系統(tǒng)上實(shí)際存在那份想要運(yùn)行的二進(jìn)制文件即可。

      特別的是,如果你使用技巧58創(chuàng)建一個(gè)帶有單個(gè)二進(jìn)制文件的容器,那么將無(wú)法啟動(dòng)shell。在這種情況下,可能想堅(jiān)持采用技巧57作為允許exec執(zhí)行的低開(kāi)銷辦法。

      技巧48 你在容器里嗎

      在創(chuàng)建容器時(shí),通常會(huì)把運(yùn)行邏輯放到一個(gè)shell腳本里,很少會(huì)嘗試直接在Dockerfile里編寫(xiě)腳本。又或者,你可能在容器運(yùn)行時(shí)用到了各種腳本。無(wú)論哪種方式,這些執(zhí)行的任務(wù)通常都需要經(jīng)過(guò)仔細(xì)定制,以便能夠運(yùn)行在容器里,并且運(yùn)行在一臺(tái)“常規(guī)”機(jī)器上可能會(huì)搞破壞。在這種情況下,設(shè)置一些安全防護(hù),防止在容器外部意外執(zhí)行是很有用的。

      問(wèn)題

      用戶代碼需要知道是否是在一個(gè)Docker容器里操作。

      解決方案

      檢查/.dockerenv文件是否存在。如果存在,那么很可能在一個(gè)Docker容器里。

      注意,這并不是100%確定的——如果任何人或任何事物把/.dockerenv文件刪掉,這個(gè)檢查就會(huì)給出誤導(dǎo)性的結(jié)果。這些情況不太可能發(fā)生,但是最壞的情況便是用戶得到錯(cuò)誤的診斷結(jié)果而沒(méi)有不良影響。用戶會(huì)認(rèn)為自己不在Docker容器里,并且在最壞的情況下不會(huì)運(yùn)行潛在的破壞性代碼。

      一個(gè)更現(xiàn)實(shí)的情況是,在較新的Docker版本里(或者使用的是實(shí)現(xiàn)這一行為之前的版本)已經(jīng)更改或刪除了這種未記錄的Docker行為。

      這些代碼可能是啟動(dòng)bash腳本的一部分,如代碼清單6-3所示,其后是剩余的啟動(dòng)腳本代碼。

      代碼清單6-3 如果在容器外運(yùn)行,如下shell腳本會(huì)運(yùn)行失敗

      #!/bin/bash
      if ! [ -f /.dockerenv ]
      then
          echo 'Not in a Docker container, exiting.'
          exit 1
      fi

      當(dāng)然,如有需要,可以使用相反的邏輯來(lái)確認(rèn)自己是不是運(yùn)行在容器外面,如代碼清單6-4所示。

      代碼清單6-4 如果在容器里運(yùn)行,如下shell腳本會(huì)運(yùn)行失敗

      #!/bin/bash if [ -f /.dockerenv ] then echo 'In a Docker container, exiting.' exit 1 fi

      上述示例使用bash命令來(lái)確認(rèn)文件是否存在,但是絕大多數(shù)編程語(yǔ)言有自己的辦法來(lái)確認(rèn)容器(或宿主機(jī))文件系統(tǒng)里是否存在某些文件。

      討論

      用戶可能想知道這種情況多久出現(xiàn)一次。作為一個(gè)時(shí)常討論的話題,它經(jīng)常出現(xiàn)在Docker論壇里,關(guān)于這是否是一個(gè)有效的用例,又或者是應(yīng)用程序設(shè)計(jì)方面存在其他問(wèn)題,這塊仍然存在爭(zhēng)議。

      撇開(kāi)這些爭(zhēng)議不提,用戶很容易陷入需要根據(jù)自己是否在Docker容器里來(lái)切換代碼路徑的情況。我們經(jīng)歷過(guò)的一個(gè)這樣的例子便是使用Makefile來(lái)構(gòu)建一個(gè)容器。

      6.2 小結(jié)

      • 用戶可以配置自己的機(jī)器,讓自己可以不帶sudo運(yùn)行Docker。
      • 使用內(nèi)置的Docker命令來(lái)清理未使用的容器和卷。
      • 以一種全新的方式使用外部工具來(lái)公開(kāi)容器的相關(guān)信息。
      • docker exec命令是進(jìn)入一個(gè)正在運(yùn)行的容器內(nèi)部的正確途徑——抵制安裝SSH。

      本文摘自《Docker實(shí)踐(第2版)》

      • 深入淺出Docker源碼分析,暢銷容器與容器云實(shí)踐教程升級(jí)版
      • 基于Docker1.13,114個(gè)實(shí)戰(zhàn)技巧
      • 解決Docker的應(yīng)用問(wèn)題,并提供源代碼

      1.暢銷Docker容器實(shí)踐教程升級(jí)版,編寫(xiě)時(shí)參考的Docker版本是Docker 1.13;
      2.114個(gè)實(shí)戰(zhàn)技巧為讀者提供解決方案以及一些細(xì)節(jié)和技巧方面的實(shí)踐經(jīng)驗(yàn);
      3.提供配套源代碼下載。
      本書(shū)詳細(xì)介紹了一些堅(jiān)實(shí)可靠的、經(jīng)過(guò)檢驗(yàn)的Docker技術(shù),如替換虛擬機(jī)(VM)、啟用微服務(wù)架構(gòu)、高效網(wǎng)絡(luò)建模、離線生產(chǎn)和建立容器驅(qū)動(dòng)的持續(xù)交付過(guò)程等,讓開(kāi)發(fā)人員能夠按照手冊(cè)風(fēng)格的“問(wèn)題-解決方案-討論”模式探索真實(shí)案例,并學(xué)習(xí)如何將這些經(jīng)驗(yàn)應(yīng)用到自己的開(kāi)發(fā)項(xiàng)目中。

      本書(shū)由淺入深地講解了Docker的相關(guān)內(nèi)容,涵蓋從開(kāi)發(fā)環(huán)境到DevOps流水線,再一路到生產(chǎn)環(huán)境的整個(gè)落地過(guò)程以及相關(guān)的實(shí)用技巧。書(shū)中介紹Docker的核心概念和架構(gòu),以及將Docker和開(kāi)發(fā)環(huán)境有機(jī)、高效地結(jié)合起來(lái)的方法,包括背Docker用作輕量級(jí)虛擬機(jī)、構(gòu)建容器、宿主機(jī)編排、配置管理、精簡(jiǎn)鏡像等。不僅如此,本書(shū)還通過(guò)“問(wèn)題-解決方案-討論”的形式,將Docker如何融入DevOps流水線、如何在生產(chǎn)環(huán)境落地等一系列難題拆解成114個(gè)相關(guān)的實(shí)用技巧,為讀者提供解決方案以及一些細(xì)節(jié)和技巧方面的實(shí)踐經(jīng)驗(yàn)。閱讀本書(shū),讀者學(xué)到的不只是Docker,還包括持續(xù)集成、持續(xù)交付、構(gòu)建和鏡像管理、容器編排等相關(guān)領(lǐng)域的一線生產(chǎn)經(jīng)驗(yàn)。本書(shū)編寫(xiě)時(shí)一些案例參考的Docker版本是Docker 1.13。

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多