Docker是一個基於輕量級虛擬化技術的容器,整個項目基於Go語言開發,並採用了Apache 2.0協議。Docker能夠將咱們的應用程序打包封裝到一個容器中,該容器包含了應用程序的代碼、運行環境、依賴庫、配置文件等必需的資源,經過容器就能夠實現方便快速而且與平臺解耦的自動化部署方式,不管你部署時的環境如何,容器中的應用程序都會運行在同一種環境下。python
舉個栗子,小明寫了一個CMS系統,該系統的技術棧很是廣,須要依賴於各類開源庫和中間件。若是按照純手動的部署方式,小明須要安裝各類開源軟件,還須要寫好每一個開源軟件的配置文件。若是隻是部署一次,這點時間開銷仍是能夠接受的,但若是小明每隔幾天就須要換個服務器去部署他的程序,那麼這些繁瑣的重複工做無疑是會使人發狂的。這時候,Docker的用處就派上場了,小明只須要根據應用程序的部署步驟編寫一份Dockerfile文件(將安裝、配置等操做交由Docker自動化處理),而後構建併發布他的鏡像,這樣,無論在什麼機器上,小明都只須要拉取他須要的鏡像,而後就能夠直接部署運行了,這正是Docker的魅力所在。git
那麼鏡像又是什麼呢?鏡像是Docker中的一個重要概念:github
Image(鏡像):它相似於虛擬機中使用到的鏡像,因爲任何應用程序都須要有它本身的運行環境,Image就是用來提供所需運行環境的一個模板。redis
Container(容器):Container是Docker提供的一個抽象層,它就像一個輕量級的沙盒,其中包含了一個極簡的Linux系統環境與運行在其中的應用程序。Container是Image的運行實例(Image自己是隻讀的,Container啓動時,Docker會在Image的上層建立一個可寫層,任何在Container中的修改都不會影響到Image,若是想要在Image保存Container中的修改,Docker採用了基於Container生成新的Image層的策略),Docker引擎利用Container來操做並隔離每一個應用(也就是說,每一個容器中的應用都是互相獨立的)。docker
其實從Docker與Container的英文單詞原意中就能夠體會出Docker的思想。Container能夠釋義爲集裝箱,集裝箱是一個能夠便於機械設備裝卸的封裝貨物的通用標準規格,它的發明簡化了物流運輸的機械化過程,使其創建起了一套標準化的物流運輸體系。而Docker的意思爲碼頭工人,能夠認爲,Docker就像是在碼頭上辛勤工做的工人,把應用打包成一個個具備某種標準化規格的"集裝箱"(其實這裏指出的集裝箱對應的是Image,在Docker中Container更像是一個運行中的沙盒),當貨物運輸到目的地後,碼頭工人們(Docker)就能夠把集裝箱拆開取出其中的貨物(基於Image來建立Container並運行)。這種標準化與隔離性能夠很方便地組合使用多個Image來構建你的應用環境(Docker也提倡每一個Image都遵循單一職責原則,也就是隻作好一件事),或者與其餘人共享你的Image。shell
本文做者爲SylvanasSun(sylvanas.sun@gmail.com),首發於SylvanasSun’s Blog。
原文連接:sylvanassun.github.io/2017/11/19/…
(轉載請務必保留本段聲明,而且保留超連接。)bash
在上文中咱們提到了Docker是基於輕量級虛擬化技術的,因此它與咱們日常使用的虛擬機是不同的。虛擬機技術能夠分紅如下兩類:服務器
系統虛擬機:經過軟件對計算機系統的模擬來提供一個真實計算機的替代品。它是物理硬件的抽象並提供了運行完整操做系統所需的功能。虛擬機經過物理機器來管理和共享硬件,這樣實現了多個虛擬機環境彼此之間的隔離,一臺機器上能夠運行多個虛擬機,每一個虛擬機包括一個操做系統的完整副本。在系統虛擬機中,所運行的全部軟件或操做都只會影響到該虛擬機的環境。咱們常用的VMWare就是系統虛擬機的實現。併發
程序虛擬機:容許程序獨立運行在平臺以外。比較典型的例子就是JVM,Java經過JVM這一抽象層使得Java程序與操做系統和硬件平臺解耦(由於每一個Java程序都是運行在JVM中的),所以實現了所謂的compile once, run everywhere。app
Docker所用到的技術與上述兩種都不相同,它使用了更輕量級的虛擬化技術,多個Container共享了同一個操做系統內核,而且就像運行在本地上同樣。Container技術相對於虛擬機來講,只是一個應用程序層的抽象,它將代碼與依賴關係打包到一塊兒,多個Container能夠在同一臺機器上運行(意味着一個虛擬機上也能夠運行多個Container),並與其它Container共享操做系統內核,每個Container都在用戶空間中做爲一個獨立的進程運行,這些特性都證實了Container要比虛擬機更加靈活與輕量(通常都是結合虛擬機與Docker一塊兒使用)。
Container技術其實並非個新鮮事物,最先能夠追溯到UNIX中的chroot(在1979年的V7 Unix中引入),它能夠改變當前正在運行的進程及其子目錄的根目錄,在這種修改過的環境下運行的程序不能在指定的目錄樹以外訪問文件,從而限制用戶的活動範圍,爲進程提供了隔離空間。
以後各類Unix版本涌現出不少Container技術,在2006年,Google提出了"Process Containers"指望在Linux內核中實現進程資源隔離的相關特性,因爲Container在Linux內核中的定義過於寬泛混亂,後來該項目更名爲CGroups(Control Groups),實現了對進程的資源限制。
2008年,LXC(Linux Containers)發佈,它是一種在操做系統層級上的虛擬化方法,用於在Linux系統上經過共享一個內核來運行多個互相隔離的程序(Container)。LXC正是結合了Linux內核中的CGroups和對分離的名稱空間的支持來爲應用程序提供了一個隔離的環境。而Docker也是基於LXC實現的(Docker的前身是dotClound公司中的內部項目,它是一家提供PaaS服務的公司。),並做出了許多改進。
在使用Docker以前你須要先安裝Docker(這好像是一句廢話。。。),根據不一樣的平臺安裝方法都不相同,能夠去參考Install Docker | Docker Documentation或者自行Google。
安裝完畢以後,輸入docker --version
來確認是否安裝成功。
$ docker --version
Docker version 17.05.0-ce-rc1, build 2878a85複製代碼
從Docker Hub中能夠pull到其餘人發佈的Image,咱們也能夠註冊一個帳號去發佈本身的Image與他人共享。
[root@Jack ~]# docker search redis # 查看redis鏡像是否存在
[root@Jack ~]# docker pull redis # 拉取redis鏡像到本機
Using default tag: latest
Trying to pull repository docker.io/library/redis ...
latest: Pulling from docker.io/library/redis
Digest: sha256:cd277716dbff2c0211c8366687d275d2b53112fecbf9d6c86e9853edb0900956
[root@Jack ~]# docker images # 查看鏡像信息
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/python 3.6-onbuild 7195f9298ffb 2 weeks ago 691.1 MB
docker.io/mongo latest d22888af0ce0 2 weeks ago 360.9 MB
docker.io/redis latest 8f2e175b3bd1 2 weeks ago 106.6 MB複製代碼
有了Image,以後就能夠在其之上運行一個Container了,命令以下。
[root@Jack ~]# docker run -d -p 6379:6379 redis # 運行redis,-p表明將本機上6379端口映射到Container的6379端口 -d表明在後臺啓動
[root@Jack ~]# docker ps -a # 查看容器信息,若是不加-a只會顯示當前運行中的容器
# 若是想要進入容器中,那麼須要執行如下命令
[root@Jack ~]# docker ps # 先得到容器的id
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1f928073b7eb redis "docker-entrypoint.sh" 45 seconds ago Up 44 seconds 0.0.0.0:6379->6379/tcp desperate_khorana
[root@Jack ~]# docker exec -it 1f928073b7eb /bin/bash # 而後再執行該命令進入到容器中
root@1f928073b7eb:/data# touch hello_docker.txt # 在容器中建立一個文件
root@1f928073b7eb:/data# exit # 退出
exit
[root@Jack ~]#
# 也能夠在啓動時直接進入 命令以下
[root@Jack ~]# docker run -d -it -p 6379:6379 redis /bin/bash複製代碼
咱們對Container作出了修改,若是想要保留這個修改,能夠經過commit命令來生成一個新的Image。
# -m爲描述信息 -a爲做者 1f9是你要保存的容器id 取前3個字符 docker能夠自行識別
# sylvanassun/redis爲鏡像名 :test 爲一個tag 通常用於標識版本
[root@Jack ~]# docker commit -m "test" -a "SylvanasSun" 1f9 sylvanassun/redis:test
sha256:e7073e8e5bd70b8d58092fd6bd8c2551e65dd29241c235eddf2a7f4b4b25cbbd
[root@Jack ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
sylvanassun/redis test e7073e8e5bd7 2 seconds ago 106.6 MB
docker.io/python 3.6-onbuild 7195f9298ffb 2 weeks ago 691.1 MB
docker.io/mongo latest d22888af0ce0 2 weeks ago 360.9 MB
docker.io/redis latest 8f2e175b3bd1 2 weeks ago 106.6 MB複製代碼
想刪除一個容器或鏡像也很簡單,但在刪除鏡像前須要先刪除依賴於它的容器。
[root@Jack ~]# docker stop 1f9 # 關閉運行中的容器,相應的也有docker start id命令來啓動一個容器
1f9
[root@Jack ~]# docker rm 1f9 # 刪除容器
1f9
[root@Jack ~]# docker rmi e70 # 刪除上面保存的鏡像
Untagged: sylvanassun/redis:test
Deleted: sha256:e7073e8e5bd70b8d58092fd6bd8c2551e65dd29241c235eddf2a7f4b4b25cbbd
Deleted: sha256:751db4a870e5f703082b31c1614a19c86e0c967334a61f5d22b2511072aef56d複製代碼
若是想要本身構建一個鏡像,那麼須要編寫Dockerfile文件,該文件描述了鏡像的依賴環境以及如何配置你的應用環境。
# 使用python:2.7-slim 做爲父鏡像
FROM python:2.7-slim
# 跳轉到/app 其實就是cd命令
WORKDIR /app
# 將當前目錄的內容(.)複製到鏡像的/app目錄下
ADD . /app
# RUN表明運行的shell命令,下面這條命令是根據requirements.txt安裝python應用的依賴包
RUN pip install --trusted-host pypi.python.org -r requirements.txt
# 暴露80端口讓外界訪問
EXPOSE 80
# 定義環境變量
ENV NAME World
# 當容器啓動時執行的命令,它與RUN不一樣,只在容器啓動時執行一次
CMD ["python", "app.py"]複製代碼
而後就能夠經過docker build -t xxx/xxxx .
命令來構建鏡像,-t
後面是鏡像名與tag等信息,注意.
表示在當前目錄下尋找Dockerfile文件。
學會如何構建本身的鏡像以後,你是否也想將它發佈到Docker Hub上與他人分享呢?要想作到這一點,須要先註冊一個Docker Hub帳號,以後經過docker login
命令登陸,而後再docker push image name
,就像在使用Git同樣簡單。
關於Docker的更多命令與使用方法,請參考Docker Documentation | Docker Documentation,另外我還推薦使用Docker Compose來構建鏡像,它能夠很方便地組合管理多個鏡像。
Docker提供了很是強大的自動化部署方式與靈活性,對多個應用程序之間作到了解耦,提供了開發上的敏捷性、可控性以及可移植性。同時,Docker也在不斷地幫助愈來愈多的企業實現了向雲端遷移、向微服務轉型以及向DevOps模式的實踐。
現在,微服務與DevOps火爆程度日益漸高,你又有何理由選擇拒絕Docker呢?讓咱們一塊兒選擇擁抱Docker,擁抱將來!