技術之路

站在代碼以外看技術

Docker入門教程

作者: 阮一峰

日期: 2018年2月 9日

2013年宣布至今, Docker 壹向廣受註視,被以為能夠會轉變軟件行業。

然則,很多人其實不清晰 Docker 究竟是甚麽,要處理甚麽成績,利益又在哪裏?本文就來具體說明,贊助人人懂得它,還帶有簡略易懂的實例,教你若何將它用于平常開辟。

《Docker入門教程》

1、情況設置裝備擺設的困難

軟件開辟最大的費事事之一,就是情況設置裝備擺設。用戶盤算機的情況都不雷同,你怎樣曉得自家的軟件,能在那些機械跑起來?

用戶必需包管兩件事:操作體系的設置,各類庫和組件的裝置。只要它們都準確,軟件能力運轉。舉例來講,裝置一個 Python 運用,盤算機必需有 Python 引擎,還必需有各類依附,能夠還要設置裝備擺設情況變量。

假如某些老舊的模塊與以後情況不兼容,那就費事了。開辟者經常會說:”它在我的機械可以跑了”(It works on my machine),言下之意就是,其他機械極可能跑不了。

情況設置裝備擺設如斯費事,換一台機械,就要重來一次,曠日費時。許多人想到,能不克不及從基本上處理成績,軟件可以帶情況裝置?也就是說,裝置的時刻,把原始情況如出壹轍地複制過去。

2、虛擬機

虛擬機(virtual machine)就是帶情況裝置的一種處理計劃。它可以在一種操作體系外面運轉另外壹種操作體系,好比在 Windows 體系外面運轉 Linux 體系。運用法式對此毫無感知,由於虛擬機看上去跟真實體系如出壹轍,而關於底層體系來講,虛擬機就是一個通俗文件,不須要了就刪失落,對其他部門毫無影響。

固然用戶可以經由過程虛擬機復原軟件的原始情況。然則,這個計劃有幾個缺陷。

(1)資本占用多

虛擬機遇獨有一部門內存和硬盤空間。它運轉的時刻,其他法式就不克不及應用這些資本了。哪怕虛擬機外面的運用法式,真正應用的內存只要 1MB,虛擬機仍然須要幾百 MB 的內存能力運轉。

(2)冗余步調多

虛擬機是完全的操作體系,一些體系級其余操作步調,常常沒法跳過,好比用戶登錄。

(3)啓動慢

啓動操作體系須要多久,啓動虛擬機就須要多久。能夠要等幾分鍾,運用法式能力真正運轉。

3、Linux 容器

因為虛擬機存在這些缺陷,Linux 發展出了另外壹種虛擬化技術:Linux 容器(Linux Containers,縮寫爲 LXC)。

Linux 容器不是模仿一個完全的操作體系,而是對過程停止隔離。或許說,在正常過程的裏面套了一個掩護層。關於容器外面的過程來講,它接觸到的各類資本都是虛擬的,從而完成與底層體系的隔離。

因為容器是過程級其余,比擬虛擬機有許多優勢。

(1)啓動快

容器外面的運用,直接就是底層體系的一個過程,而不是虛擬機外部的過程。所以,啓動容器相當于啓動本機的一個過程,而不是啓動一個操作體系,速度就快許多。

(2)資本占用少

容器只占用須要的資本,不占用那些沒有效到的資本;虛擬機因為是完全的操作體系,弗成防止要占用壹切資本。別的,多個容器可以同享資本,虛擬機都是獨享資本。

(3)體積小

容器只需包括用到的組件便可,而虛擬機是全部操作體系的打包,所以容器文件比虛擬機文件要小許多。

總之,容器有點像輕量級的虛擬機,可以或許供給虛擬化的情況,然則本錢開支小很多。

4、Docker 是甚麽?

Docker 屬于 Linux 容器的一種封裝,供給簡略易用的容器應用接口。它是今朝最風行的 Linux 容器處理計劃。

Docker 將運用法式與該法式的依附,打包在一個文件外面。運轉這個文件,就會生成一個虛擬容器。法式在這個虛擬容器裏運轉,就似乎在真實的物理機上運轉一樣。有了 Docker,就不消擔憂情況成績。

整體來講,Docker 的接口相當簡略,用戶可以便利地創立和應用容器,把本身的運用放入容器。容器還可以停止版本治理、複制、分享、修正,就像治理通俗的代碼一樣。

5、Docker 的用處

Docker 的重要用處,今朝有三大類。

(1)供給一次性的情況。好比,當地測試別人的軟件、連續集成的時刻供給單位測試和構建的情況。

(2)供給彈性的雲辦事。由於 Docker 容器可以隨開隨關,很合適動態擴容和縮容。

(3)組建微辦事架構。經由過程多個容器,一台機械可以跑多個辦事,是以在本機就能夠模仿出微辦事架構。

6、Docker 的裝置

Docker 是一個開源的貿易産品,有兩個版本:社區版(Community Edition,縮寫爲 CE)和企業版(Enterprise Edition,縮寫爲 EE)。企業版包括了一些免費辦事,小我開辟者普通用不到。上面的引見都針對社區版。

Docker CE 的裝置請參考官方文檔。

裝置完成後,運轉上面的敕令,驗證能否裝置勝利。


$ docker version
# 或許
$ docker info

Docker 須要用戶具有 sudo 權限,為了不每次敕令都輸出sudo,可以把用戶參加 Docker 用戶組(官方文檔)。


$ sudo usermod -aG docker $USER

Docker 是辦事器—-客戶端架構。敕令交運行docker敕令的時刻,須要本機有 Docker 辦事。假如這項辦事沒有啓動,可以用上面的敕令啓動(官方文檔)。


# service 敕令的用法
$ sudo service docker start

# systemctl 敕令的用法
$ sudo systemctl start docker

6、image 文件

Docker 把運用法式及其依附,打包在 image 文件外面。只要經由過程這個文件,能力生成 Docker 容器。image 文件可以看做是容器的模板。Docker 依據 image 文件生成容器的實例。統壹個 image 文件,可以生成多個同時運轉的容器實例。

image 是二進制文件。現實開辟中,一個 image 文件常常經由過程繼續另外壹個 image 文件,加上一些特性化設置而生成。舉例來講,你可以在 Ubuntu 的 image 基本上,往外面參加 Apache 辦事器,構成你的 image。


# 列出本機的壹切 image 文件。
$ docker image ls

# 刪除 image 文件
$ docker image rm [imageName]

image 文件是通用的,一台機械的 image 文件拷貝到另外壹台機械,照樣可使用。普通來講,爲了節儉時光,我們應當盡可能應用他人制造好的 image 文件,而不是本身制造。即便要定制,也應當基于他人的 image 文件停止加工,而不是從零開端制造。

爲了便利同享,image 文件制造完成後,可以上傳到網上的倉庫。Docker 的官方倉庫 Docker Hub 是最主要、最經常使用的 image 倉庫。另外,出售本身制造的 image 文件也是可以的。

7、實例:hello world

上面,我們經由過程最簡略的 image 文件”hello world”,感觸感染一下 Docker。

須要解釋的是,國際銜接 Docker 的官方倉庫很慢,還會斷線,須要將默許倉庫改成國際的鏡像網站,詳細的修正辦法在下一篇文章的第一節。有須要的同夥,可以先看一下。

起首,運轉上面的敕令,將 image 文件從倉庫抓取到當地。


$ docker image pull library/hello-world

下面代碼中,docker image pull是抓取 image 文件的敕令。library/hello-world是 image 文件在倉庫外面的地位,個中library是 image 文件地點的組,hello-world是 image 文件的名字。

因為 Docker 官方供給的 image 文件,都放在library組外面,所以它的是默許組,可以省略。是以,下面的敕令可以寫成上面如許。


$ docker image pull hello-world

抓取勝利今後,就能夠在本機看到這個 image 文件了。


$ docker image ls

如今,運轉這個 image 文件。


$ docker container run hello-world

docker container run敕令會從 image 文件,生成一個正在運轉的容器實例。

留意,docker container run敕令具有主動抓取 image 文件的功效。假如發明當地沒有指定的 image 文件,就會從倉庫主動抓取。是以,後面的docker image pull敕令並非必須的步調。

假如運轉勝利,你會在屏幕上讀到上面的輸入。


$ docker container run hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.

... ...

輸入這段提醒今後,hello world就會停滯運轉,容器主動終止。

有些容器不會主動終止,由於供給的是辦事。好比,裝置運轉 Ubuntu 的 image,就能夠在敕令行體驗 Ubuntu 體系。


$ docker container run -it ubuntu bash

關於那些不會主動終止的容器,必需應用docker container kill 敕令手動終止。


$ docker container kill [containID]

8、容器文件

image 文件生成的容器實例,自己也是一個文件,稱爲容器文件。也就是說,一旦容器生成,就會同時存在兩個文件: image 文件和容器文件。並且封閉容器其實不會刪除容器文件,只是容器停滯運轉罷了。


# 列出本機正在運轉的容器
$ docker container ls

# 列出本機壹切容器,包含終止運轉的容器
$ docker container ls --all

下面敕令的輸入成果當中,包含容器的 ID。許多處所都須要供給這個 ID,好比上一節終止容器運轉的docker container kill敕令。

終止運轉的容器文件,仍然會占領硬盤空間,可使用docker container rm敕令刪除。


$ docker container rm [containerID]

運轉下面的敕令以後,再應用docker container ls --all敕令,就會發明被刪除的容器文件曾經消逝了。

9、Dockerfile 文件

學會應用 image 文件今後,接上去的成績就是,若何可以生成 image 文件?假如你要推行本身的軟件,必將要本身制造 image 文件。

這就須要用到 Dockerfile 文件。它是一個文本文件,用來設置裝備擺設 image。Docker 依據 該文件生成二進制的 image 文件。

上面經由過程一個實例,演示若何編寫 Dockerfile 文件。

10、實例:制造本身的 Docker 容器

上面我以 koa-demos 項目爲例,引見怎樣寫 Dockerfile 文件,完成讓用戶在 Docker 容器外面運轉 Koa 框架。

作爲預備任務,請先下載源碼


$ git clone https://github.com/ruanyf/koa-demos.git
$ cd koa-demos

10.1 編寫 Dockerfile 文件

起首,在項目標根目次下,新建一個文本文件.dockerignore,寫入上面的內容


.git
node_modules
npm-debug.log

下面代碼表現,這三個途徑要消除,不要打包進入 image 文件。假如你沒有途徑要消除,這個文件可以不新建。

然後,在項目標根目次下,新建一個文本文件 Dockerfile,寫入上面的內容


FROM node:8.4
COPY . /app
WORKDIR /app
RUN npm install --registry=https://registry.npm.taobao.org
EXPOSE 3000

下面代碼一共五行,寄義以下。

  • FROM node:8.4:該 image 文件繼續官方的 node image,冒號表現標簽,這裏標簽是8.4,即8.4版本的 node。
  • COPY . /app:將以後目次下的壹切文件(除.dockerignore消除的途徑),都拷貝進入 image 文件的/app目次。
  • WORKDIR /app:指定接上去的任務途徑爲/app
  • RUN npm install:在/app目次下,運轉npm install敕令裝置依附。留意,裝置後壹切的依附,都將打包進入 image 文件。
  • EXPOSE 3000:將容器 3000 端口裸露出來, 許可內部銜接這個端口。

10.2 創立 image 文件

有了 Dockerfile 文件今後,就能夠應用docker image build敕令創立 image 文件了。


$ docker image build -t koa-demo .
# 或許
$ docker image build -t koa-demo:0.0.1 .

下面代碼中,-t參數用來指定 image 文件的名字,前面還可以用冒號指定標簽。假如不指定,默許的標簽就是latest。最初的誰人點表現 Dockerfile 文件地點的途徑,上例是以後途徑,所所以一個點。

假如運轉勝利,就能夠看到重生成的 image 文件koa-demo了。


$ docker image ls

10.3 生成容器

docker container run敕令會從 image 文件生成容器。


$ docker container run -p 8000:3000 -it koa-demo /bin/bash
# 或許
$ docker container run -p 8000:3000 -it koa-demo:0.0.1 /bin/bash

下面敕令的各個參數寄義以下:

  • -p參數:容器的 3000 端口映照到本機的 8000 端口。
  • -it參數:容器的 Shell 映照到以後的 Shell,然後你在本機窗口輸出的敕令,就會傳入容器。
  • koa-demo:0.0.1:image 文件的名字(假如有標簽,還須要供給標簽,默許是 latest 標簽)。
  • /bin/bash:容器啓動今後,外部第一個履行的敕令。這裏是啓動 Bash,包管用戶可使用 Shell。

假如一切正常,運轉下面的敕令今後,就會前往一個敕令行提醒符。


1e:/app#

這表現你曾經在容器外面了,前往的提醒符就是容器外部的 Shell 提醒符。履行上面的敕令。


1e:/app# node demos/01.js

這時候,Koa 框架曾經運轉起來了。翻開本機的閱讀器,訪問 http://127.0.0.1:8000,網頁顯示”Not Found”,這是由於這個 demo 沒有寫路由。

這個例子中,Node 過程運轉在 Docker 容器的虛擬情況外面,過程接觸到的文件體系和網絡接口都是虛擬的,與本機的文件體系和網絡接口是隔離的,是以須要界說容器與物理機的端口映照(map)。

如今,在容器的敕令行,按下 Ctrl + c 停滯 Node 過程,然後按下 Ctrl + d (或許輸出 exit)加入容器。另外,也能夠用docker container kill終止容器運轉。


# 在本機的另外壹個終端窗口,查出容器的 ID
$ docker container ls

# 停滯指定的容器運轉
$ docker container kill [containerID]

容器停滯運轉以後,其實不會消逝,用上面的敕令刪除容器文件。


# 查出容器的 ID
$ docker container ls --all

# 刪除指定的容器文件
$ docker container rm [containerID]

也能夠應用docker container run敕令的--rm參數,在容器終止運轉後主動刪除容器文件。


$ docker container run --rm -p 8000:3000 -it koa-demo /bin/bash

10.4 CMD 敕令

上一節的例子外面,容器啓動今後,須要手動輸出敕令node demos/01.js。我們可以把這個敕令寫在 Dockerfile 外面,如許容器啓動今後,這個敕令就曾經履行了,不消再手動輸出了。


FROM node:8.4
COPY . /app
WORKDIR /app
RUN npm install --registry=https://registry.npm.taobao.org
EXPOSE 3000
CMD node demos/01.js

下面的 Dockerfile 外面,多了最初一行CMD node demos/01.js,它表現容器啓動後主動履行node demos/01.js

你能夠會問,RUN敕令與CMD敕令的差別在哪裏?簡略說,RUN敕令在 image 文件的構建階段履行,履行成果都邑打包進入 image 文件;CMD敕令則是在容器啓動後履行。別的,一個 Dockerfile 可以包括多個RUN敕令,然則只能有一個CMD敕令。

留意,指定了CMD敕令今後,docker container run敕令就不克不及附加敕令了(好比後面的/bin/bash),不然它會籠罩CMD敕令。如今,啓動容器可使用上面的敕令。


$ docker container run --rm -p 8000:3000 -it koa-demo:0.0.1

10.5 宣布 image 文件

容器運轉勝利後,就確認了 image 文件的有用性。這時候,我們就能夠斟酌把 image 文件分享到網上,讓其別人應用。

起首,去 hub.docker.com 或 cloud.docker.com 注冊一個賬戶。然後,用上面的敕令登錄。


$ docker login

接著,爲當地的 image 標注用戶名和版本。


$ docker image tag [imageName] [username]/[repository]:[tag]
# 實例
$ docker image tag koa-demos:0.0.1 ruanyf/koa-demos:0.0.1

也能夠不標注用戶名,從新構建一下 image 文件。


$ docker image build -t [username]/[repository]:[tag] .

最初,宣布 image 文件。


$ docker image push [username]/[repository]:[tag]

宣布勝利今後,登錄 hub.docker.com,就能夠看到曾經宣布的 image 文件。

11、其他有效的敕令

docker 的重要用法就是下面這些,另外還有幾個敕令,也異常有效。

(1)docker container start

後面的docker container run敕令是新建容器,每運轉一次,就會新建一個容器。異樣的敕令運轉兩次,就會生成兩個如出壹轍的容器文件。假如願望反復應用容器,就要應用docker container start敕令,它用來啓動曾經生成、曾經停滯運轉的容器文件。


$ docker container start [containerID]

(2)docker container stop

後面的docker container kill敕令終止容器運轉,相當于向容器外面的主過程收回 SIGKILL 旌旗燈號。而docker container stop敕令也是用來終止容器運轉,相當于向容器外面的主過程收回 SIGTERM 旌旗燈號,然後過一段時光再收回 SIGKILL 旌旗燈號。


$ bash container stop [containerID]

這兩個旌旗燈號的差異是,運用法式收到 SIGTERM 旌旗燈號今後,可以自行停止掃尾清算任務,但也能夠不睬會這個旌旗燈號。假如收到 SIGKILL 旌旗燈號,就會強行立刻終止,那些正在停止中的操作會全體喪失。

(3)docker container logs

docker container logs敕令用來檢查 docker 容器的輸入,即容器外面 Shell 的尺度輸入。假如docker run敕令運轉容器的時刻,沒有應用-it參數,就要用這個敕令檢查輸入。


$ docker container logs [containerID]

(4)docker container exec

docker container exec敕令用于進入一個正在運轉的 docker 容器。假如docker run敕令運轉容器的時刻,沒有應用-it參數,就要用這個敕令進入容器。一旦進入了容器,就能夠在容器的 Shell 履行敕令了。


$ docker container exec -it [containerID] /bin/bash

(5)docker container cp

docker container cp敕令用于從正在運轉的 Docker 容器外面,將文件拷貝到本機。上面是拷貝到以後目次的寫法。


$ docker container cp [containID]:[/path/to/file] .

異常感激你壹向讀到了這裏,這個系列還有下一篇,引見若何應用 Docker 搭建真實的網站,歡迎持續瀏覽

點贊

揭櫫評論

電子郵件地址不會被公開。 必填項已用*標注