在計算機技術突飛猛進的今天, Docker
在國內發展的如火如荼,特別是在一線互聯網公司, Docker
的使用是十分廣泛的,甚至成爲了一些企業面試的加分項,不信的話看看下面這張圖。html
這是我在某招聘網站上看到的招聘 Java開發工程師 的招聘要求,其中有一條熟悉 docker
成爲了你快速入職的加分項,因而可知熟悉 docker
在互聯網公司的地位之重要。python
固然對於咱們 CTF選手 而言,熟悉 docker
能夠快速搭建 CTF環境
,完美地還原比賽真實漏洞的場景,幫助咱們快速提高本身。linux
市面上已經有不少優秀的教程,可是不少原理性的東西,筆者認爲那些教程對初學者而言仍是很難理解,感受沒有說清楚(筆者本身都以爲挺懵逼的),爲了讓初學者少走彎路,我將以個人學習經歷以及做爲一個 CTF選手 的角度,編寫此套教程,來帶你們去了解並熟練運用 docker
,祝願各位讀者朋友們學完此套教程後,在將來企業面試中可以多一項加分的籌碼,可以幫助到你們,我以爲就很值了。nginx
既然說了這麼多, docker
究竟是個什麼東西呢?git
咱們在理解 docker
以前,首先咱們得先區分清楚兩個概念,容器和虛擬機。github
可能不少讀者朋友都用過虛擬機,而對容器這個概念比較的陌生。web
咱們用的傳統虛擬機如 VMware
, VisualBox
之類的須要模擬整臺機器包括硬件,每臺虛擬機都須要有本身的操做系統,虛擬機一旦被開啓,預分配給它的資源將所有被佔用。每一臺虛擬機包括應用,必要的二進制和庫,以及一個完整的用戶操做系統。面試
而容器技術是和咱們的宿主機共享硬件資源及操做系統,能夠實現資源的動態分配。容器包含應用和其全部的依賴包,可是與其餘容器共享內核。容器在宿主機操做系統中,在用戶空間以分離的進程運行。sql
容器技術是實現操做系統虛擬化的一種途徑,可讓您在資源受到隔離的進程中運行應用程序及其依賴關係。經過使用容器,咱們能夠輕鬆打包應用程序的代碼、配置和依賴關係,將其變成容易使用的構建塊,從而實現環境一致性、運營效率、開發人員生產力和版本控制等諸多目標。容器能夠幫助保證應用程序快速、可靠、一致地部署,其間不受部署環境的影響。容器還賦予咱們對資源更多的精細化控制能力,讓咱們的基礎設施效率更高。經過下面這幅圖咱們能夠很直觀的反映出這二者的區別所在。docker
Docker 屬於 Linux 容器的一種封裝,提供簡單易用的容器使用接口。它是目前最流行的 Linux
容器解決方案。
而 Linux
容器是 Linux
發展出了另外一種虛擬化技術,簡單來說, Linux
容器不是模擬一個完整的操做系統,而是對進程進行隔離,至關因而在正常進程的外面套了一個保護層。對於容器裏面的進程來講,它接觸到的各類資源都是虛擬的,從而實現與底層系統的隔離。
Docker
將應用程序與該程序的依賴,打包在一個文件裏面。運行這個文件,就會生成一個虛擬容器。程序在這個虛擬容器裏運行,就好像在真實的物理機上運行同樣。有了 Docker
,就不用擔憂環境問題。
整體來講, Docker
的接口至關簡單,用戶能夠方便地建立和使用容器,把本身的應用放入容器。容器還能夠進行版本管理、複製、分享、修改,就像管理普通的代碼同樣。
Docker相比於傳統虛擬化方式具備更多的優點:
docker
啓動快速屬於秒級別。虛擬機一般須要幾分鐘去啓動docker
須要的資源更少, docker
在操做系統級別進行虛擬化, docker
容器和內核交互,幾乎沒有性能損耗,性能優於經過 Hypervisor
層與內核層的虛擬化docker
更輕量, docker
的架構能夠共用一個內核與共享應用程序庫,所佔內存極小。一樣的硬件環境, Docker
運行的鏡像數遠多於虛擬機數量,對系統的利用率很是高docker
隔離性更弱, docker
屬於進程之間的隔離,虛擬機可實現系統級別隔離docker
的安全性也更弱。 Docker
的租戶 root
和宿主機 root
等同,一旦容器內的用戶從普通用戶權限提高爲root權限,它就直接具有了宿主機的root權限,進而可進行無限制的操做。虛擬機租戶 root
權限和宿主機的 root
虛擬機權限是分離的,而且虛擬機利用如 Intel
的 VT-d
和 VT-x
的 ring-1
硬件隔離技術,這種隔離技術能夠防止虛擬機突破和彼此交互,而容器至今尚未任何形式的硬件隔離,這使得容器容易受到攻擊docker
的集中化管理工具還不算成熟。各類虛擬化技術都有成熟的管理工具,例如 VMware vCenter
提供完備的虛擬機管理能力docker
對業務的高可用支持是經過快速從新部署實現的。虛擬化具有負載均衡,高可用,容錯,遷移和數據保護等通過生產實踐檢驗的成熟保障機制, VMware
可承諾虛擬機 99.999%
高可用,保證業務連續性Docker
容器建立是秒級別的, Docker
的快速迭代性,決定了不管是開發、測試、部署均可以節約大量時間Docker
在 Dockerfile
中記錄了容器構建過程,可在集羣中實現快速分發和快速部署咱們能夠從下面這張表格很清楚地看到容器相比於傳統虛擬機的特性的優點所在:
特性 | 容器 | 虛擬機 |
---|---|---|
啓動 | 秒級 | 分鐘級 |
硬盤使用 | 通常爲MB | 通常爲GB |
性能 | 接近原生 | 弱於 |
系統支持量 | 單機支持上千個容器 | 通常是幾十個 |
從上圖咱們能夠看到,Docker
中包括三個基本的概念:
Image
(鏡像)Container
(容器)Repository
(倉庫)鏡像是 Docker
運行容器的前提,倉庫是存放鏡像的場所,可見鏡像更是 Docker
的核心。
那麼鏡像究竟是什麼呢?
Docker
鏡像能夠看做是一個特殊的文件系統,除了提供容器運行時所需的程序、庫、資源、配置等文件外,還包含了一些爲運行時準備的一些配置參數(如匿名卷、環境變量、用戶等)。鏡像不包含任何動態數據,其內容在構建以後也不會被改變。
鏡像(Image)
就是一堆只讀層(read-only layer)
的統一視角,也許這個定義有些難以理解,下面的這張圖可以幫助讀者理解鏡像的定義。
從左邊咱們看到了多個只讀層,它們重疊在一塊兒。除了最下面一層,其它層都會有一個指針指向下一層。這些層是Docker
內部的實現細節,而且可以在主機的文件系統上訪問到。統一文件系統 (union file system)
技術可以將不一樣的層整合成一個文件系統,爲這些層提供了一個統一的視角,這樣就隱藏了多層的存在,在用戶的角度看來,只存在一個文件系統。咱們能夠在圖片的右邊看到這個視角的形式。
容器 (container)
的定義和鏡像 (image)
幾乎如出一轍,也是一堆層的統一視角,惟一區別在於容器的最上面那一層是可讀可寫的。
因爲容器的定義並無說起是否要運行容器,因此實際上,容器 = 鏡像 + 讀寫層。
Docker
倉庫是集中存放鏡像文件的場所。鏡像構建完成後,能夠很容易的在當前宿主上運行,可是, 若是須要在其它服務器上使用這個鏡像,咱們就須要一個集中的存儲、分發鏡像的服務,Docker Registry
(倉庫註冊服務器)就是這樣的服務。有時候會把倉庫 (Repository)
和倉庫註冊服務器 (Registry)
混爲一談,並不嚴格區分。Docker
倉庫的概念跟 Git
相似,註冊服務器能夠理解爲 GitHub
這樣的託管服務。實際上,一個 Docker Registry
中能夠包含多個倉庫 (Repository)
,每一個倉庫能夠包含多個標籤 (Tag)
,每一個標籤對應着一個鏡像。因此說,鏡像倉庫是 Docker
用來集中存放鏡像文件的地方相似於咱們以前經常使用的代碼倉庫。
一般,一個倉庫會包含同一個軟件不一樣版本的鏡像,而標籤就經常使用於對應該軟件的各個版本 。咱們能夠經過<倉庫名>:<標籤>
的格式來指定具體是這個軟件哪一個版本的鏡像。若是不給出標籤,將以 latest
做爲默認標籤.。
倉庫又能夠分爲兩種形式:
public
(公有倉庫)private
(私有倉庫)Docker Registry
公有倉庫是開放給用戶使用、容許用戶管理鏡像的 Registry
服務。通常這類公開服務容許用戶免費上傳、下載公開的鏡像,並可能提供收費服務供用戶管理私有鏡像。
除了使用公開服務外,用戶還能夠在本地搭建私有 Docker Registry
。Docker
官方提供了 Docker Registry
鏡像,能夠直接使用作爲私有 Registry
服務。當用戶建立了本身的鏡像以後就可使用 push
命令將它上傳到公有或者私有倉庫,這樣下次在另一臺機器上使用這個鏡像時候,只須要從倉庫上 pull
下來就能夠了。
咱們主要把 Docker
的一些常見概念如 Image
, Container
, Repository
作了詳細的闡述,也從傳統虛擬化方式的角度闡述了 docker
的優點,咱們從下圖能夠直觀地看到 Docker
的架構:
Docker
使用 C/S
結構,即客戶端/服務器體系結構。 Docker
客戶端與 Docker
服務器進行交互,Docker服務端負責構建、運行和分發 Docker
鏡像。 Docker
客戶端和服務端能夠運行在一臺機器上,也能夠經過 RESTful
、 stock
或網絡接口與遠程 Docker
服務端進行通訊。
這張圖展現了 Docker
客戶端、服務端和 Docker
倉庫(即 Docker Hub
和 Docker Cloud
),默認狀況下Docker
會在 Docker
中央倉庫尋找鏡像文件,這種利用倉庫管理鏡像的設計理念相似於 Git
,固然這個倉庫是能夠經過修改配置來指定的,甚至咱們能夠建立咱們本身的私有倉庫。
Docker
的安裝和使用有一些前提條件,主要體如今體系架構和內核的支持上。對於體系架構,除了 Docker
一開始就支持的 X86-64
,其餘體系架構的支持則一直在不斷地完善和推動中。
Docker
分爲 CE
和 EE
兩大版本。 CE
即社區版(免費,支持週期 7
個月), EE
即企業版,強調安全,付費使用,支持週期 24
個月。
咱們在安裝前能夠參看官方文檔獲取最新的 Docker
支持狀況,官方文檔在這裏:
https://docs.docker.com/install/
Docker
對於內核支持的功能,即內核的配置選項也有必定的要求(好比必須開啓 Cgroup
和 Namespace
相關選項,以及其餘的網絡和存儲驅動等), Docker
源碼中提供了一個檢測腳原本檢測和指導內核的配置,腳本連接在這裏:
https://raw.githubusercontent.com/docker/docker/master/contrib/check-config.sh
在知足前提條件後,安裝就變得很是的簡單了。
Docker CE
的安裝請參考官方文檔:
MacOS
:https://docs.docker.com/docker-for-mac/install/Windows
:https://docs.docker.com/docker-for-windows/install/Ubuntu
:https://docs.docker.com/install/linux/docker-ce/ubuntu/Debian
:https://docs.docker.com/install/linux/docker-ce/debian/CentOS
:https://docs.docker.com/install/linux/docker-ce/centos/Fedora
:https://docs.docker.com/install/linux/docker-ce/fedora/Linux
發行版:https://docs.docker.com/install/linux/docker-ce/binaries/這裏咱們以 CentOS7
做爲本文的演示。
因爲 Docker-CE
支持 64
位版本的 CentOS7
,而且要求內核版本不低於 3.10
首先咱們須要卸載掉舊版本的 Docker
$ sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-selinux \ docker-engine-selinux \ docker-engine
咱們執行如下安裝命令去安裝依賴包:
$ sudo yum install -y yum-utils \ device-mapper-persistent-data \ lvm2
這裏我事先已經安裝過了,因此提示我已經安裝了最新版本
安裝Docker
Docker
軟件包已經包括在默認的 CentOS-Extras
軟件源裏。所以想要安裝 docker
,只須要運行下面的 yum
命令
$ sudo yum install docker
固然在測試或開發環境中 Docker
官方爲了簡化安裝流程,提供了一套便捷的安裝腳本,CentOS
系統上可使用這套腳本安裝:
curl -fsSL get.docker.com -o get-docker.sh sh get-docker.sh
具體能夠參看 docker-install
的腳本:
https://github.com/docker/docker-install
執行這個命令後,腳本就會自動的將一切準備工做作好,而且把 Docker CE
的 Edge
版本安裝在系統中。
安裝完成後,運行下面的命令,驗證是否安裝成功:
docker version or docker info
返回docker的版本相關信息,證實 docker
安裝成功
啓動Docker-CE
$ sudo systemctl enable docker $ sudo systemctl start docker
因爲服務器平常崩潰了, docker
出了點問題,因此如下案例的演示是基於 Kali Linux
環境下進行的。
咱們經過最簡單的 image
文件 hello world
,感覺一下 Docker
的魅力吧!
咱們直接運行下面的命令,將名爲 hello-world
的 image
文件從倉庫抓取到本地。
docker pull library/hello-world
docker pull images
是抓取 image
文件, library/hello-world
是 image
文件在倉庫裏面的位置,其中 library
是 image
文件所在的組, hello-world
是 image
文件的名字。
抓取成功之後,就能夠在本機看到這個 image
文件了。
docker images
咱們能夠看到以下結果:
如今,咱們能夠運行 hello-world
這個 image
文件
docker run hello-world
咱們能夠看到以下結果:
輸出這段提示之後,hello world
就會中止運行,容器自動終止。有些容器不會自動終止,由於提供的是服務,好比Mysql鏡像等。
是否是很 easy
呢?咱們從上面能夠看出, docker
的功能是十分強大的,除此以外,咱們還能夠拉去一些 Ubuntu
, Apache
等鏡像,在將來的教程中咱們將會一一提到。
Docker
提供了一套簡單實用的命令來建立和更新鏡像,咱們能夠經過網絡直接下載一個已經建立好了的應用鏡像,並經過 Docker RUN
命令就能夠直接使用。當鏡像經過 RUN
命令運行成功後,這個運行的鏡像就是一個 Docker
容器啦,容器能夠理解爲一個輕量級的沙箱, Docker
利用容器來運行和隔離應用,容器是能夠被啓動、中止、刪除的,這並不會影響 Docker
鏡像。
咱們能夠看看下面這幅圖:
Docker
客戶端是 Docker
用戶與 Docker
交互的主要方式。當您使用 docker
命令行運行命令時, Docker
客戶端將這些命令發送給服務器端,服務端將執行這些命令。 docker
命令使用 docker API
。 Docker
客戶端能夠與多個服務端進行通訊。
咱們將剖析一下 Docker
容器是如何工做的,學習好Docker容器工做的原理,咱們就能夠本身去管理咱們的容器了。
在上面的學習中,咱們簡單地講解了Docker的基本架構。瞭解到了Docker
使用的是 C/S
結構,即客戶端/服務器體系結構。明白了 Docker
客戶端與 Docker
服務器進行交互時, Docker
服務端負責構建、運行和分發 Docker
鏡像。 也知道了Docker
客戶端和服務端能夠運行在一臺機器上,能夠經過 RESTful
、 stock
或網絡接口與遠程 Docker
服務端進行通訊。
咱們從下圖能夠很直觀的瞭解到Docker的架構:
Docker
的核心組件包括:
Docker
採用的是 Client/Server
架構。客戶端向服務器發送請求,服務器負責構建、運行和分發容器。客戶端和服務器能夠運行在同一個 Host
上,客戶端也能夠經過 socket
或 REST API
與遠程的服務器通訊。可能不少朋友暫時不太理解一些東西,好比 REST API
是什麼東西等,不過不要緊,在後面的文章中會一一給你們講解清楚。
Docker Client
,也稱 Docker
客戶端。它其實就是 Docker
提供命令行界面 (CLI)
工具,是許多 Docker
用戶與 Docker
進行交互的主要方式。客戶端能夠構建,運行和中止應用程序,還能夠遠程與Docker_Host
進行交互。最經常使用的 Docker
客戶端就是 docker
命令,咱們能夠經過 docker
命令很方便地在 host
上構建和運行 docker
容器。
Docker daemon
是服務器組件,以 Linux
後臺服務的方式運行,是 Docker
最核心的後臺進程,咱們也把它稱爲守護進程。它負責響應來自 Docker Client
的請求,而後將這些請求翻譯成系統調用完成容器管理操做。該進程會在後臺啓動一個 API Server
,負責接收由 Docker Client
發送的請求,接收到的請求將經過Docker daemon
內部的一個路由分發調度,由具體的函數來執行請求。
咱們大體能夠將其分爲如下三部分:
Docker Daemon的架構以下所示:
Docker Daemon
能夠認爲是經過 Docker Server
模塊接受 Docker Client
的請求,並在 Engine
中處理請求,而後根據請求類型,建立出指定的 Job
並運行。 Docker Daemon
運行在 Docker host
上,負責建立、運行、監控容器,構建、存儲鏡像。
運行過程的做用有如下幾種可能:
Docker Registry
獲取鏡像graphdriver
執行容器鏡像的本地化操做networkdriver
執行容器網絡環境的配置execdriver
執行容器內部運行的執行工做因爲 Docker Daemon
和 Docker Client
的啓動都是經過可執行文件 docker
來完成的,所以二者的啓動流程很是類似。 Docker
可執行文件運行時,運行代碼經過不一樣的命令行 flag
參數,區分二者,並最終運行二者各自相應的部分。
啓動 Docker Daemon
時,通常可使用如下命令來完成
docker --daemon = true docker –d docker –d = true
再由 docker
的 main()
函數來解析以上命令的相應 flag
參數,並最終完成 Docker Daemon
的啓動。
下圖能夠很直觀地看到 Docker Daemon
的啓動流程:
默認配置下, Docker daemon
只能響應來自本地 Host
的客戶端請求。若是要容許遠程客戶端請求,須要在配置文件中打開 TCP
監聽。咱們能夠照着以下步驟進行配置:
一、編輯配置文件 /etc/systemd/system/multi-user.target.wants/docker.service
,在環境變量 ExecStart
後面添加 -H tcp://0.0.0.0
,容許來自任意 IP 的客戶端鏈接。
二、重啓 Docker daemon
systemctl daemon-reload systemctl restart docker.service
三、咱們經過如下命令便可實現與遠程服務器通訊
docker -H 服務器IP地址 info
-H
是用來指定服務器主機, info
子命令用於查看 Docker
服務器的信息
Docker
鏡像能夠看做是一個特殊的文件系統,除了提供容器運行時所需的程序、庫、資源、配置等文件外,還包含了一些爲運行時準備的一些配置參數(如匿名卷、環境變量、用戶等)。鏡像不包含任何動態數據,其內容在構建以後也不會被改變。咱們可將 Docker
鏡像當作只讀模板,經過它能夠建立 Docker
容器。
鏡像有多種生成方法:
咱們能夠將鏡像的內容和建立步驟描述在一個文本文件中,這個文件被稱做 Dockerfile
,經過執行 docker build <docker-file>
命令能夠構建出 Docker 鏡像,在後續的教程中,咱們會用一篇專門討論這個問題。
Docker registry
是存儲 docker image
的倉庫,它在 docker
生態環境中的位置以下圖所示:
運行docker push
、docker pull
、docker search
時,其實是經過 docker daemon
與 docker registry
通訊。
Docker
容器就是 Docker
鏡像的運行實例,是真正運行項目程序、消耗系統資源、提供服務的地方。 Docker Container
提供了系統硬件環境,咱們可使用 Docker Images
這些製做好的系統盤,再加上咱們所編寫好的項目代碼, run
一下就能夠提供服務啦。
看到這裏,我相信各位讀者朋友們應該已經對Docker基礎架構已經熟悉的差很少了,咱們還記得運行的第一個容器嗎?如今咱們再經過hello-world這個例子來體會一下 Docker
各個組件是如何協做的。
容器啓動過程以下:
Docker
客戶端執行 docker run
命令Docker daemon
發現本地沒有 hello-world
鏡像daemon
從 Docker Hub
下載鏡像hello-world
被保存到本地Docker daemon
啓動容器具體過程能夠看以下這幅演示圖:
咱們能夠經過docker images
能夠查看到 hello-world
已經下載到本地
咱們能夠經過docker ps
或者 docker container ls
顯示正在運行的容器,咱們能夠看到, hello-world
在輸出提示信息之後就會中止運行,容器自動終止,因此咱們在查看的時候沒有發現有容器在運行。
咱們把 Docker
容器的工做流程剖析的十分清楚了,咱們大致能夠知道 Docker
組件協做運行容器能夠分爲如下幾個過程:
Docker
客戶端執行 docker run
命令Docker daemon
發現本地沒有咱們須要的鏡像daemon
從 Docker Hub
下載鏡像Docker daemon
啓動容器瞭解了這些過程之後,咱們再來理解這些命令就不會以爲很突兀了,下面我來給你們講講 Docker
經常使用的一些命令操做吧。
咱們能夠經過 docker -h
去查看命令的詳細的幫助文檔。在這裏我只會講一些日常平常比賽或者生活中咱們可能會用的比較多的一些命令。
例如,咱們須要拉取一個 docker
鏡像,咱們能夠用以下命令:
docker pull image_name
image_name
爲鏡像的名稱,而若是咱們想從 Docker Hub
上去下載某個鏡像,咱們可使用如下命令:
docker pull centos:latest
centos:lastest
是鏡像的名稱, Docker daemon
發現本地沒有咱們須要的鏡像,會自動去 Docker Hub
上去下載鏡像,下載完成後,該鏡像被默認保存到 /var/lib/docker
目錄下。
接着咱們若是想查看下主機下存在多少鏡像,咱們能夠用以下命令:
docker images
咱們要想知道當前有哪些容器在運行,咱們能夠用以下命令:
docker ps -a
-a
是查看當前全部的容器,包括未運行的
咱們該如何去對一個容器進行啓動,重啓和中止呢?咱們能夠用以下命令:
docker start container_name/container_id docker restart container_name/container_id docker stop container_name/container_id
這個時候咱們若是想進入到這個容器中,咱們可使用 attach
命令:
docker attach container_name/container_id
那若是咱們想運行這個容器中的鏡像的話,而且調用鏡像裏面的 bash
,咱們可使用以下命令:
docker run -t -i container_name/container_id /bin/bash
那若是這個時候,咱們想刪除指定鏡像的話,因爲 image
被某個 container
引用(拿來運行),若是不將這個引用的 container
銷燬(刪除),那 image
確定是不能被刪除。咱們首先得先去中止這個容器:
docker ps docker stop container_name/container_id
而後咱們用以下命令去刪除這個容器:
docker rm container_name/container_id
而後這個時候咱們再去刪除這個鏡像:
docker rmi image_name
此時,經常使用的 Docker
相關的命令就講到這裏爲止了,咱們在後續的文章中還會反覆地提到這些命令。
前面咱們已經提到了 Docker
的一些基本概念。以 CTF
選手的角度來看,咱們能夠去使用 Dockerfile
定義鏡像,依賴鏡像來運行容器,能夠去模擬出一個真實的漏洞場景。所以毫無疑問的說, Dockerfile
是鏡像和容器的關鍵,而且 Dockerfile
還能夠很輕易的去定義鏡像內容,說了這麼多,那麼 Dockerfile
究竟是個什麼東西呢?
Dockerfile
是自動構建 docker
鏡像的配置文件, 用戶可使用 Dockerfile
快速建立自定義的鏡像。Dockerfile
中的命令很是相似於 linux
下的 shell
命令。
咱們能夠經過下面這幅圖來直觀地感覺下 Docker 鏡像、容器和 Dockerfile 三者之間的關係。
咱們從上圖中能夠看到, Dockerfile
能夠自定義鏡像,經過 Docker
命令去運行鏡像,從而達到啓動容器的目的。
Dockerfile
是由一行行命令語句組成,而且支持已 #
開頭的註釋行。
通常來講,咱們能夠將 Dockerfile
分爲四個部分:
FROM
MAINTAINER
RUN
、 EVN
、 ADD
和 WORKDIR
等CMD
、 ENTRYPOINT
和 USER
等下面是一段簡單的Dockerfile的例子:
FROM python:2.7 MAINTAINER Angel_Kitty <angelkitty6698@gmail.com> COPY . /app WORKDIR /app RUN pip install -r requirements.txt EXPOSE 5000 ENTRYPOINT ["python"] CMD ["app.py"]
咱們能夠分析一下上面這個過程:
Docker Hub
上 pull
下 python 2.7
的基礎鏡像copy
當前目錄到容器中的 /app
目錄下 複製本地主機的 <src>
( Dockerfile
所在目錄的相對路徑)到容器裏 <dest>
/app
5000
端口app
這個例子是啓動一個 python flask app
的 Dockerfile
( flask
是 python
的一個輕量的 web
框架),相信你們從這個例子中可以稍微理解了Dockfile的組成以及指令的編寫過程。
根據上面的例子,咱們已經差很少知道了Dockerfile的組成以及指令的編寫過程,咱們再來理解一下這些經常使用命令就會駕輕就熟了。
因爲 Dockerfile
中全部的命令都是如下格式:INSTRUCTION argument
,指令 (INSTRUCTION)
不分大小寫,可是推薦大寫,和sql語句是否是很類似呢?下面咱們正式來說解一下這些指令集吧。
FROM
是用於指定基礎的 images
,通常格式爲 FROM <image>
or FORM <image>:<tag>
,全部的 Dockerfile
都用該以 FROM
開頭,FROM
命令指明 Dockerfile
所建立的鏡像文件以什麼鏡像爲基礎,FROM
之後的全部指令都會在 FROM
的基礎上進行建立鏡像。能夠在同一個 Dockerfile
中屢次使用 FROM
命令用於建立多個鏡像。好比咱們要指定 python 2.7
的基礎鏡像,咱們能夠像以下寫法同樣:
FROM python:2.7
MAINTAINER 是用於指定鏡像建立者和聯繫方式,通常格式爲 MAINTAINER <name>
。這裏我設置成個人 ID
和郵箱:
MAINTAINER Angel_Kitty <angelkitty6698@gmail.com>
COPY
是用於複製本地主機的 <src>
(爲 Dockerfile 所在目錄的相對路徑)到容器中的 <dest>
。
當使用本地目錄爲源目錄時,推薦使用 COPY
。通常格式爲 COPY <src><dest>
。例如咱們要拷貝當前目錄到容器中的 /app
目錄下,咱們能夠這樣操做:
COPY . /app
WORKDIR
用於配合 RUN
,CMD
,ENTRYPOINT
命令設置當前工做路徑。能夠設置屢次,若是是相對路徑,則相對前一個 WORKDIR
命令。默認路徑爲/
。通常格式爲 WORKDIR /path/to/work/dir
。例如咱們設置/app
路徑,咱們能夠進行以下操做:
WORKDIR /app
RUN
用於容器內部執行命令。每一個 RUN
命令至關於在原有的鏡像基礎上添加了一個改動層,原有的鏡像不會有變化。通常格式爲 RUN <command>
。例如咱們要安裝 python
依賴包,咱們作法以下:
RUN pip install -r requirements.txt
EXPOSE
命令用來指定對外開放的端口。通常格式爲 EXPOSE <port> [<port>...]
例如上面那個例子,開放5000端口:
EXPOSE 5000
ENTRYPOINT
可讓你的容器表現得像一個可執行程序同樣。一個 Dockerfile
中只能有一個 ENTRYPOINT
,若是有多個,則最後一個生效。
ENTRYPOINT
命令也有兩種格式:
ENTRYPOINT ["executable", "param1", "param2"]
:推薦使用的 exec
形式ENTRYPOINT command param1 param2
:shell
形式例以下面這個,咱們要將 python
鏡像變成可執行的程序,咱們能夠這樣去作:
ENTRYPOINT ["python"]
CMD
命令用於啓動容器時默認執行的命令,CMD
命令能夠包含可執行文件,也能夠不包含可執行文件。不包含可執行文件的狀況下就要用 ENTRYPOINT
指定一個,而後 CMD
命令的參數就會做爲ENTRYPOINT
的參數。
CMD
命令有三種格式:
CMD ["executable","param1","param2"]
:推薦使用的 exec
形式。CMD ["param1","param2"]
:無可執行程序形式CMD command param1 param2
:shell 形式。一個 Dockerfile
中只能有一個CMD
,若是有多個,則最後一個生效。而 CMD
的 shell
形式默認調用 /bin/sh -c
執行命令。
CMD
命令會被 Docker
命令行傳入的參數覆蓋:docker run busybox /bin/echo Hello
Docker
會把 CMD
裏的命令覆蓋。
例如咱們要啓動 /app
,咱們能夠用以下命令實現:
CMD ["app.py"]
固然還有一些其餘的命令,咱們在用到的時候再去一一講解一下。
咱們大致已經把Dockerfile的寫法講述完畢,咱們能夠本身動手寫一個例子:
mkdir static_web cd static_web touch Dockerfile 而後 vi Dockerfile 開始編輯該文件 輸入 i 開始編輯 如下是咱們構建的Dockerfile內容 `````````` FROM nginx MAINTAINER Angel_Kitty <angelkitty6698@gmail.com> RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html `````````` 編輯完後 按 esc 退出編輯 而後 :wq 寫入 退出
咱們在 Dockerfile
文件所在目錄執行:
docker build -t angelkitty/nginx_web:v1 .
咱們解釋一下, -t
是爲新鏡像設置倉庫和名稱,其中 angelkitty
爲倉庫名, nginx_web
爲鏡像名, :v1
爲標籤(不添加爲默認 latest
)
咱們構建完成以後,使用 docker images
命令查看全部鏡像,若是存在 REPOSITORY
爲 nginx
和 TAG
是 v1
的信息,就表示構建成功。
接下來使用 docker run
命令來啓動容器
docker run --name nginx_web -d -p 8080:80 angelkitty/nginx_web:v1
這條命令會用 nginx 鏡像啓動一個容器,命名爲 nginx_web
,而且映射了 8080 端口,這樣咱們能夠用瀏覽器去訪問這個 nginx
服務器:http://localhost:8080/
或者 http://本機的IP地址:8080/,頁面返回信息:
這樣一個簡單使用 Dockerfile
構建鏡像,運行容器的示例就完成了!
做 者:Angel_Kitty
出 處:https://www.cnblogs.com/ECJTUACM-873284962/
關於做者:阿里雲ACE,目前主要研究方向是Web安全漏洞以及反序列化。若有問題或建議,請多多賜教!
版權聲明:本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文連接。
特此聲明:全部評論和私信都會在第一時間回覆。也歡迎園子的大大們指正錯誤,共同進步。或者直接私信我
聲援博主:若是您以爲文章對您有幫助,能夠點擊文章右下角【推薦】一下。您的鼓勵是做者堅持原創和持續寫做的最大動力!