進入docker的世界
最近學習Machine Learning發現好多人都用docker,之前一直聽說但是感覺和自己無關。但是現在發現原來docker是個這麼方便的東西,可以跨平臺(不分什麼版本的linux,甚至mac和windows也行)執行。所以這裡開一篇來記錄學習感受。
不提那些難懂的術語,大白話就是:
一個Docker就是一個Linux的Live CD系統,跟USB系統一樣,有完整的系統檔案目錄和程式。
我們可以在這個與外界隔離的便攜系統裡隨便讀寫操作,只是每次進入它時候,都會恢復最開始的樣子,像什麼事都沒發生一樣。
我們可以像定製Live CD或WinPE一樣,定製這個小系統裡面預設裝什麼軟體。一旦定製好了,就是不可更改的,非常穩定。
理解Docker的邏輯
一開始發現很亂很難理解,覺得所有人都把它說的太複雜了。直到後來發現,其實它的執行邏輯很簡單。
實際上,可以把Docker看成是給電腦安裝Linux系統時的 Live CD
,或者是給Windows用USB安裝系統時的 WinPE
。這樣會方便理解一點。
回想下自己在給PC或是虛擬機器上安裝Linux系統時,都會有個Live CD選項。也是就是你可以什麼都不安裝,直接進入系統,所有的工具都能用,所有的軟體都能安裝,所有的配置也可以改。只不過你重啟過後,一切修改的地方都恢復原樣了。
每篇攻略都會提到這三個基本概念:
-
映象 Image
相當於一個系統光碟的ISO映象檔案,是隻讀的。你可以直接進入image中各種操作沒有障礙,感覺就像進入_Live CD_系統了。只是所有操作都會在退出時消失,下次進image時候還是初始的樣子。
-
容器 Container
就像給"ISO檔案"加了一層可讀寫的外衣,所有的變動都會儲存在 Container
裡,而image還是image,不會變。就像你可以隨便換衣服,但是身體不會變。
-
倉庫 Repo
一般指的 Dockerhub
,就是一個像Github的網站,只不過不是收集程式碼,而是收集各種image映象。你可以隨意上傳下載各大廠商或個人製作的映象。
安裝Docker
Docker分CE和EE兩個版本,一個社群公開免費,一個商業付費。
Ubuntu上安裝Docker
參考官方安裝步驟:Get Docker CE for Ubuntu
準備工作:
#安裝SSL相關,讓apt通過HTTPS下載: sudo apt-get install apt-transport-https ca-certificates curl software-properties-common # 新增docker的GPG key curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - #檢查key是否相符(9DC8 5822 9FC7 DD38 854AE2D8 8D81 803C 0EBF CD88) sudo apt-key fingerprint 0EBFCD88 #新增docker的apt下載源 sudo add-apt-repository"deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" #更新源 sudo apt-get update
安裝docker:
$ sudo apt-get install docker-ce
解除安裝Docker:
$ sudo apt-get remove docker docker-engine docker.io
Mac上安裝Docker
直接下載app:
樹莓派上安裝Docker
樹莓派是基於ARM架構的,和PC不同。所以即使樹莓派上能做一些docker映象,也不能在別的PC上執行。反過來別的PC上的docker映象,也不能在樹莓派上執行。
如果需要找樹莓派專用的映象,那就在 Dockerhub
上搜索 ARM
或 Rpi
相關就能找到了。
有一個叫 Hypriot
的倉庫製作了非常多樹莓派專用docker,可以參考下。
樹莓派安裝Docker,最難的在於正確的選擇源和新增GPG-key,才能找到版本適合的docker並下載。這個過程是非常繁瑣且很難有統一方案的。
另外:官方的一鍵安裝版本已經失效了。必須手動操作。
執行Docker
[站外圖片上傳中...(image-e81557-1548159126389)]
從Image映象建立一個Container容器:
# 新建一個Container容器(如果本地有image則直接從它建立,如果沒有則從網上下載) # 進入docke的shell -t,即進入虛擬的一個系統,有自己的/root檔案系統結構 $ docker run -it <repo>:<tag> <CMD> #如: $ docker run -it jekyll/jekyll:latest bash # 為container指定名稱(而不是隻用ID來引用) $ docker run -it --name <NAME> <image-ID>
檢視已有的:
# 檢視已有的images $ docker images # 檢視已建立的containers $ docker container ls -a
執行一個已有的Container:
# 先啟動container $ docker container <ID> start # 執行(掛載)container,掛載後自動進入容器裡的shell $ docker attach <ID> # 或者一句話完成(--attach) $ docker start -a<ID>
刪除已有的:
# 刪除image $ docker rm <Image-ID> # 刪除container $ docker rm <Container-ID>
無需sudo執行docker
為了每次執行 docker
不需要總是輸入 sudo
,我們需要為docker建立一個使用者組,並授予許可權才行:
# 建立docker使用者組 sudo groupadd docker # 把當前使用者加入到docker使用者組 sudo gpasswd -a $USER docker # 更新當前使用者組變動(就不用退出並重新登入了) newgrp docker
掛載Host主機上的資料夾
我們肯定不會滿足於docker只訪問自己的小世界裡的檔案系統(什麼資料都沒有),所以有必要讓它能訪問外界Host主機上的一些資料夾。比如我有一個docker是作為下載機用的,那麼我肯定得讓它把下載好的東西存到我的主機上,要不然就白下載了。
掛載資料夾是在docker執行映象的命令裡就指定的(利用-v引數):
$ docker run -it -v <HOST-PATH>:<DOCKER-PATH> ubuntu64 /bin/bash #或者作為只讀掛載 (:ro) $ docker run -it -v <HOST-PATH>:<DOCKER-PATH>:ro ubuntu64 /bin/bash
注意,掛載的雙方都必須是絕對路徑。
對映Docker裡的埠到Host主機上的埠
如果Docker裡執行的是Web服務比如Nginx,裡面有一個網站,那你必須得把”虛擬機器“裡的埠對映到外部才能正常看到網頁。
對映是在執行docker命令時指定的,比如把 裡面 的80埠對映到 外面 的8888埠,命令如下:
$ docker run --name webserver -d -p 80:8888 nginx
然後你在主機上的瀏覽器訪問 http://localhost:8888
,就可以看到nginx裡的網頁了。
Docker映象儲存更改
直接在映象上改動的內容,會在退出時全部消失。但是我們經常需要把這些變動儲存下來。
Docker儲存這些變動的機制就是——生成另一個只讀映象。(-_-!)
雖然正常看來,這不太好吧。但實際上,這很好!
Docker映象實際上是非常小的,所以生成另一個映象也沒有多費事。而且這種機制保證了每個映象的不可隨便修改的性質,這一點就極大的避免了混亂。
Docker儲存更改有兩種方式:
-
docker commit
:就像git commit
一樣,把每次改動作為一個commit提交,可以追溯歷史 -
Dockerfile
:這是從頭build構建一個映象的配置檔案,把你想改動的地方(如安裝一個程式)寫成一句bash命令,加到Dockerfile
這個檔案裡,它就會按照你的要求執行所有的命令,然後生成一個新的映象。
Commit可以追溯歷史,但是變動了哪些地方是對外界 黑箱 的。
Dockerfile確實明明白白寫清楚有哪些改變。
所以一般情況下,正式構建一個映象,都是用Dockerfile的。
"docker commit" 將變動過的Container儲存為映象
docker commit
命令,可以將容器的儲存層儲存下來成為映象。換句話說,就是在原有映象的基礎上,再疊加上容器的儲存層,並構成新的映象。以後我們執行這個新映象的時候,就會擁有原有容器最後的檔案變化。
慎用 docker commit
:
由於命令的執行,還有很多檔案被改動或添加了。這還僅僅是最簡單的操作,如果是安裝軟體包、編譯構建,那會有大量的無關內容被新增進來,如果不小心清理,將會導致映象極為臃腫。
此外,使用 docker commit 意味著所有對映象的操作都是黑箱操作,生成的映象也被稱為黑箱映象,換句話說,就是除了製作映象的人知道執行過什麼命令、怎麼生成的映象,別人根本無從得知。而且,即使是這個製作映象的人,過一段時間後也無法記清具體在操作的。雖然 docker diff 或許可以告訴得到一些線索,但是遠遠不到可以確保生成一致映象的地步。這種黑箱映象的維護工作是非常痛苦的。
而且,回顧之前提及的映象所使用的分層儲存的概念,除當前層外,之前的每一層都是不會發生改變的,換句話說,任何修改的結果僅僅是在當前層進行標記、新增、修改,而不會改動上一層。如果使用 docker commit 製作映象,以及後期修改的話,每一次修改都會讓映象更加臃腫一次,所刪除的上一層的東西並不會丟失,會一直如影隨形的跟著這個映象,即使根本無法訪問到。這會讓映象更加臃腫。