個人主力機是windows,windows下面有太多提高效率的軟件.可是開發的時候不得不使用linux.就單單開發而言.我仍是喜歡使用linux.因此就形成了我得在windows下面使用虛擬機.這是最開始的辦法.後面得知有vagrant這個東西以後,用了一陣子感受還不錯.可是我使用的時候動不動就會出現一些問題,因此一怒之下決定學學docker.而後使用docker來做爲開發環境.php
使用docker做爲開發環境大概我有這幾點要求html
部署快,不要換臺機子裝了一天的環境linux
穩定...nginx
輕輕輕!git
container得能夠訪問本機所在局域網github
能夠實現文件共享docker
在我接觸了一陣子docker以後,發現docker能夠知足我大部分意淫出來的美好開發環境.折騰一番以後終於搞定,因而祭出本文.但願能夠幫助到須要的人.shell
學習本篇以前但願你對docker有一丟丟的瞭解,一丟丟就能夠了.apache
我通常不喜歡講如何安裝一個軟件,可是介於docker的一些問題.仍是講講.ubuntu
若是是windows10以前的用戶,那麼安裝docker比較麻煩. 你可能須要一個Docker Toolbox
的東西,具體安裝方式請自行google.由於個人機子是Windows10的.
若是你是Windows10的用戶,恭喜你.你只要點這裏下載一個exe文件,而後就能夠無腦安裝了.可是要保證開啓Hyper-V
功能.如何開啓看這裏.注意,這個開啓以後就不能使用virtualbox虛擬機了.
安裝好以後,啓動docker在左下角就能夠看到docker的logo了.以後咱們的操做都是在PowerShell/CMD下面執行的了.執行docker info
會看到下面的內容
PS C:\Windows\system32\WindowsPowerShell\v1.0> docker info Containers: 1 Running: 1 Paused: 0 Stopped: 0 Images: 4 ........
因爲docker主機在外國,安裝好以後咱們須要更改下源,否則下載image的時候會很慢.這裏使用daoCloud提供的鏡像,你須要註冊登陸以後,獲取到每一個人獨一無二的url.而後粘貼要下面就能夠了.記得重啓啊喂...
在使用docker以前你要明白兩個概念,兩個學docker過程當中必定會一直強調的概念
image
container (這種術語直接使用英文,不作翻譯)
這兩個是整個docker的基礎概念,這裏本着不負責任的僥倖心理大概的說一下這兩個的區別.
image是靜態的,類比爲面向對象就是一個類
container是動態運行的,類比爲面向對象就是一個實例化的對象.
通常,container是可運行的,咱們啓動一個container以後,這個container裏面就是咱們的linux環境.
懂得了上面的意思,你就明白了咱們要作的事情很簡單:找一個合適的image,這個image裏面應該包含一切開發時候所須要的東西, 而後啓動它,咱們就能夠在這個container環境上工做了.固然這個時候container應該能夠跟宿主共享文件.而且能夠在本局域網內能夠被訪問到.
在繼續搭建咱們的開發環境以前,咱們仍是要先學一點docker的命令和概念的.
每一個image都有一個惟一的id來標識,一樣container也有.這個惟一的id通常很長,好比:c59dc2dfad95
,可是通常咱們輸入的時候只要輸入若干位能標識當前系統內惟一標識某一個image就能夠了.好比只要輸入c59d
可能就能夠標識這個image.除了id,還能夠給一個image起名字,這樣子也能夠經過name來操做一個image.
經過docker run image_name
能夠直接啓動本地的一個image.這個命令後面能夠加不少子參數來開啓其餘功能.若是本地不存在這個image,那麼docker會去官方的倉庫去下載,這個倉庫你能夠理解爲github同樣的網站,上面存放了許多別人push上去的image.
每一個image都有一個名稱.除了名稱以外還有一個叫作tag的東西,這個稱之爲標籤的東西能夠用來標識同一個image的不一樣版本.若是你沒有給一個image指定一個tag,那麼docker會默認爲這個iamge添加一個名爲:latest的tag.若是你使用docker run ubuntu
,那麼就會默認運行ubuntu:latest
.若是本地沒有這個image,那麼就會去從倉庫下載ubuntu:latest
的iamge.不少時候你會看到ubuntu:14.04
的image.這個14.04就是表明這個image的tag.只是不少時候image製做者把tag用來標記version了而已.
這個命令會列出本地全部的images.每一個image都會有一個獨一無二的id.以下面 IMAGE ID
字段.
PS C:\Windows\system32\WindowsPowerShell\v1.0> docker images REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu-ok latest 5f93b91bc208 26 hours ago 423.7 MB ubuntu latest a421b4d8494d 27 hours ago 423.1 MB ubuntu 14.04 3f755ca42730 2 days ago 188 MB
這個命令會列出全部在運行的container.當運行docker ps -a
就會列出全部的container.包括已經退出的container.
這個命令能夠把一個container製做成一個image.
docker rm container_id
能夠用來刪除一個container.docker rmi image_id/image_name
能夠用來刪除一個image.
不少文章講docker都會把這個放到後面一點講.反正不會在相似"使用docker作開發環境"的文章裏面講. 可是我以爲這個東西是理解docker的關鍵.因此必定要講.
AUFS比不是docker獨有的,不少Linux的發行版中都用到了這個特性.提及AUFS,這個東西是UFS的升級版,前面的A就是表明advanced的意思.那AUFS/UFS究竟是個什麼東西?
所謂AUFS,Advanced Union File System 就是把不一樣物理位置的目錄合併mount到同一個目錄中.這種技術有一點典型的應用:有些linux發行版只要插入一個光盤就能夠直接運行.不用進行安裝.你對系統文件進行的增刪改只是反映在電腦的硬盤上面,不會影響到光盤的內容.即對光盤只讀不寫.那麼docker是如何使把這個技術應用到docker上?
docker把一個鏡像分紅了不少層layer.這些層合併在一塊兒才成爲了一個完整的image.這樣子有什麼好處?最直觀的一點就是,ubuntu15.04跟ubuntu16.04的image可能只有一點點差異.這點差異體如今第四層layer上.那麼ubuntu15.04跟16.04就能夠共享前三層layer.這樣子若是你本地有了ubuntu15.04的image.那麼再pull ubuntu16.06的時候只要把第四層的pull下來就能夠了.
並且,image的全部層都是只讀的,當你啓動一個image當作container運行的時候,docker會在image的只讀層上加一層薄薄的可寫層.你在container裏面作的全部操做都是反映在可寫層.當你退出container以後,下次啓動同一個image,以前操做的全部東西都會沒有掉.一個從新作人的image.
這個時候有一個問題就來了,咱們pull一個image,啓動了container.好不容易把該安裝的軟件都安裝好了,而後退出了container.以前安裝的軟件就都沒有了!這個時候咱們就要使用commit命令了.commit命令能夠把當前的可寫層合併到image的只讀層裏面.這樣子這個image又多了一層.下次咱們啓動這個image的時候安裝的軟件就都還在了.
一個image由好幾層layer構成.每一個layer都是一個只讀層
當啓動一個container以後,就會在iamge的只讀層基礎上添加一個可寫層.全部對container執行的操做都反映在container上.(以上圖片都來自docker文檔.)
這裏提一點,當使用docker images
命令查看iamge信息的時候,後面的SIZE是表示當前iamge所佔用的大小,可是不意味着全部SIZE相加起來就是佔用磁盤空間的總大小.必定要注意,可能有image共享若干層layer.這些layer在相加的時候被計算了好幾遍.
PS C:\Windows\system32\WindowsPowerShell\v1.0> docker images REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> 12e32b701daa 25 minutes ago 188 MB ubuntu 14.04 3f755ca42730 3 days ago 188 MB centos 6 8315978ceaaa 6 weeks ago 194.6 MB
上面的命令提到刪除有rm跟rmi兩個,rm是用來刪除一個已經退出的container.rmi是用來刪除一個image的.有了上面AUFS的概念以後,要明白的是咱們使用docker rm container_id
的時候,其實只是刪除掉了一層可寫層的數據.由於只讀層是container跟image共享的.只要iamge沒有被刪掉,那麼只讀層的數據必定也不會被刪除掉.
一樣,當多個image共享若干層只讀層的時候,刪除掉一個image.只是刪除掉了這個image獨有的一層只讀層數據.其餘共享的數據並無被刪除掉,只有當刪除掉全部的image以後,共享的layer層纔會被刪掉.
執行刪除命令的時候會看到以下的信息,這裏每一次deleted都是表明刪除掉了一層layer.
PS C:\Windows\system32\WindowsPowerShell\v1.0> docker rmi ubuntu-fin Untagged: ubuntu-fin:latest Deleted: sha256:9e0728e8edbaf72846c43c629590fba5f46b1d705111d3fb1d79b9cf03a6c50c Deleted: sha256:d53e457ca7161cd6f2d1b6678ecaafd19043dcaeb1363471867e1047819268fa Deleted: sha256:496ef4fa137e03d80cf821745f875860d3d3120447326b8609938aa70f2edbd9 Deleted: sha256:12e32b701daa90c435176a273b2b41b4bfb219523c1ae396dc2f7068bbb6c088 Deleted: sha256:e8f29656cf54ad60a17d4b38362d9207b52a846cce3cc13e245fc3b799ff53e9 Deleted: sha256:48f6b521c809e40468886b0a159040503d00a0abb1eabf310451edfea562b459 Deleted: sha256:e94abc94ab1aff00280016eaf0649a75270886a2b60c8fe862ca549a0601949f Deleted: sha256:3f755ca4273009a8b9d08aa156fbb5e601ed69dc698860938f36b2109c19cc39 Deleted: sha256:565903b66233d5576592815ca4d499bd6fe09a9b4baf83f345aaf64544f1cd78 Deleted: sha256:b653e4373a4b35aa760ff67cfa3de2c9fe3c089823b63ec797eb04de256f86ba Deleted: sha256:362e536c4e530b94ce4204461e4f8c998705bcb98c91be54dd40b22f50531f3a Deleted: sha256:b69ad682d83af6a6962b4a60a0b5f033c8d39efcd20dbdf320b6dd8136e50aae Deleted: sha256:bc224b1b676d12be2a49f99778dda08b90d22747244d0a0afcdf4cfeb7db5d89
咱們再刪除iamge的時候有時候不能成功刪除.大概緣由有一下幾點:
container正在運行,你刪除這個container會失敗.應該使用docker stop container_id
退出當前container再嘗試刪除.
container退出了,刪除當前image也會失敗.由於container雖然退出,當前container保存着運行環境等數據.container是在iamge的基礎上添加了一層可寫層.因此他們是共享只讀層的.
刪除一個iamge會有Untagged: ubuntu:14.04
.這個不是沒有刪除成功.這個是由於有其餘image跟這個ubuntu:14.04共享layer層.因此刪除時候並無真正刪除掉layer層的數據.
ok,有了上面的預備知識,咱們如今能夠開始準備咱們的環境了.剛剛說過,咱們退出一個container以後在container所安裝的軟件,添加的文件等等數據都會丟失掉,因此正確的辦法應該是:在一個container環境中配置好全部開發要用到的東西以後,使用docker commit
命令來把當前這個container製做成一個image.而後下次咱們啓動這個image的時候環境就是咱們所須要的了.可是這樣子會存在三個問題:
當別人給你一個image以後,你知道這個image裏面安裝了哪些文件,修改了哪些數據麼?
每次commit都會造成一個新的只讀層.commit次數多了會使得image變得愈來愈臃腫.
再着,一個image動輒2,3G.帶着這麼大個文件跑也不優雅.
要解決上面的這些問題,就要使用Dockerfile了.因此咱們開始以前還要作點功課.
Dockerfile是用來描述如何構建一個image的,Dockerfile由一些指令構成,所有指令大概有20個左右,這裏不所有講解.只講一些咱們下面會用到的.具體Dockerfile的所有用法參考Docker官方出的最佳實踐.
咱們要製做的image必然是基於某個現有image的基礎,from命令就是用來指定使用哪一個基礎iamge的.像不少ubuntu官方在Docker Hub上維護由官方的image.咱們下面開發環境的搭建就是基於ubuntu:14.04的環境下完成的.
copy命令是把宿主機上的文件拷貝到image中.add能夠是copy的高級版.
copy要求拷貝的文件在宿主機上存在
add能夠指定一個url座位源文件,docker會自動去下載這個url的文件, 而後拷貝到image中.
咱們待會兒就會用到add指令,由於咱們須要使用163的ubuntu源來替換ubuntu原生的apt-get
源.因此咱們的Dockerfile會有相似的指令 : ADD http://mirrors.163.com/.help/sources.list.trusty /etc/apt/sources.list
.
這個是指定啓動一個container以後,默認執行的命令.咱們執行docker run ubuntu:14.04
啓動一個container以後,默認就進入了bash界面.這就說明這個ubuntu:14.04的CMD就是bash.
這裏要澄清一個概念.使用docker run
以後默認進入了bash會讓不少人覺得啓動container跟啓動一個虛擬機沒什麼區別.其實不是的.docker的container就是爲了某個進程而存在的,這個進程就是CMD所指定的程序.好比:CMD /bin/bash
就是啓動了bash.當咱們退出了bash以後,整個container也就退出了.若是你的CMD寫成:CMD service nginx start
.你會發現container執行以後就立刻結束了.這是由於整個container只是爲了service nginx start
這條命令而存在的,它不會管你這條命令啓動了什麼.默認啓動的bash正好是一直在前臺運行,只有你使用exit命令退出bash的時候才結束bash進程.這個時候container才結束.纔會讓人有container跟虛擬機差很少的錯覺.
上面的這個概念很重要,必定要理解透徹.若是沒有搞清楚這點.你會一直以爲docker跟虛擬機沒有什麼區別.
這個命令指定了在構建image時候image中藥執行的命令.這麼說可能有點蹩腳.舉個例子,咱們但願咱們的鏡像構建好的時候就安裝好了git.那麼咱們就能夠在Dockerfile裏面寫RUN apt-get -y install git
.這樣子在構建鏡像的時候就會去安裝git了.待會兒咱們要安裝的軟件都是經過這個命令指定的.也是有了RUN指令,咱們就能夠知道一個image構建過程當中作了一些什麼操做.
好了.Dockerfile咱們目前只須要這些指令.下面咱們就根據上面學到的東西來快速的搭建咱們所須要的開發環境.
我知道,上面那樣子好像很隨意的講了一下Dockerfile,確定也不會寫.因此,這裏我給出我構建iamge使用的Dockerfile做爲參考.
FROM ubuntu:14.04 ADD http://mirrors.163.com/.help/sources.list.trusty /etc/apt/sources.list COPY install.sh /usr/local/src/install.sh COPY supervisord.conf /usr/local/src/supervisord.conf RUN apt-get update && \ apt-get -y install build-essential && \ apt-get -y install supervisor && \ cp /usr/local/src/supervisord.conf /etc/supervisor/supervisord.conf && \ apt-get -y install openssh-server && \ apt-get -y install git && \ apt-get -y install vim && \ apt-get -y install lrzsz && \ apt-get -y install libxml2-dev && \ apt-get -y install pkg-config libssl-dev libsslcommon2-dev && \ apt-get -y install libbz2-dev && \ apt-get -y install libcurl4-gnutls-dev && \ apt-get -y install libjpeg8-dev && \ apt-get -y install libpng-dev && \ apt-get -y install libfreetype6-dev && \ apt-get -y install libmcrypt-dev && \ apt-get -y install libxslt-dev && \ apt-get -y install libgmp-dev && \ apt-get -y install libreadline-dev && \ ln -s /usr/include/x86_64-linux-gnu/gmp.h /usr/include/gmp.h && \ bash /usr/local/src/install.sh && \ adduser --gecos '' --disabled-password chenjiayao && \ echo -e '1111\n1111' | passwd chenjiayao && \ echo -e '11\n11' | passwd root CMD supervisord -n
上面的Dockerfile其實至關的簡單,指令都是咱們上面用到的,這裏再解釋一下每一行的做用.
第一行FROM ubuntu:14.04
指明瞭使用ubuntu官方維護的14.04的image做爲基礎image來構建本身的image.執行這條指令以後,若是你的本地沒有ubuntu:14.04
這個image的話, 那麼就會去hub docker下載
第二行ADD指令上面提到了,這裏就是使用163的源代替ubuntu內置的源,這樣子下載軟件的速度就會比較快.
接着是兩個copy指令.這裏從宿主機拷貝了兩個文件到鏡像中.其中install.sh是我本身寫的編譯安裝php+apache的腳本文件,這裏根據本身須要來決定.後面的supervisord是linux下面用來管理進程的軟件.你會發現CMD啓動的就是supervisord
.後面-n
參數說明是之前臺的方式啓動.而不是後臺啓動.這樣子就避免了container運行一下就退出了.
RUN 裏面都是在安裝軟件.執行一些必要的操做.你會發現我把全部的軟件安裝都寫成了一個RUN指令.你可能會有疑問爲何不使用不少個RUN來編寫.爲何要再一個RUN裏面安裝所有軟件.這裏就要說明一點 : 每執行一個Dockerfile的指令都會讓咱們的image增長一層只讀層.因此,寫不少指令的話,咱們的image就會有太多的layer.因此儘可能要剋制命令的個數.
CMD命令.這裏我沒有使用默認的bash做爲啓動命令是由於:若是使用bash做爲默認的啓動進程以後,當前container就只會有一個進程bash.那麼其餘的apache.ssh等服務都不會自動啓動.*每次運行container都得手動啓動這些服務很麻煩.因此這裏使用supervisor來管理.配置好supervisor以後,只要啓動了supervisor,supervisor就會自動幫咱們啓動其餘進程.好比apache.ssh等等.這樣就比較方便.因此若是還不知道supervisor的童鞋,趕忙學起來,並且至關的簡單.若是就是不學的同窗,也不要急,後面我會給出個人Dockerfile和其餘配置文件.能夠直接clone個人.
好了,Dockerfile咱們已經準備好了,下面使用docker build -t ubuntu-php .
來構建本身的image了.可是在開始以前要強調一下build的命令.
build命令 接着 -t ubuntu-php
表示構建好的image的名稱.注意後面的.
,這參數表示的是當前目錄.不少時候咱們在一個目錄下建立了Dockerfile,編寫好以後.使用powershell進入這個目錄. 而後執行docker build -t image_name .
就開始編譯.很容易就覺得最後一個參數是指定Dockerfile所在的目錄.其實不是這樣子的.這個目錄指定的是當前docker編譯這個image的工做目錄.
要先明白,docker是一個C/S的軟件,咱們使用powerShell輸入命令 .以後命令是被髮送到服務端執行,而後返回結果的.這跟MySQL同樣.只是咱們把客戶端和服務端安裝在一臺主機上.
當咱們構建image的時候,執行相似COPY指令,那麼把文件拷貝到image中,可是構建文件是在服務端完成的,如何讓docker服務端獲得拷貝的文件?這裏咱們就要指定一個docker構建的工做目錄了.當構建開始的時候,docker會把工做目錄下的全部文件都發送到服務端.而後開始構建.這樣子他就能夠獲得咱們要copy到image的文件了.
因此咱們構建的時候指定.
是想把當前目錄下的文件等發送到docker服務端進行構建.只是在上面,咱們的Dockerfile正好是放在了docker構建image的工做目錄中了.
那麼,既然上面的參數不是指定Dockerfile所在的目錄.那若是個人機子上有多個Dockerfile的話,那麼docker會使用哪一個?我編寫這個Dockerfile的目的就是但願使用這個Dockerfile.這個不用擔憂. 若是你在build的時候沒有指定使用哪一個Dockerfile.默認會使用構建iamge的工做目錄下名字爲Dockerfile的那個Dockerfile....聽着有點暈...若是不想理清楚這些問題.每次構建的時候使用powerShell進入Dockerfile所在的目錄下,而後執行docker build image_name .
就能夠了.
在構建過程當中會輸出相似下面的內容
PS D:\code\docker\ubuntu> docker build -t ubuntu-fin . Sending build context to Docker daemon 8.192 kB Step 1 : FROM ubuntu:14.04 ---> 3f755ca42730 Step 2 : ADD http://mirrors.163.com/.help/sources.list.trusty /etc/apt/sources.list Downloading [==================================================>] 872 B/872 B ---> 386d7ab302b9 Removing intermediate container f183c42cf864 Step 3 : COPY supervisord.conf /usr/local/src/supervisord.conf ---> 8ce5250f8498 Removing intermediate container 2c6d89b3be22 Step 4 : COPY install.sh /usr/local/src ---> efa055e7d1b3 Removing intermediate container e0c7dacd9136 Step 5 : RUN apt-get update && apt-get -y install build-essential && apt-get -y install supervisor && cp /usr/local/src/supervisord.conf /etc/supervisor/supervisord.conf && apt-get -y install openssh-server && apt-get -y install git && apt-get -y install vim && apt-get -y install lszrz && apt-get -y install libxml2-dev && apt-get -y install pkg-config libssl-dev libsslcommon2-dev && apt-get -y install libbz2-dev && apt-get -y install libcurl4-gnutls-dev && apt-get -y install libjpeg8-dev && apt-get -y install libpng-dev && apt-get -y install libfreetype6-dev && apt-get -y install libmcrypt-dev && apt-get -y install libxslt-dev && apt-get -y install libgmp-dev && apt-get -y install libreadline-dev && ln -s /usr/include/x86_64-linux-gnu/gmp.h /usr/include/gmp.h && bash /usr/local/src/install.sh && adduser --gecos '' --disabled-password chenjiayao && echo -e '1111\n1111' | passwd chenjiayao && echo -e '11\n11' | passwd root ---> Running in 1dd5ade41249
發現,每個Step其實就是執行Dockerfile中的每個指令.好了,構建已經開始,等待構建結束以後,咱們的環境也就搭建好了,建議把Dockerfile等構建必須的文件放到github上面,之後換一個環境.只要下載文件.而後就能夠構建了.
這裏我放出我構建環境時寫的Dockerfile,有須要自取.傳送門.
最後咱們還有三個問題須要解決:
文件共享
端口映射
commit製做鏡像
這些問題,考慮到文章篇幅應該夠多,因此將再開一篇文章簡介.