最近研究了幾天docker的快速部署,感覺很有新意既琴,非常輕量級和方便占婉,打算在公司推廣一下,解放運維甫恩,省得每次部署一臺新服務器都去跑安裝腳本了逆济,對于我們開發(fā)人員也是好事情,無需寫太多重復的部署文檔磺箕,直接將docker的images丟上服務器就可以運行了奖慌。
可能還有一些同學不了解docker這個項目,docker是由go語言編寫的松靡,一個快速部署的輕量級虛擬技術項目简僧,他允許開發(fā)人員將自己的程序和運行環(huán)境一起打包,制作成一個docker的image(鏡像)雕欺,這樣部署到服務器上岛马,也只需要下載這個image就可以將程序跑起來,免去每次都安裝各種依賴和環(huán)境的麻煩屠列,還能夠做到應用程序之間的隔離啦逆,因為我們公司部署的python程序,這樣一來我也省去了每次都到新服務器配置 vitualenv了笛洛。
官網(wǎng)地址:http://www.docker.com/
如此看來docker非常適合做小巧的外包項目夏志,免去每次都為客戶配置一遍運行環(huán)境,費時費力苛让。
一沟蔑、安裝:
安裝很簡單,直接進入下載頁面蝌诡,根據(jù)自己的操作系統(tǒng)下載相對應的安裝包即可溉贿,下面說一下windows安裝:
下載地址:https://docs.docker.com/installation/windows/
在安裝docker時,會附帶安裝git和VirtualBox浦旱,所以可能安裝時間稍微長一些宇色,安裝完畢重啟系統(tǒng),以管理員身份進入命令行,就可以使用進入linux虛擬機命令 “boot2docker” 宣蠕,由于docker目前的鏡像只針對linux例隆,所以windows下面必須安裝虛擬機才能使用。
第一次使用boot2docker start抢蚀,會出現(xiàn)錯誤:
Failedtogetmachine"boot2docker-vm":machine doesnotexist
沒關系镀层,這是因為沒有boot2docker iso的鏡像所致,執(zhí)行:
$ boot2docker init
就可以初始化鏡像皿曲,耐心等待下載并安裝完畢后唱逢,我們繼續(xù)執(zhí)行開啟虛擬機。
$ boot2docker start
在windows下是無法直接使用cmd窗口來操作linux系統(tǒng)的屋休,所以我們需要進入linux虛擬機來操作docker坞古,執(zhí)行:
$ boot2docker ssh
就可以進入linux虛擬機,如果要退出并關閉虛擬機劫樟,執(zhí)行如下命令:
$exit$ boot2docker stop
調(diào)試時查看虛擬機ip地址痪枫,后面部署測試環(huán)境會用到:
$ boot2docker ip192.168.59.103
我們可以通過ssh的ip地址192.168.59.103,用戶名 docker叠艳,密碼 tcuser奶陈,登錄到虛擬機中去。
如果不幸長時間無法init成功附较,說明鏡像被GFW擋住了吃粒,手動去github上下載鏡像,地址為:
https://github.com/boot2docker/boot2docker/releases
如果還是無法下載成功拒课,我是好心人声搁,把1.1.2版本的boot2docker.iso鏡像丟到了百度云上:
http://pan.baidu.com/s/1c01qieG
下載完畢之后放到目錄:
C:\Users\你的用戶名\.boot2docker\boot2docker.iso
然后再執(zhí)行
$ boot2docker init
二、下載鏡像捕发,安裝環(huán)境
我們先執(zhí)行如下命令,啟動虛擬機:
$ boot2docker start2014/08/1821:22:41WaitingforVM to be started..............2014/08/1821:23:21Started.2014/08/1821:23:21Dockerclient doesnotrun onWindowsfornow.Pleaseuse2014/08/1821:23:21"boot2docker"ssh2014/08/1821:23:21to SSHintothe VM instead.
如果我們的物理機內(nèi)存低于4G,那么跑這個boot2docker可能需要手動設置內(nèi)存占用大泻芑辍:
$ boot2docker start-m=512
我們利用命令就可以進入linux虛擬機了
$ boot2docker ssh##? ? ? ? .## ## ##? ? ? ==## ## ## ##? ? ? ===/""""""""""""""""\___/===~~~{~~~~~~~~~~~~~~~~/? ===- ~~~
\______ o? ? ? ? ? __/\? ? \? ? ? ? __/\____\______/_? ? ? ? ? ? ? ? _? ____? ? _? ? ? ? ? ? _||__? ___? ___||_|___ \ __||___? ___||_____ _ __|'_ \ / _ \ / _ \| __| __) / _` |/ _ \ / __| |/ / _ \ '__|||_)|(_)|(_)||_/__/(_||(_)|(__|<__/||_.__/\___/\___/\__|_____\__,_|\___/\___|_|\_\___|_|boot2docker:1.1.2master:740106c-ThuJul2403:24:10UTC2014
執(zhí)行 docker 命令扎酷,會有一個命令列表,里面列出了所有 docker 支持的功能遏匆,列表如下:
Commands:attachAttachto a running container
buildBuildan imagefromaDockerfilecommitCreateanewimagefroma container's changes
... ...
下面會對一些常用的命令進行示例說明法挨,我們可以通過如下命令,先查找centos的鏡像幅聘,并把他下載下來
$ docker search centos#查找centos名字的鏡像$ docker pull centos#下載官方純凈版本的centos鏡像
在調(diào)用search命令時凡纳,你會看到有好多centos包,他們都是這樣的/帝蒿,這些不在根目錄的鏡像都是非官方的荐糜,是其他用戶提交到docker hub上去的,耐心等待片刻我們就可以將centos的鏡像拉下來了。
如果臉黑暴氏,鏡像又不幸被墻延塑,那么試試加上下面的hosts:
54.234.135.251get.docker.io54.234.135.251cdn-registry-1.docker.io
成功下載好centos鏡像之后,我們可以利用如下命令來查看鏡像列表:
$ docker images
REPOSITORY? ? ? ? ? TAG? ? ? ? ? ? ? ? IMAGE ID? ? ? ? ? ? CREATED
VIRTUAL SIZE
centos? ? ? ? ? ? ? centos6? ? ? ? ? ? b1bd49907d552weeks ago212.5MB
centos? ? ? ? ? ? ? centos7? ? ? ? ? ? b157b77b1a652weeks ago243.7MB
centos? ? ? ? ? ? ? latest? ? ? ? ? ? ? b157b77b1a652weeks ago243.7MB
接下來我們就利用centos7這個鏡像輸出一段 hello world
$ docker run b15/bin/echo'Hello world'Helloworld
注意這里的 b15答渔,他表示centos7這個images的id关带,不用全部打全,只要保證輸入的id前幾位能找到唯一鏡像即可沼撕,這點很贊宋雏。
稍微復雜一點的例子:
$ docker run-i-d-t b15/bin/sh-c"while true; do echo hello world; sleep 1; done"
-i表示同步container的stdin,-t表示同步container的輸出务豺,-d表示deamon磨总,以后臺啟動這個container,執(zhí)行這個container是永遠不會停止的冲呢,每一秒鐘都會輸出hello world舍败。
至于什么是container,container和image的關系我們下一段再說敬拓,列出鏡像的歷史:
$docker history image_name
三邻薯、安裝環(huán)境
在開始第三段介紹之前,有必要說幾個利用windows cmd窗口的小技巧乘凸。
1厕诡、如果想要使用標記選中功能,你會發(fā)現(xiàn)营勤,當我們進入 boot2docker ssh 之后灵嫌,鼠標對窗口的右鍵是無效的,所以想要利用標記選中窗口內(nèi)的文字得這么弄:“點擊左上角圖標->編輯->標記”葛作,這樣就可以使用標記了
2寿羞、如果從其他地方復制了命令,但是窗口沒有右鍵無法粘貼怎么辦赂蠢?用和1相同的辦法:“點擊左上角圖標->編輯->粘貼”绪穆。
3、坑爹的windws如果命令太長虱岂,在boot2docker ssh里換行會錯位的玖院,在“點擊左上角圖標->屬性->布局->屏幕緩沖區(qū)大小和窗口大小”的數(shù)值,保證長的命令也在一行內(nèi)就沒有問題了第岖,注意要重啟cmd窗口难菌。
接下來我們簡單說明一下image和container的關系,image顧名思義就是鏡像的意思蔑滓,我們把他理解為一個執(zhí)行環(huán)境(env)郊酒,當我們執(zhí)行了docker run命令之后遇绞,dock就會根據(jù)當前的image創(chuàng)建一個新的container,container更像是一個操作或者程序運行的一個沙箱猎塞,他們互相獨立试读,但是都運行在image創(chuàng)建的執(zhí)行環(huán)境之上,根據(jù)上一段我們執(zhí)行了2個run的任務荠耽,也就創(chuàng)建了2個獨立的container钩骇,我們通過命令
$ docker ps#查看當前運行的container$ docker ps-a#查看所有的containerCONTAINER ID? ? ? ? IMAGE? ? ? ? ? ? ? COMMAND? ? ? ? ? ? ? ? CREATED? ? ? ? ? ? STATUS? ? ? ? ? ? ? ? ? ? ? PORTS? ? ? ? ? ? ? NAMES
d1eca89869d0? ? ? ? centos:centos7/bin/sh-c'while tr? 13 minutes ago? ? ? Exited (0) 7 minutes ago? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? distracted_mcclintock
0b71024c8a95? ? ? ? centos:centos7? ? ? /bin/sh -c 'whiletr15minutes agoExited(0)7minutes ago? ? ? ? ? ? ? ? ? ? ? ? pensive_meitner79a488c9cfb6centos:centos7? ? ? console22minutes ago? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? sick_babbage06f43c19d10acentos:centos7/bin/echo'Hello wor? 25 minutes ago? ? ? Exited (0) 25 minutes ago? ? ? ? ? ? ? ? ? ? ? berserk_einstein
我們可以分別利用命令對image和container進行刪除
$ docker rm#刪除container$ docker rmi#刪除image$ docker rm`docker ps -a -q`#刪除所有容器
這樣執(zhí)行一次run就創(chuàng)建一個container,勢必會造成大量的無用的container铝量,可能我不需要持久化保存container倘屹,如果在docker run命令加上 --rm=true 選項,那當這個container執(zhí)行完畢慢叨,將自動自己刪除寻定,保證了container數(shù)量不會泛濫增長枝哄。
我們之前下載純凈版centos7是沒有任何第三方軟件的,包括wget,ping等命令都要通過yum工具來重新安裝处硬,我們當然不想每次都重新安裝這些東西堰塌,我不僅希望要把一些常用的庫安裝到的image中去扩氢,同時還希望把程序運行的環(huán)境也安裝進去换衬,所以image更像是一個系統(tǒng)的模版。
你會發(fā)現(xiàn)亡蓉,當你執(zhí)行如下命令晕翠,wget命令時安裝成功了,但是當你下次執(zhí)行wget命令時砍濒,又會報錯淋肾,說找不到這個命令,到底是怎么回事呢爸邢?
$ docker run-t b15 yum install-y wget#通過yum工具安裝wget命令#安裝完畢后樊卓,執(zhí)行wget會報沒有這個命令$ docker run-t b15 wget http://www.baidu.com2014/08/1815:42:19exec:"wget":executable filenotfoundin$PATH
為什么會出現(xiàn)這個問題呢?答案就是我們上面所說的那樣杠河,每次執(zhí)行docker run都會去獨立的創(chuàng)建一個新的container來執(zhí)行程序简识,所以我們必須手動把這些對container的更改提交成一個新的image,才能夠依據(jù)這個image執(zhí)行wget操作感猛。
我們先把當前所有的container都刪除,然后直接登錄到container的bash命令窗口中去奢赂,免得每次都去輸入docker run了
$ docker run-t-i b15/bin/bash
bash-4.2#
這樣我們進入了一個新的container陪白,依據(jù)centos7作為模板,我們將要在其上面安裝wget工具膳灶,直接執(zhí)行
$ yum install-y wget
安裝完畢之后咱士,我們執(zhí)行exit退出container
輸入docker ps -a 我們找到剛才安裝過wget工具的container ID立由,我們要把這個container重新做成一個新的image模版,這個模版將帶wget命令序厉。
$ docker ps-a
CONTAINER ID? ? ? ? IMAGE? ? ? ? ? ? ? COMMAND? ? ? ? ? ? CREATED? ? ? ? ? ? STATUS? ? ? ? ? ? ? ? ? ? PORTS? ? ? ? ? ? ? NAMES26cc82ad29afcentos:centos7/bin/bash3minutes agoExited(0)5seconds ago? ? ? ? ? ? ? ? ? ? ? desperate_mccarthy
我們執(zhí)行如下命令锐膜,將一個安裝過軟件的container提交為一個image
$ docker commit26wget-centos760cd26c6ca1e753bf77aa913ed7b826767a678b75f6dd8421353f6c0899d3e5e
我們查看當前image鏡像的列表:
wget-centos7? ? ? ? latest60cd26c6ca1e37seconds ago304.6MB
centos? ? ? ? ? ? ? centos6? ? ? ? ? ? b1bd49907d552weeks ago212.5MB
centos? ? ? ? ? ? ? centos7? ? ? ? ? ? b157b77b1a652weeks ago243.7MB
centos? ? ? ? ? ? ? latest? ? ? ? ? ? ? b157b77b1a652weeks ago243.7MB
你會發(fā)現(xiàn)多了一行我們剛才提交的 wget-centos7 的image鏡像記錄,現(xiàn)在我們執(zhí)行這個鏡像的wget命令弛房,看看會不會報錯
$ docker run-t-i--rm=true60wget http://www.baidu.com--2014-08-1815:54:55--http://www.baidu.com/Resolvingwww.baidu.com(www.baidu.com)...180.97.33.108,180.97.33.107Connectingto www.baidu.com(www.baidu.com)|180.97.33.108|:80...connected.HTTP request sent,awaiting response...200OK
執(zhí)行完畢后道盏,docker自動刪除這個container,并且至今報錯的wget命令無法找到也不會出錯了文捶。
第二種安裝環(huán)境的辦法荷逞,類似腳本安裝,我們預先錄入好一系列安裝腳本粹排,可以讓docker幫我們依次執(zhí)行這些安裝腳本种远,然后生成image,例如有安裝腳本Dockerfile:
# This is a commentFROM centos
MAINTAINER doublespoutRUN yum install-y wget
我們執(zhí)行如下命令進行創(chuàng)建images
$ mkdir wget
$ cd wget
$ viDockerfile#將上面內(nèi)容復制進去$ docker build-t="doublespout/wget"./#將看到安裝腳本的執(zhí)行輸出顽耳,安裝完成后坠敷,執(zhí)行 docker images 就可以看到我們剛才創(chuàng)建的鏡像了docker images
container 和 host 文件互相拷貝:
1、從container往host拷貝文件:
docker cp:/root/hello.txt.
2射富、從host往container里拷貝文件膝迎,比較麻煩一點,首先停止Contaitner(當然不停止也能拷貝)
docker stop
然后執(zhí)行拷貝操作辉浦,執(zhí)行完成之后就能看到Contaitner里有這個文件拉
#執(zhí)行命令找到程序pidContainerID=$(docker inspect--format{{.Id}})cp/tmp/tmp.txt/var/lib/docker/aufs/mnt//tmp/
四弄抬、發(fā)布應用程序
我們根據(jù)上一段的步驟,手動將node.js環(huán)境裝好container并且發(fā)布成image宪郊,并保存"app.js"文件到"/var/nodejs/app.js"掂恕,文件內(nèi)容為:
varhttp=require('http');http.createServer(function(req,res){res.writeHead(200,{'Content-Type':'text/plain'});res.end('Hello World\n');}).listen(1337);//注意這邊不能和官網(wǎng)示例那樣監(jiān)聽127.0.0.1console.log('Server running at http://0.0.0.0:1337/');
執(zhí)行如下命令,運行container:
$ docker run-d-i-p--name=nodeapp1337:1337fa node/var/nodejs/app.js#32bac9ed8ba055c935bd641d23097a36a573a243ee942358fd74dc4140308bc6
其中fa是我創(chuàng)建的鏡像id弛槐,這個值因人而異懊亡,name參數(shù)是給這個container取名字,必須是唯一的乎串。
-p參數(shù)就是類似端口映射的功能店枣,將主機的端口1337映射到contianer的1337端口,我們可以運行 docker ps叹誉,查看正在運行的container鸯两,打開瀏覽器,就能夠看到 hello world了长豁。
用同樣的方法就可以將我們開發(fā)好的應用快速部署到生產(chǎn)服務器上去了钧唐。如果在docker run命令需要設置cpu的支持數(shù)和權重值可以這樣:
-c,--cpu-shares=0CPU shares(relative weight)--cpuset=""CPUsinwhich to allow execution(0-3,0,1)
另外一個小敲門,如果我想要進入一個在運行中的docker container時匠襟,可以使用 docker attach钝侠,連上這個container的輸入和輸出该园。
五、將多個 container 連接起來
我現(xiàn)在先下載一個redis數(shù)據(jù)庫image帅韧,這也是以后做項目的常規(guī)用法里初,數(shù)據(jù)庫單獨用一個image,程序一個image忽舟,利用docker的link屬性將他們連接起來双妨。
$ docker pull redis#下載官方的redis鏡像,耐心等待一段時間
接著我們執(zhí)行命令啟動redis鏡像到一個container萧诫,開啟redis-server持久化服務
$ docker run--name redis-server-d redis redis-server--appendonly yes
然后我們再啟動一個redis鏡像的container作為客戶端連接它
$ docker run-it--link redis-server:redis--rm redis/bin/bash
redis[@7441b8880e4e](/user/7441b8880e4e):/data$ env#想要知道當前我們在主機還是container斥难,注意$前面的host和nameREDIS_PORT_6379_TCP_PROTO=tcp
HOSTNAME=7441b8880e4eTERM=xterm
REDIS_NAME=/boring_perlman/redis
REDIS_PORT_6379_TCP_ADDR=172.17.0.34#redis服務器ipREDIS_PORT_6379_TCP_PORT=6379#redis服務器端口PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/data
REDIS_PORT_6379_TCP=tcp://172.17.0.34:6379SHLVL=1REDIS_PORT=tcp://172.17.0.34:6379HOME=/
_=/usr/bin/env
$ redis-cli-h"$REDIS_PORT_6379_TCP_ADDR"-p"$REDIS_PORT_6379_TCP_PORT"172.17.0.34:6379>seta1#成功連入redis數(shù)據(jù)庫服務器OK172.17.0.34:6379>geta"1"172.17.0.34:6379>
通過這樣的方法,我們就可以將發(fā)布的應用程序和數(shù)據(jù)庫分開帘饶,單獨進行管理哑诊,以后對數(shù)據(jù)庫進行升級或者對程序進行調(diào)整兩者都沒有沖突,系統(tǒng)環(huán)境變量我們可以通過程序的os模塊來獲得及刻。
六镀裤、文件卷標加載
比如我們想要一個日志文件保存目錄,如果直接寫入container缴饭,那樣image升級之后暑劝,日志文件處理就比較麻煩了,所以就需要將主機的文件卷標掛載到container中去颗搂,掛載方法如下:
$ docker run--rm=true-i-t--name=ls-volume-v/etc/:/opt/etc/centos ls/opt/etc
boot2docker? hostname? ? ld.so.conf? ? passwd-securetty? sysconfigdefaulthosts? ? ? ? mke2fs.conf? ? pcmcia? ? ? services? sysctl.conf
fstab? ? ? ? hosts.allow? modprobe.conf? profile? ? ? shadow? ? udevgrouphosts.deny? motd? ? ? ? ? profile.d? ? shadow-versiongroup-init.d? ? ? mtab? ? ? ? ? protocols? ? shells
gshadow? ? ? inittab? ? ? netconfig? ? ? rc.d? ? ? ? skel
gshadow-issue? ? ? ? nsswitch.conf? resolv.conf? ssl
host.conf? ? ld.so.cache? passwd? ? ? ? rpc? ? ? ? ? sudoers
如果想要掛載后的文件是只讀担猛,需要在這樣掛載:
-v/etc/:/opt/etc/:ro#read only
我們也可以掛載其他container中的文件系統(tǒng),需要用到 -volumes-from 參數(shù)丢氢,我們先創(chuàng)建一個container傅联,他共享/var/目錄給其他container。
$ docker run-d-i-t-p1337:1337--name nodedev-v/var/fa node/var/nodejs/app.js
然后我們啟動一個ls-var的container來掛載nodedev共享的目錄:
$ docker run--rm=true-i-t--volumes-fromnodedev--name=aaa1 centos ls/varadm? ? db? ? games? kerberoslocallog? nis? ? opt? ? ? run? ? tmp? yp
cache? empty? gopher? liblockmail? nodejs? preserve? spoolvar
我們打印var目錄疚察,會發(fā)現(xiàn)多了一個nodejs的目錄蒸走,就是從nodedev中的container掛載過來的。其實我們掛載其他container的路徑都是在根目錄上的貌嫡。
七比驻、發(fā)布到docker hub上去
我們做完鏡像,就需要將鏡像發(fā)布到docker hub上岛抄,供服務器下載然后運行别惦,這類似git倉庫,將自己開發(fā)的東西丟到云服務器上夫椭,然后自己在其他機器或者其他開發(fā)者可以下載鏡像步咪,并且從這個鏡像開始運行程序或者再進行2次制作鏡像。
我們需要先登錄docker帳號益楼,執(zhí)行:
$ docker login#輸入你在docker官網(wǎng)注冊的帳號和密碼就可以登錄了$ docker push<用戶名>/<鏡像名>#將你制作的鏡像提交到docker hub上
非官方不允許直接提交根目錄鏡像猾漫,所以必須以<用戶名>/<鏡像名>這樣的方式提交,比如 doublespout/dev 這樣
八感凤、總結
docker快速部署介紹完畢了悯周,總結一下,要創(chuàng)建一個簡單項目使用的步驟:
1陪竿、安裝配置docker
2禽翼、pull鏡像,安裝程序執(zhí)行環(huán)境
3族跛、pull數(shù)據(jù)庫鏡像
4闰挡、開發(fā)程序
5、push 程序的鏡像
6礁哄、服務器安裝配置docker
7长酗、運行數(shù)據(jù)庫鏡像
8、運行程序鏡像桐绒,并且把數(shù)據(jù)庫鏡像link進來夺脾,并且掛載主機的日志目錄或其他上傳目錄。
使用了docker以后茉继,環(huán)境配置只需一次咧叭,免去了開發(fā)部署一套,測試部署一套烁竭,生產(chǎn)又部署一套的麻煩菲茬,以后程序搬家也是非常簡單。
最后分享一個小敲門派撕,如何像使用linux虛擬機那樣運行一個container婉弹,比如我我們想要直接登錄container執(zhí)行多個任務,又不想直接借助 docker run 命令腥刹,以后我們還想登錄到這個container來查看運行情況马胧,比如執(zhí)行top,ps -aux命令等等衔峰。
$ docker run-d-i-t-p1337:1337fa/bin/bash
$ docker attach58bash-4.2#
這樣我們就可以通過進入container來調(diào)試程序了佩脊。但是一旦執(zhí)行ctrl+d或者exit,container就將退出垫卤,這個方法也只適用于開發(fā)調(diào)試的時候威彰。
最后請?zhí)?container 是一個小的vps的概念,詳見另一篇文章.