docker是什麼?docker不是虛拟機,是容器.
虛拟機可以了解為大房子裡面的套間房,套間裡面有客廳/廁所/廚房等,其他套間的使用人不能使用别人的廁所和廚房等,各自不知道各自房間裡面有什麼,就連房主(母機)也不知道裡面有什麼.
容器可以了解為大房子裡面的獨立房間,客廳/廁所/廚房等是公用的,所有房間的使用人都有權使用它們這些共有資源,但是各自不知道各自房間裡面有什麼,不過房主(母機)會知道他們占用了什麼資源.
Docker是基于cgroup和lxc開發的容器工具.
cgroup原本是用來分割限制linux不同使用者使用系統資源的工具.例如:A使用者配置設定為1核cpu2G記憶體,B使用者配置設定2核cpu4G記憶體,限制了使用者使用的資源.
而lxc是基于cgroup提出的早期容器工具,不但可以分割限制資源,還可以隔離容器間的資源和通信,使其互不幹擾,做到類似于虛拟機的存在,不同于虛拟機的是共享了核心和系統本身的檔案系統和結構,相當輕量化,不用像虛拟機那樣需要用就必須先安裝整套系統,相當臃腫.不過因為安裝麻煩,穩定性不佳,是以最終沒有大規模使用.
最後,docker把lxc進一部改進,引入鏡像功能和加強了穩定性,安裝也簡單,操作簡單明了,而且也繼承了其前任輕量化的經驗,社群支援力度也很大,是以最終成為時下最流行的”微服務”的主流應用.不過也不得不說,因為功能還是比較多,很多文章也不夠全面,下面轉入正題.
安裝
不得不說,Docker由于比較新,對于系統核心要求也要比較新,最起碼要用3.1以上的核心,而3.8的核心是最好的,至于3.1以下的核心,事實上是可以使用的,但是穩定性會比較差一些,一般來說,我們選擇centos7.2或ubuntu14.04以上的版本,就問題不大了,還有就是docker的版本,也盡量用最新的比較好,因為社群不斷的在改進中,新版本的穩定性自然也有改善了.
安裝其實很簡單,因為docker類似redis,隻需要指令就可以了,是以一般來說,yum安裝和簡單編譯就可以了.
Ubuntu:
<code>apt-get update</code>
<code>apt-get </code><code>install</code> <code>-y docker.io</code>
<code>ln</code> <code>-sf </code><code>/usr/bin/docker</code><code>.io </code><code>/usr/local/bin/docker</code>
Centos:
<code>yum </code><code>install</code> <code>-y docker-io</code>
關于docker安裝完之後,會有一個docker的指令,以後所有相關操作都是圍繞這個指令,例如下面是我們建立一個容器的簡單語句:
<code>docker run --</code><code>rm</code> <code>-ti centos:latest </code><code>/bin/bash</code>
然後,docker預設的安裝目錄是/var/lib/docker/,任何和容器相關的東西都存放在這個檔案夾裡.不過顯然這個預設目錄不一定符合我們的使用标準,例如大多數人喜歡将資料盤挂載到/data目錄,這樣就不能很好的合理利用了.
這個時候,我們第一時間想到的是改配置檔案,然而docker的配置檔案不是很好改,但是也可以用軟連接配接的方式替代原本的目錄,這個方法我覺得更加通用一些和靈活一些,不過缺點就是必須停掉所有容器來做了,方法如下:
<code>/etc/init</code><code>.d</code><code>/docker</code> <code>stop</code>
<code>#建立新的docker目錄路徑,例如/data是資料盤</code>
<code>mkdir</code> <code>/data/dockerhome</code>
<code>#将docker安裝目錄的檔案全部遷移過來</code>
<code>mv</code> <code>/var/lib/docker/</code><code>* </code><code>/data/dockerhome/</code>
<code>#删了原本的目錄,并建立軟連接配接</code>
<code>rm</code> <code>-rf </code><code>/var/lib/docker</code>
<code>ln</code> <code>-sf </code><code>/data/dockerhome</code> <code>/var/lib/docker</code>
<code>#啟動docker服務</code>
<code>/etc/init</code><code>.d</code><code>/docker</code> <code>start</code>
這個時候你可以看到目錄就是一個軟連接配接,但這完全不影響使用
<code>root@xxxxxx:~</code><code># ll /var/lib/docker</code>
<code>lrwxrwxrwx 1 root root 13 Oct 17 13:25 </code><code>/var/lib/docker</code> <code>-> </code><code>/data/dockerhome/</code>
這個時候,安裝就算完成了,下面來看怎麼使用,
使用
使用docker之前,除了要了解容器是什麼之外,還要先了解下鏡像是什麼.
Docker的鏡像功能正是docker優于lxc的地方,以往lxc的母機是什麼發行版的系統,容器就是什麼發行版的系統,例如系統是centos,那容器就必然是centos.
而docker就靈活很多,系統是什麼發行版本都沒所謂,可以自己編輯自己想要的鏡像,也可以去社群下載下傳别人上傳的鏡像,通常别人上傳的鏡像還有特殊的功能和軟體,例如remine,java等,下載下傳了就直接能用相關功能了,不再需要自己去安裝依賴包和編譯什麼的,相當友善.
需要注意的是,當你安裝完docker之後,并沒有帶有任何鏡像,需要自己去下載下傳,預設的下載下傳位址就是docker的官網,而他們的官網在國内沒有節點,時不時就被國家防火牆隔絕,會出現DNS解析不到,或者找不到鏡像等狗血提示,是以如果有這些提示了,就别太驚訝了.
解決的方法有三個:
第一,就是不斷嘗試,因為牆也不是完全隔絕,偶爾還是有可以的時候,雖然比較費時,不過我個人還是比較推薦,畢竟官網鏡像比較純淨簡約.
第二,添加加速器,現在國内做docker的公司還是挺多,是以他們為了給使用者和自己友善,搞了加速器,其中有:阿裡雲,孔雀雲,DaoCloud等,安裝方法就不列舉了,大家可以自己去網上搜一下相關的,個人建議用DaoCloud,因為方法比較簡單一些.
第三,更換下載下傳位址,雖然預設是從官方網站下載下傳,但是不代表不可以改,而且國内鏡像站也有不少,可以考慮,不過安全性和純淨度就見仁見智了,我個人是不建議的,因為我沒用過,方法也不多說了,下面列舉了幾個.
<code>#阿裡雲</code>
<code>docker pull registry.cn-hangzhou.aliyuncs.com</code><code>/acs-sample/redis-sameersbn</code>
<code>#時速雲</code>
<code>docker pull index.tenxcloud.com</code><code>/tenxcloud/ubuntu</code>
<code>#網易蜂巢</code>
<code>docker pull hub.c.163.com</code><code>/xbingo/jdk8</code><code>:latest</code>
說了那麼多,怎麼下載下傳鏡像呢?其實我們說的第一條指令,就是可以自動下載下傳鏡像并建立一個容器.
隻下載下傳鏡像,不建立容器就是
<code>docker pull centos:latest</code>
上面兩條指令都會先查找目前鏡像庫有沒有相關名字的鏡像,沒有的話就去下載下傳相關鏡像名的鏡像.
查找有什麼鏡像就用下面的指令,他列舉出所有相關名字内容的docker鏡像名,包含官方的,也包含社群其他使用者上傳的,一般來說會注明鏡像包含了什麼軟體和功能,然後自己按需求來下載下傳選擇,這裡也是docker強大的地方
<code>docker search centos</code>
嫌下載下傳太慢嗎?确實也是慢,我們可以從其他機器把鏡像導出來,再導到目的伺服器
先從有鏡像的伺服器導出來鏡像來,參數的說明在最後,導出導入可以有兩種方法,一般用下面這種,導出來就是tar格式,别去解壓了.
<code>#先看看有沒有想要的鏡像</code>
<code>docker images</code>
<code>REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE</code>
<code>centos latest 9baab0af79c4 6 weeks ago 196.8 MB</code>
<code>#導出到tar檔案</code>
<code>docker save centos:latest > centos-dockerimages.</code><code>tar</code>
<code>#拷貝到目的機器</code>
<code>scp</code> <code>-P 22 -o StrictHostKeyChecking=no centos-dockerimages.</code><code>tar</code> <code>[email protected]:</code><code>/opt/</code>
再過去目的伺服器導進去,導進去也是原始tar格式就可以了
<code>cd</code> <code>/opt</code>
<code>#開始導進去</code>
<code>docker load <centos-dockerimages.</code><code>tar</code>
<code>#看看鏡像導成功沒有</code>
手頭上完全沒鏡像嗎?去這裡下載下傳吧,是我從官方下載下傳的centos的最精簡化鏡像,要解壓一次,就是tar檔案了,别解壓兩次了
http://pan.baidu.com/s/1gfPsXFl
好了,我們回歸正題,這個時候,我們來研究執行第一條指令
這條指令意思是通過鏡像centos:latest建立了一個未命名的容器,run就是運作并建立容器,--rm是當容器退出就直接删除容器的意思,-ti的意思是建立了容器之後立刻進入互動模式,/bin/bash則是指定在容器内執行什麼操作,一般來說,視乎鏡像包含了什麼軟體和環境,你的容器就有什麼軟體和環境.
這個自然也就延伸成可以自己建立鏡像,這樣指令運作之後的容器,也有你當時建立鏡像時的軟體和環境,甚至可以自啟動軟體什麼的.
這條指令執行之後,就會直接進入建立容器的系統内部,因為是互動模式,類似下面這樣
<code>[root@76728f45d90b /]</code><code># ps aux </code>
<code>USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND</code>
<code>root 1 0.0 0.0 11752 1872 ? Ss 05:56 0:00 </code><code>/bin/bash</code>
<code>root 15 0.0 0.0 47424 1652 ? R+ 05:59 0:00 </code><code>ps</code> <code>aux</code>
因為沒有指定hostname,是以計算機名是随機的,因為是容器,不是虛拟機,不會出現除了你指定執行的程式(這裡是/bin/bash)外的任何程式.
好了,既然進入了系統,其他怎麼裝軟體和怎麼裝依賴包什麼的,我就不打算說太多,就當做是一般虛拟機來用就行了,是ubuntu的就用apt,是centos的就用yum,自己定義好安裝源就好了.我下面重點說幾個基本上是必用的參數和事例.
重點講解
先來看看常用指令和參數解析:
docker images: 檢視本地已經存在的鏡像,-a 列出所有(預設不包括中間鏡像);
docker rmi IMAGE: 删除指定的鏡像,-f 強制删除;
docker ps: 檢視運作中的 Docker 容器,-a 列出所有(預設不包括未運作的容器);
docker rm CONTAINER: 删除指定的容器,-f 強制删除;
docker attach containerID: 進入指定ID的容器内,不過要慎用,有隐患,建議用docker exec -it containerID/containerNAME bash來替代
docker inspect containerID: 檢視指定ID的容器配置
docker commit containerID 鏡像名: 将指定ID的容器制作成鏡像,友善以後複用,可以重新送出來更新鏡像
-d : 背景運作容器,并傳回容器ID;
-i : 以互動模式運作容器,通常與 -t 同時使用;
-t : 為容器重新配置設定一個僞輸入終端,通常與 -i 同時使用;
-c: 配置設定cpu資源,并不是按核數區分,可以配置設定1-1024任何一個數字,預設是1024,隻是一個對比值,比如A和B兩個容器,A配置的是1024,B配置的是512,那麼A最大可以使用的CPU資源是B的兩倍,如果A容器一直閑着,那B容器還是可以使用空閑資源的。
-m: 配置設定記憶體,支援k/m/g/t/p機關,例如配置設定1G記憶體:-m 1g
--memory-swap: 配置設定多少(非負數值)swap資源,-1即完全不配置設定
-p: 映射母機端口到容器端口,例如:将母機的8001端口映射給容器的80端口:-p 8001:80,将母機内網44444端口映射到容器的22端口:192.168.1.10:44444:22,甚至可以把tcp協定換成udp(我是不太建議):192.168.0.225:300:3000/udp
-v: 把母機的檔案夾挂載到容器内的檔案夾,例如将母機的/data/soft挂載到容器内的/soft檔案夾:-v /data/soft:/soft
--name="nginx-lb" : 為容器指定一個名稱(和計算機名不是一回事);
--dns 8.8.8.8 : 指定容器使用的DNS伺服器,預設和宿主一緻;
--dns-search example.com : 指定容器DNS搜尋域名,預設和宿主一緻;
-h "mars": 指定容器的hostname(和容器名不是一回事);
-e username="ritchie" : 設定環境變量;
--env-file=[]: 從指定檔案讀入環境變量;
--net="bridge" : 指定容器的網絡連接配接類型,支援 bridge /host / none
--restart=on-failure:3 : 容器意外停止後的操作方式,這裡是嘗試重新開機3次的意思
例如我們現在搭建了一個可以運作web的容器:
<code>root@xxxxx:~</code><code># docker ps -a</code>
<code>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAME</code>
<code>6b21dcdefffe centos:latest </code><code>"/bin/init.sh"</code><code>43 hours ago Up 43 hours 0.0.0.0:22222->22</code><code>/tcp</code> <code>testweb1</code>
然後我們把他建立成鏡像,準備複用,如果已經存在相同的鏡像名稱,則代表更新這個鏡像,是以執行這個指令之前,要先确定自己想要的是不是這樣的結果.
<code>docker commit 6b21dcdefffe centos</code><code>/test</code><code>:webdemo1</code>
最後我們建立一個自己想要的容器,要開通端口,要挂載web代碼資料,那麼指令就如下:
<code>docker run -ti -e </code><code>"TZ=Asia/Shanghai"</code> <code>--name testweb1 --restart=on-failure:3 -c 250 -m 1g --memory-swap=-1 -p 8001:80 -p 22222:22 -</code><code>v</code> <code>/data/webdata</code><code>:</code><code>/data/htdocs/www</code> <code>centos</code><code>/test</code><code>:webdemo1 </code><code>/bin/init</code><code>.sh</code>
意思就是建立一個容器,用鏡像centos/test:webdemo1來做模闆,設定時區是Asia/Shanghai,名字叫testweb1,配置設定了250份cpu和1G記憶體,把母機8001端口映射到容器的80端口,把22222端口映射給22端口,把目錄/data/webdata挂載到/data/htdocs/www,在容器内運作初始化腳本/bin/init.sh(需要自己編寫),這樣你想要的容器就搭建完成了,你用web通路母機IP加8001端口就能通路了,想ssh登入就用22222端口.
大家看了上面的參數說明,其實就大概應該明白指令是什麼意思,隻是最後的/bin/init.sh是不了解為什麼要這樣寫,後面來看一些注意事項,把一個容器真正當成伺服器來使用.
經驗之談
以下純屬經驗之談,是對一些容易被忽略而又比較有意思的點的總結,如果有不對,歡迎指正.
首先說說/bin/init.sh是什麼東西,因為這個是我自己定義的東西,不說清楚就都不知道了.
我知道很多相關文章教啟動docker都是/bin/bash,他的意思是建立一個bash會話,用處是不讓容器自己退出,因為容器預設是啟動并執行完指令就退出的,雖然也可以從新啟動,但是任務結束了,容器也還是會退出,而啟動bash會話會一直等待輸入,類似死循環,是以指定容器運作/bin/bash的話,如果不主動讓這個容器停止的話,就永遠不會退出(除非使用者發送指令退出),這樣就可以随便在上面配置你想要的東西了.
而我的/bin/init.sh意義和/bin/bash差不多,隻是功能更多一些,先來看看這個腳本究竟有什麼東西:
<code>#!/bin/bash</code>
<code>touch</code> <code>/var/lock/subsys/local</code>
<code>ulimit</code> <code>-HSn 65535</code>
<code>/bin/sh</code> <code>/etc/init</code><code>.d</code><code>/sshd</code> <code>start ></code><code>/dev/null</code> <code>2>&1</code>
<code>/bin/sh</code> <code>/etc/init</code><code>.d</code><code>/php-fpm</code> <code>start ></code><code>/dev/null</code> <code>2>&1</code>
<code>/bin/sh</code> <code>/etc/init</code><code>.d</code><code>/nginx</code> <code>start ></code><code>/dev/null</code> <code>2>&1</code>
<code>/bin/sh</code> <code>/etc/init</code><code>.d</code><code>/crond</code> <code>start ></code><code>/dev/null</code> <code>2>&1</code>
<code>source</code> <code>/etc/profile</code>
<code>/bin/bash</code>
<code>exit</code> <code>0</code>
我這個腳本就是啟動完ssh,php-fpm,nginx,crond和加載/etc/profile之後再執行/binbash,是以才說功能和/bin/bash差不多,隻是功能多了一些,至于為什麼要這樣做呢,正是我下面要說的事情.
從lxc開始到docker,容器終究是容器,不是虛拟機,一些本應在系統啟動的時候加載的軟體和環境變量并不會主動加載到容器内部,這個給我們帶來的難度是有些本來應該已經加載到容器内直接使用的東西,要手動去啟動和加載,相當不友善.
雖然有一些可以在建立可複用鏡像前做好(例如時區和語言環境),然而有一些還是要手動執行和啟動,我們終究是要解決的,是以就出現這種處理方式了,在啟動容器的時候,就讓他用腳本去啟動和加載,也就是/bin/init.sh的用途了.
下面來說一些坑點:
比較容易解決的是時區和語言環境,容器内不一定有你需求的語言包,例如zh_CN.UTF-8這個字元集,除了你要先確定母機有這個字元集,你可能還要先安裝兩個軟體包
<code>yum </code><code>install</code> <code>kde-l10n-Chinese</code>
<code>yum reinstall glibc-common</code>
不過,有可能還是不行的特殊情況,我感覺是yum軟體版本問題,然後自己建立字元集吧
<code>#建立字元集zh_CN.UTF-8</code>
<code>localedef -i zh_CN -f UTF-8 zh_CN.UTF-8</code>
<code>#如果你想用傳統的英文字元集en_US.UTF-8</code>
<code>#localedef -i en_US -f UTF-8 en_US.UTF-8</code>
<code>#添加到環境變量檔案最後一行</code>
<code>echo</code> <code>"export LANG=zh_CN.UTF-8"</code> <code>>></code><code>/etc/profile</code>
<code>echo</code> <code>"export LC_ALL=zh_CN.UTF-8"</code> <code>>></code><code>/etc/profile</code>
時區問題就比較狗血,如果沒定義好,很可能是UTC時間,這個就要修改指定時區了,各種系統不盡相同,下面僅供參考
<code>ln</code> <code>-sf </code><code>/usr/share/zoneinfo/Asia/Shanghai</code> <code>/etc/localtime</code>
還有就是一個還不清楚原因的簡單問題,linux的計劃任務crontab在容器内是不能自動生效的,甚是奇怪,需要修改一個地方才可以變得和一般機器一樣使用.
<code>sed</code> <code>-i </code><code>'s/required/sufficient/g'</code> <code>/etc/pam</code><code>.d</code><code>/crond</code>
還有就是關于容器登入密碼的問題,容器也是可能密碼登入的,是以也是可以用ssh來遠端連接配接,這也是為什麼要映射22端口,和啟動sshd的原因,設定密碼的方法就不多說了,passwd root就是了,反正就是給root使用者設定密碼了,如果把容器制作成鏡像,那麼容器的密碼也會自動随鏡像加載.
然後又一個關于centos7容器的特有問題,就是systemctl不能使用,導緻服務不能啟動,解決的辦法非常麻煩,但是用回centos6的方式"/etc/init.d/XXX start"就沒問題了,不過,你需要有centos6方式的腳本,例如sshd,httpd等,需要自己去找.
還有一個關于docker母機重新開機和docker更新的問題,母機重新開機是無可奈何,但是docker更新就要慎重,因為更新後需要重新開機docker程序,他們造成的問題都是docker會重新開機,由于docker内部的net網絡是随機配置設定IP的DHCP,是以每次重新開機都可能會出現IP位址和之前不一緻的情況,如果做了什麼反向代理或位址直連的腳本什麼的,就可能會失效了.
上面這些做完之後,一般來說你的容器已經和一般伺服器環境已經基本差不多了,然後使用類似我的腳本那樣的,自動把你想要的服務(例如ssh和web相關)啟動起來,加載profile環境(例如java環境)變量,這樣就真的和一台伺服器一樣了.
其他參數說明:
Attach--将終端依附到容器上
Build--通過Dockerfile建立鏡像
Commit--通過容器建立本地鏡像
Cp--在主控端和容器之間互相COPY檔案
Create--建立一個新的容器,注意,此時,容器的status隻是Created
Diff--檢視容器内發生改變的檔案,以我的mysql容器為例
Events--實時輸出Docker伺服器端的事件,包括容器的建立,啟動,關閉等。
Exec--用于容器啟動之後,執行其它的任務,也可以建立容器,例如:docker exec -ti cc /bin/bash
Export--将容器的檔案系統打包成tar檔案
History--顯示鏡像制作的過程,相當于dockfile
Images--列出本機的所有鏡像
Import--根據tar檔案的内容建立一個鏡像,與之前的export指令相對應
Info--檢視docker的系統資訊
Inspect--用于檢視容器的配置資訊,包含容器名、環境變量、運作指令、主機配置、網絡配置和資料卷配置等。
Kill--強制終止容器
load --與下面的save指令相對應,将下面sava指令打包的鏡像通過load指令導入
Login--登入到自己的Docker register,需有Docker Hub的新增賬號
Logout--登出
Logs--用于檢視容器的日志,它将輸出到标準輸出的資料作為日志輸出到docker logs指令的終端上。常用于背景型容器
Pause--暫停容器内的所有程序,
Port--輸出容器端口與主控端端口的映射情況
Ps--列出所有容器,其中docker ps用于檢視正在運作的容器,ps -a則用于檢視所有容器。
Pull--從docker hub中下載下傳鏡像
Push--将本地的鏡像上傳到docker hub中
Rename--更改容器的名字
Restart--重新開機容器
rm --删除容器,注意,不可以删除一個運作中的容器,必須先用docker stop或docker kill使其停止。
Rmi--删除鏡像
Run--讓建立的容器立刻進入運作狀态,該指令等同于docker create建立容器後再使用docker start啟動容器
Save--将鏡像打包,與上面的load指令相對應
Search--從Docker Hub中搜尋鏡像
Start--啟動容器
Stats--動态顯示容器的資源消耗情況,包括:CPU、記憶體、網絡I/O
Stop--停止一個運作的容器
Tag--對鏡像進行重命名
Top--檢視容器中正在運作的程序
Unpause--恢複容器内暫停的程序,與pause參數相對應
Version--檢視docker的版本
Wait--捕捉容器停止時的退出碼
附圖:
<a href="https://s5.51cto.com/wyfs02/M01/8E/FC/wKiom1jQwxGwyKFoAAFAkxeaUyg777.jpg" target="_blank"></a>
本文轉自arthur376 51CTO部落格,原文連結:http://blog.51cto.com/arthur376/1863986,如需轉載請自行聯系原作者