一,小王對于容器的困惑
小王剛開始學習Docker的時候,找資料在網上看到最多的是Docker的好處。比如:
1、Docker 容器的啟動可以在秒級實現,這相比傳統的虛擬機方式要快得多
2、Docker 對系統資源的利用率很高,一臺主機上可以同時運行數千個 Docker 容器。
3、更快速的交付和部署、更輕松的遷移和擴展
等等……
因為小王是做java開發的,他們現有的模式是在一個服務器上安裝統一一個jdk,運行多個tomcat,每個tomcat里面一個java應用,大家也知道tomcat不用安裝,當他們項目要遷徙的時候也只需要把整個tomcat打包然后在另一臺服務器上解壓就ok了,也很簡單。。。當時小王就不懂Docker有什么好處,一度以為對他們現有的模式沒用。知道昨天跟其他人交流小王才弄明白一個問題,那就是應用隔離與資源獨立!!

這是小王剛畫的一個圖,現在他們的模式是A1,所有的應用共享服務器的CPU、內存等資源,這時如果一個應用出現問題,比如CPU爆滿等等,另一個應用也就玩完了。所以要這時就要做到資源獨立,一個應用一份資源,現在要做到這樣只有做成A2那樣,一個服務器上裝幾個虛擬機,一個虛擬機一個應用。這時如果你要重啟虛擬機,你想想你重啟電腦要多久。而且你想遷移應用的話,你就又要裝虛擬機,配環境等等,麻煩不?我是覺得麻煩。如果有了Docker,就是A3 的模式,容器是什么概念我就不說了,這時一個服務器上運行多個容器,一個容器擁有獨立的CPU、內存等資源,完全滿足了應用隔離的需求。而且容器重啟,1秒搞定!應用遷移的時候,這個大家應該也知道,所有裝了Docker的服務器,只需把鏡像pull或者load進去,run,一切OK,就是這么任性!
二,docker教程
基本概念

Docker是基于Go語言實現的云開源項目,誕生于2013年初,最初發起者是dotCloud公司,其目標是“Build, Ship and Run Any App, Anywhere”,主要概念包括鏡像、容器、倉庫。Docker引擎的技術是Linux容器(Linux Containers, LXC)技術。容器有效地將由單個操作系統的資源劃分到孤立的組中,以便更好地在孤立的組之間平衡有沖突的資源使用需求。
鏡像Image:類似于虛擬機鏡像,可以理解為面向Docker引擎的只讀模板,包括文件系統。
獲取鏡像:docker pull NAME[:TAG]
查看鏡像信息: 查看所有鏡像docker images
;查看某個鏡像具體信息docker inspect
添加標簽:?docker tag xxx ubuntu:first
搜尋鏡像:?docker search xxx
,?-s=0
指定星級
刪除鏡像:?docker rmi xxx
,一般情況下會刪除鏡像的標簽,而不是文件,當刪除最后一個TAG時則會刪除文件,需要注意。
使用鏡像ID刪除鏡像:?-f
刪除可以強制刪除鏡像,推薦做法為先刪除依賴該鏡像的所有容器,之后刪除鏡像,Qdocker rm e81
創建鏡像: 創建鏡像包括3種方式,基于已有鏡像的容器創建,首先啟動一個鏡像docker run -ti ubuntu:14.04 /bin/bash
,任意創建一個test文件,之后創建鏡像docker commit -m "add file" -a "xionger" a9fdsfxx test
;基于本地模板創建,推薦使用OpenVZ提供的模板來創建;基于Dockerfile創建。
存出鏡像和載入鏡像(導出、導入): 導出到本地文件sudo docker save -o ubuntu_14.04.tar ubuntu:14.04
,導入鏡像docker load --input ubuntu_14.04.tar
上傳鏡像:?docker push NAME[:TAG]
,默認上傳鏡像到DockerHub官方倉庫,需要登錄。

容器Container:類似一個輕量級的沙箱,可以利用容器來運行和隔離應用,容器從鏡像啟動時會在鏡像的最上層創建一個可寫層,鏡像本身保持不變。
創建容器:docker create -it ubuntu:lastest
,通過docker ps -a
查看容器,通過docker start
啟動容器
新建并啟動容器:docker run ubuntu /bin/bash
,-d
參數守護態運行,通過Ctrl+d或者exit退出容器
終止容器:docker stop xxx
,首先會發送SIGTERM信號,一段時候后發送SIGKILL,可以通過docker kill
強行中止,docker restart
可以關閉并重啟容器,docker ps -a -q
可以查看處于終止態的容器信息。
進入容器:docker attach xxx
會被阻塞不推薦使用;docker exec -ti xxx /bin/bash
可以直接在容器中運行命令;nsenter工具。
刪除容器:docker rm xxx
,需要注意區分,rmi
是刪除鏡像,rm
是刪除容器
導入和導出容器:docker export xxx
導出一個已經創建的容器到文件,不管是否在運行;docker import
,需要理解的是export
的是快照,信息少,而save
的是鏡像,信息多,包含元數據和歷史信息。
倉庫Repository:類似于代碼倉庫,是Docker存放鏡像的場所,而Registry注冊服務器是存放倉庫的地方,其上放著很多倉庫,每個倉庫集中存放某一類鏡像的多個文件,可以通過tag標簽來區分。目前最大的公有倉庫是Docker Hub,而國內是Docker Pool。
Docker Pub:本地用戶目錄.dockercfg中存儲登錄信息,在倉庫中存在centos這類由Docker公司創建、驗證、支持的根鏡像,也有類似xionger/centos這類由個人提供的鏡像,可以通過-s N
來查看高星鏡像。此外,Docker Hub還可以通過設置追蹤類似GitHub的網站,然后根據其更行,自動執行創建。
創建和使用私有倉庫:可以通過官方提供的registry
鏡像來簡單搭建一套本地私有倉庫環境。
docker?run?-d?-p?5000:5000?-v?/opt/data/registry:/tmp/registry?registry
docker?images
docker?tag?ubuntu:14.04?139.196.96.27:5000/test
docker?push?139.196.xx.xx:5000/test
curl?http://139.196.xx.xx:5000/v1/searchdocker?pull?139.196.xx.xx:5000/test
Tip:
CURL(CommandLine Uniform Resource Locator):curl是利用URL語法在命令行方式下工作的開源文件傳輸工具。
安裝Docker(Ubuntu16.04),默認安裝在/var/lib/docker
????sudo?apt-get?install?apt-transport-https
????sudo?apt-get?update
????sudo?apt-get?install?-y?docker.io
Tip:
在用putty連接阿里云時,經常會斷開,如何解決?
解決方法:在Connection里面有個Seconds between keepaliaves。這里就是每間隔指定的秒數,就給服務器發送一個空的數據包,來保持連接。以免登錄的主機那邊在長時間沒接到數據后,會自動斷開SSH的連接,設置為10。
阿里云購買ECS, 操作系統版本Ubuntu 16.04(LTS)
進階概念
數據管理:在使用docker過程中,會涉及查看容器內應用產生的數據,或者數據在多個容器間共享,此時需要管理數據的兩種方式包括數據卷Data Volumes和數據卷容器Data Volume Containers.
數據卷:是一個可供容器使用的特殊目錄,繞過文件系統,具有的特性包括數據卷可以在容器之間共享和重用、對數據卷的修改會馬上生效、對數據卷的更新不會影響鏡像、卷會一致存在,知道沒有容器使用,類似Linux下對目錄或文件進行mount操作。
在容器內創建一個數據卷:使用training/webapp
鏡像創建一個web容器,并創建一個數據卷掛在到容器的/webapp目錄,docker run -d -P --name web -v /webapp python app.py
。
掛載一個主機目錄作為數據卷:加載主機的/src/webapp
目錄到容器的/opt/webapp
目錄,docker run -d -P --name web - v /src/webapp:/opt/webapp training/webapp python app.py
。
Tip:編輯工具包括vi或者sed?--in-place,推薦掛載目錄而不是文件,因為inode變化會造成docker容器啟動失敗。
數據卷容器:其實就是一個普通的容器,其中會掛載數據卷用戶共享,創建數據庫容器dbdata,之后其他容器將掛載可以掛載該數據卷容器中的數據卷。
????docker?run?-it?-v?/dbdata?--name?dbdata?ubuntu
????ls
????docker?run?-it?--volumes-from?dbdata?--name?db1?ubuntu
利用數據卷容器遷移數據:可以通過數據卷容器對其中的數據卷進行備份、回復,以實現數據的遷移。接下來的示例利用ubuntu鏡像創建一個容器worker,使用--volumes-from dbdata
參數掛載dbdata容器的數據卷,
使用-v ${pwd}:/backup
參數來掛載本地的當前目錄到worker容器的/backup
目錄,
容器啟動后,使用tar cvf /backup/backup.tar /dbdata
來講/dbdata
下內容備份為容器內的/backup/backup.tar
。
????docker?run?--volumes-from?dbdata?-v?${pwd}:/backup?--name?worker?ubuntu?tar?cvf?/backup/backup.tar?/dbdata????//恢復,首先創建一個帶有數據卷的容器dbdata2,之后?創建另一個新的容器,掛載dbdata2容器,并使用untar解壓備份文件到所掛載的容器卷中即可
????docker?run?-v?/dbdata?--name?dbdata2?ubuntu?/bin/bash
????docker?run?--volumes-from?dbdata2?-v?${pwd}:/backup?busybox?tar?xvf?/backup/backup.tar
在生產環境,推薦使用分布式文件系統Ceph、GPFS、HDFS定期對主機的本地數據進行備份。
網絡基礎配置:
端口映射實現訪問容器:在啟動容器時,如果不指定對應參數,在容器外部是無法通過網絡來訪問容器內的網絡應用和服務的??梢允褂?code>-p ip:hostPort:containerPort映射端口,docker logs
查看應用的信息,docker port
查看端口配置。
????docker?run?-d?-p?5000:5000?-p?3000:80?training/webapp?python?app.py
容器互聯實現容器間通信:容器見的連接系統是除了端口映射外另一種可以與容器中應用進行交互的方式,它會在源和接受容器間創建一個隧道,接受容器可以看到源容器制定的信息,比如--link
連接應用容器和數據庫容器,這樣可以保證db的接口不暴露到公網。
????docker?run?-d?-P?--name?web?training/webapp?python?app.py
????docker?ps?-l
????docker?inspect?-f?xxx
????//容器互聯
????docker?run?-d?--name?db?training/postgres
????docker?rm?-f?web
????docker?run?-d?-P?--name?web?--link?db:db?training/webapp?python?app.py
????docker?ps
Docker通過兩種方式為容器公開連接信息,包括環境變量env
和/etc/hosts文件,通過apt-get install -yqq inetutils-ping
安裝ping。
擴展知識:Docker已有的實現PaaS的項目有Deis、Flynn等,持續集成方面有Drone,管理工具有Citadel, Shipyard, DockerUI等。
使用Dockerfile創建鏡像
基本結構:dockerfile由命令語句組成,支持#開頭的注釋,分為4個部分,包括基礎鏡像信息、維護者信息、鏡像操作指令和容器啟動執行指令,在docker hub上有很多dockerfile的demo,需要時可以直接使用。
????#基礎鏡像
????FROM?ubuntu???
????#維護者信息
????MAINTAINER?xionger?xiongere@email.com???
????#鏡像的操作指令
????RUN?apt-get?update?&&?apt-get?install?-y?nginx
????RUN?echo?"\ndaemon?off;"?>>?/etc/nginx/nginx.conf????
????#容器啟動時執行指令
????CMD?/usr/sbin/nginx
指令:一般格式為INSTRUCTION arguments,具體如下所示。
FROM?<image>:<tag>
默認的第一條指令
MAINTAINER?<name>
維護者信息
RUN?<command>
或者RUN?["executable", "param1", "param2"]
,前者將在shell終端中運行命令,即/bin/sh -c
,后者則使用exec
執行。
CMD?["executable", "param1", "param2"]
使用exec
執行,推薦方式。
EXPOSE?<port> [<port>..]
告訴Docker服務器容器暴露的端口號,供互聯網系統使用。
ENV?<key> <value>
指定一個環境變量,會被后續的RUN
指令使用
ADD?<src> <dest>
該命令將復制指定到容器中的
COPY?<src> <dest>
復制本地主機<src>
到容器中<dest>
,推薦使用
ENTRYPOINT?["executable", "param1", "param2"]
配置容器啟動后執行的命令,不能被docker run
提供的參數覆蓋
VOLUME?["/data"]
創建一個可以從本地主機或其他容器掛載的掛載點,一般用來存放數據庫和需要保持的數據。
USER?daemon
指定運行容器時的UID,后續的RUN
也會使用指定用戶,如RUN group add -r postgres && useradd -r -g postgres postgres
,要獲取管理員權限時可以使用gosu
而不是sudo
WORKDIR?path/to/workdir
為后續的指令配置工作目錄
ONBUILD?[INSTRUCTION]
配置當所創建的鏡像作為其他新創建鏡像的基礎鏡像時,所執行的操作指令。
創建鏡像:編寫好dockerfile后,可以通過docker build
命令來創建鏡像,該命令將讀取指定路徑下(包括子目錄)的dockerfile,并將該路徑下所有內容發送給docker服務端,由服務端來創建鏡像,此外可以通過.dockerignore
文件來忽略目錄或文件,還可以通過-t
指定鏡像的標簽信息。示例docker build -t build_repo/first_image /tmp/docker_builder/
實踐之道
操作系統:CentOS和Ubuntu都可以,個人喜好ubuntu(還可以選用debian:jessie, alpine),屬于最基礎的鏡像。
tip: 當試圖安裝軟件出現沒有相關包信息時,需要apt-get update
或編輯/etc/apt/sources.list
文件(deb, deb-src
,需要時在查詢,比如163的鏡像,阿里云的話無需設置),可以通過netstat -tunlp
查看當前網絡情況。
支持SSH:當需要直接進入容器進行管理時安裝,不必須。
Web服務器與應用(Nginx,可以使用淘寶優化的Tengine代替Nginx,Tomcat):在/usr/docker
下創建tomcat
,nginx
目錄應用存放Dockerfile文件,最終還是選擇通過pull拉去鏡像的方式安裝應用,dockerfile比較復雜。
????docker?pull?nginx:1.12
????docker?ps?-a????
??
????docker?run?--name?nginx01?-p?80:80?-v?$PWD/www:/www?-v?$PWD/conf:/etc/nginx?-v?$PWD/logs:/wwwlogs?-d?nginx:1.12
????docker?pull?tomcat:8.0
????docker?run?--name?tomcat01?-p?8080:8080?-v?$PWD/test:/usr/local/tomcat/webapps/test?-d?tomcat:8.0
tip:
有時可能需要重啟docker服務,?service docker restart
,可以選擇tomcat7.0:jdk1.8
數據庫應用MySQL(5.6), MongoDB(3.2), Redis(3.2)
docker?pull?mysql
docker?run?-p?3306:3306?--name?mysql01?-v?$PWD/conf:/etc/mysql?-v?$PWD/logs:/logs?-v?$PWD/data:/mysql_data?-e?MYSQL_ROOT_PASSWORD=123456?-d?mysql//主從模式docker?run?-p?3306:3306?--name?mysql01?-v?$PWD/conf01:/etc/mysql?-v?$PWD/logs01:/logs?-v?$PWD/data01:/mysql_data?-e?MYSQL_ROOT_PASSWORD=123456?-e?REPLICATION_MASTER=true?-d?mysql
docker?run?-p?3307:3306?--name?mysql02?-v?$PWD/conf02:/etc/mysql?-v?$PWD/logs02:/logs?-v?$PWD/data02:/mysql_data?-e?MYSQL_ROOT_PASSWORD=123456?-e?REPLICATION_SLAVE=true?--link?mysql01:mysql01?-d?mysql//mongodb,暫時單機,其默認提供集群的配置docker?pull?mongo:3.2docker?run?-p?27017:27017?-p?28017:28017?--name?mongodb01?-v?$PWD/db01:/data/db?-e?MONGODN_PASS="123456"?-d?mongo:3.2//redisdocker?pull??redis:3.2docker?run?-p?6379:6379?--name?redis01?-v?$PWD/data01:/data??-d?redis:3.2?redis-server?--appendonly?yes
tip:可以進入db的容器進行操作,docker exec -ti mysql /bin/bash
其他應用:maven, gitlab, jenkins, dubbo, cat,具體內容將在之后的文章中陸續介紹。
????docker?pull?jenkins:2.60.1
????docker?run?--name?jenkins01?-p?9090:8080?-p?9091:50000?-v?$PWD/jenkins01:/var/jenkins_home?-d?jenkins:2.60.1

構建Docker容器集群:核心問題就是讓不同主機中的Docker容器相互訪問,簡單的方式包括兩種。使用自定義網橋連接跨主機容器,Docker默認的網橋是docker0,可以通過brctl show
查看。使用Ambassador容器:當2個docker容器再同意主機時,可以通過--link相互訪問,如果需要跨主機實現,則需要知道其他物理主機的IP地址。
Docker CI集成方案:在之后的Jenkins一文中將重點分析。
Tip:
目前百度BAE已經在生產環境使用Docker,Airbnb,ebay已使用mesos集成docker部署應用,此外可以使用apparmor對容器的能力進行限制。
三,docker優點
? ?1、快速分發應用
Docker可以幫助你把控開發各個周期。Docker允許你在本地的開發環境中進行代碼開發,然后將開發好的應用整合到團隊的開發流程中。
比如:你可以再本地編寫代碼,當編寫完成后。你將代碼開發堆棧信息共享給團隊成員。當他們也編寫完成后,同樣共享開發堆棧信息。然后再測試環境中,使用團隊共享的開發堆棧就可以進行所需要的測試了。當完成測試后,團隊就可以將測試通過的docker鏡像(images)發布到產品環境中。
2、方便部署和易于管理
Docker基于容器的機制可以很容易進行部署。Docker容器可以在本地主機上面執行,也可以在虛擬機中執行,不論這些虛擬機是在本地或者云中。
Docker快速部署和輕量級的特性也使得管理負載變得很容易。你可以快速啟動或者銷毀容器。這種時間幾乎是實時的。
3、可以執行大量的工作負載
因為Docker具有便于部署和快速啟停的方式,同時docker也提供了可行的,符合效益-成本的虛擬機管理機制。使得docker很適合負載要求高的環境。比如:將你的云平臺作為PAAS用途時,或者你要求你的環境具有高資源使用率時。