Docker 入門指南

一、Docker的優點

1.簡化配置

虛擬機的最大好處是能在你的硬件設施上運行各種配置不一樣的平臺(軟件, 系統), Docker在降低額外開銷的情況下提供了同樣的功能. 它能讓你將運行環境和配置放在代碼彙總然後部署, 同一個Docker的配置可以在不同的環境環境中使用, 這樣就降低了硬件要求和應用環境之間耦合度.

2.代碼流水線管理

代碼從開發者的機器到最終在生產環境上的部署, 需要經過很多的中堅環境. 而每一箇中間環境都有自己微小的差別, Docker給應用提供了一個從開發到上線均一致的環境, 讓代碼的流水線變得簡單不少.

3.提升開發效率

不同環境中, 開發者的共同目標:

(1)想讓開發環境儘量貼近生產環境.

(2)想快速搭建開發環境

開發環境的機器通常內存比較小, 之前使用虛擬的時候, 我們經常需要為開發環境的機器加內存, 而現在Docker可以輕易的讓幾十個服務在Docker中跑起來.

4.隔離應用

開發時會在一個臺機器上運行不同的應用.

(1)為了降低成本, 進行服務器整合

(2)將一個整體式的應用拆分成低耦合的單個服務(微服務架構)

5.整合服務器

Docker隔離應用的能力使得Docker可以整合多個服務器以降低成本. 由於沒有多個操作系統的內存佔用, 以及能在多個實例之間共享沒有使用的內存, Docker可以比虛擬機提供更好的服務器整合解決方案.

6.調試能力

Docker提供了很多的工具, 這些工具不一定只是針對容器, 但是卻適用於容器. 他們提供了很多功能, 包括可以為容器設置檢查點, 設置版本, 查看兩個容器之間的差別, 這些特性可以幫助調試Bug.

7.多租戶環境

多租戶環境的應用中, 它可以避免關鍵應用的重寫.我們一個特別的關於這個場景的例子是為loT(物聯網)的應用開發一個快速, 易用的多租戶環境. 這種多租戶的基本代碼非常複雜, 很難處理, 重新規劃以應用不但消耗時間, 也浪費金錢.

使用Docker, 可以為每一個租戶的應用層的多個實例創建隔離的環境, 這不僅簡單而且成本低廉, 因為Docker環境啟動的速度快, diff命令很高效.

8.快速部署

Docker為進程創建一個容器, 不需要啟動一個操作系統, 時間縮短為秒級別.可以在數據中心創建銷燬資源而無須擔心重新啟動帶來的開銷. 通常數據中心的資源利用率只有30% , 通過使用Docker並進行有效的資源分配可以提高資源的利用率.


Docker 入門指南

Docker架構

二、虛擬機

虛擬機(virtual machine)就是帶環境安裝的一種解決方案。它可以在一種操作系統裡面運行另一種操作系統,比如在 Windows 系統裡面運行 Linux 系統。應用程序對此毫無感知,因為虛擬機看上去跟真實系統一模一樣,而對於底層系統來說,虛擬機就是一個普通文件,不需要了就刪掉,對其他部分毫無影響。

雖然用戶可以通過虛擬機還原軟件的原始環境。但是,這個方案有幾個缺點。

(1)資源佔用多

虛擬機會獨佔一部分內存和硬盤空間。它運行的時候,其他程序就不能使用這些資源了。哪怕虛擬機裡面的應用程序,真正使用的內存只有 1MB,虛擬機依然需要幾百 MB 的內存才能運行。

(2)冗餘步驟多

虛擬機是完整的操作系統,一些系統級別的操作步驟,往往無法跳過,比如用戶登錄。

(3)啟動慢

啟動操作系統需要多久,啟動虛擬機就需要多久。可能要等幾分鐘,應用程序才能真正運行。

三、Linux 容器

由於虛擬機存在這些缺點,Linux 發展出了另一種虛擬化技術:Linux 容器(Linux Containers,縮寫為 LXC)。

Linux 容器不是模擬一個完整的操作系統,而是對進程進行隔離。或者說,在正常進程的外面套了一個保護層。對於容器裡面的進程來說,它接觸到的各種資源都是虛擬的,從而實現與底層系統的隔離。

由於容器是進程級別的,相比虛擬機有很多優勢。

(1)啟動快

容器裡面的應用,直接就是底層系統的一個進程,而不是虛擬機內部的進程。所以,啟動容器相當於啟動本機的一個進程,而不是啟動一個操作系統,速度就快很多。

(2)資源佔用少

容器只佔用需要的資源,不佔用那些沒有用到的資源;虛擬機由於是完整的操作系統,不可避免要佔用所有資源。另外,多個容器可以共享資源,虛擬機都是獨享資源。

(3)體積小

容器只要包含用到的組件即可,而虛擬機是整個操作系統的打包,所以容器文件比虛擬機文件要小很多。

總之,容器有點像輕量級的虛擬機,能夠提供虛擬化的環境,但是成本開銷小得多。

四、Docker 是什麼?

Docker 屬於 Linux 容器的一種封裝,提供簡單易用的容器使用接口。它是目前最流行的 Linux 容器解決方案。

Docker 將應用程序與該程序的依賴,打包在一個文件裡面。運行這個文件,就會生成一個虛擬容器。程序在這個虛擬容器裡運行,就好像在真實的物理機上運行一樣。有了 Docker,就不用擔心環境問題。

總體來說,Docker 的接口相當簡單,用戶可以方便地創建和使用容器,把自己的應用放入容器。容器還可以進行版本管理、複製、分享、修改,就像管理普通的代碼一樣。

五、Docker 的用途

Docker 的主要用途,目前有三大類。

(1)提供一次性的環境。比如,本地測試他人的軟件、持續集成的時候提供單元測試和構建的環境。

(2)提供彈性的雲服務。因為 Docker 容器可以隨開隨關,很適合動態擴容和縮容。

(3)組建微服務架構。通過多個容器,一臺機器可以跑多個服務,因此在本機就可以模擬出微服務架構。

六、Docker 的安裝

Docker 是一個開源的商業產品,有兩個版本:社區版(Community Edition,縮寫為 CE)和企業版(Enterprise Edition,縮寫為 EE)。企業版包含了一些收費服務,個人開發者一般用不到。下面的介紹都針對社區版。

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

Mac

Windows

Ubuntu

Debian

CentOS

Fedora

· 首先卸載舊版本Docker

<code>$ sudo yum remove docker \\
docker-client \\
docker-client-latest \\
docker-common \\
docker-latest \\
docker-latest-logrotate \\
docker-logrotate \\
docker-engine/<code>

· 安裝需要的組件

<code>$ sudo yum install -y yum-utils \\
device-mapper-persistent-data \\
lvm2/<code>

· 添加Docker官方yum源

<code>$ sudo yum-config-manager \\
--add-repo \\
https://download.docker.com/linux/centos/docker-ce.repo/<code>

· 列出可用的docker-ce版本

<code>yum list docker-ce --showduplicates | sort -r

docker-ce.x86_64 3:18.09.1-3.el7 docker-ce-stable
docker-ce.x86_64 3:18.09.0-3.el7 docker-ce-stable
docker-ce.x86_64 18.06.1.ce-3.el7 docker-ce-stable
docker-ce.x86_64 18.06.0.ce-3.el7 docker-ce-stable/<code>

· 安裝選定版本的Docker

<code>sudo yum install docker-ce-<version> docker-ce-cli-<version> containerd.io/<version>/<version>/<code>

· 啟動docker

<code>sudo systemctl start docker/<code>

· 開啟開機自啟動

<code>sudo systemctl enable docker/<code>

其他 Linux 發行版

安裝完成後,運行下面的命令,驗證是否安裝成功。

<code>$ docker info/<code>

Docker 需要用戶具有 sudo 權限,為了避免每次命令都輸入sudo,可以把用戶加入 Docker 用戶組(官方文檔)。

<code>$ sudo usermod -aG docker $USER/<code>

Docker 是服務器----客戶端架構。命令行運行docker命令的時候,需要本機有 Docker 服務。如果這項服務沒有啟動,可以用下面的命令啟動(官方文檔)。

# service 命令的用法

<code>$ sudo service docker start
# systemctl 命令的用法
$ sudo systemctl start docker/<code>

七、image 文件

Docker 把應用程序及其依賴,打包在 image 文件裡面。只有通過這個文件,才能生成 Docker 容器。image 文件可以看作是容器的模板。Docker 根據 image 文件生成容器的實例。同一個 image 文件,可以生成多個同時運行的容器實例。

image 是二進制文件。實際開發中,一個 image 文件往往通過繼承另一個 image 文件,加上一些個性化設置而生成。舉例來說,你可以在 Ubuntu 的 image 基礎上,往裡面加入 Apache 服務器,形成你的 image。

# 列出本機的所有 image 文件。

<code>$ docker image/<code>

# 刪除 image 文件

<code>$ docker image rm [imageName]/<code>

image 文件是通用的,一臺機器的 image 文件拷貝到另一臺機器,照樣可以使用。一般來說,為了節省時間,我們應該儘量使用別人製作好的 image 文件,而不是自己製作。即使要定製,也應該基於別人的 image 文件進行加工,而不是從零開始製作。

為了方便共享,image 文件製作完成後,可以上傳到網上的倉庫。Docker 的官方倉庫 Docker Hub 是最重要、最常用的 image 倉庫。此外,出售自己製作的 image 文件也是可以的。

八、hello world實例

下面,我們通過最簡單的 image 文件"hello world",感受一下 Docker。

需要說明的是,國內連接 Docker 的官方倉庫很慢,還會斷線,需要將默認倉庫改成國內的鏡像網站,具體的修改方法在下一篇文章的第一節。有需要的朋友,可以先看一下。

首先,運行下面的命令,將 image 文件從倉庫抓取到本地。

<code>$ docker image pull library/hello-world/<code>

上面代碼中,docker image pull是抓取 image 文件的命令。library/hello-world是 image 文件在倉庫裡面的位置,其中library是 image 文件所在的組,hello-world是 image 文件的名字。

由於 Docker 官方提供的 image 文件,都放在library組裡面,所以它的是默認組,可以省略。因此,上面的命令可以寫成下面這樣。

<code>$ docker image pull hello-world/<code>

抓取成功以後,就可以在本機看到這個 image 文件了。

<code>$ docker image/<code>

現在,運行這個 image 文件。

<code>$ docker container run hello-world/<code>

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

注意,docker container run命令具有自動抓取 image 文件的功能。如果發現本地沒有指定的 image 文件,就會從倉庫自動抓取。因此,前面的docker image pull命令並不是必需的步驟。

如果運行成功,你會在屏幕上讀到下面的輸出。

<code>$ docker container run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
... .../<code>

輸出這段提示以後,hello world就會停止運行,容器自動終止。

有些容器不會自動終止,因為提供的是服務。比如,安裝運行 Ubuntu 的 image,就可以在命令行體驗 Ubuntu 系統。

<code>$ docker container run -it ubuntu bash/<code>

對於那些不會自動終止的容器,必須使用docker container kill 命令手動終止。

<code>$ docker container kill [containID]/<code>

九、容器文件

image 文件生成的容器實例,本身也是一個文件,稱為容器文件。也就是說,一旦容器生成,就會同時存在兩個文件: image 文件和容器文件。而且關閉容器並不會刪除容器文件,只是容器停止運行而已。

# 列出本機正在運行的容器

<code>$ docker container ls/<code>

# 列出本機所有容器,包括終止運行的容器

<code>$ docker container ls --all/<code>

上面命令的輸出結果之中,包括容器的 ID。很多地方都需要提供這個 ID,比如上一節終止容器運行的docker container kill命令。

終止運行的容器文件,依然會佔據硬盤空間,可以使用docker container rm命令刪除。

<code>$ docker container rm [containerID]/<code>

運行上面的命令之後,再使用docker container ls --all命令,就會發現被刪除的容器文件已經消失了。

十、Dockerfile 文件

學會使用 image 文件以後,接下來的問題就是,如何可以生成 image 文件?如果你要推廣自己的軟件,勢必要自己製作 image 文件。

這就需要用到 Dockerfile 文件。它是一個文本文件,用來配置 image。Docker 根據 該文件生成二進制的 image 文件。

下面通過一個實例,演示如何編寫 Dockerfile 文件。

<code>[root@localhost docker]# cat Dockerfile/<code>
<code># base image
FROM centos
# MAINTAINER
MAINTAINER [email protected]
# put nginx-1.14.2.tar.gz into /usr/local/src and unpack nginx
ADD http://nginx.org/download/nginx-1.14.2.tar.gz /usr/local/src
# running required command
RUN yum install -y gcc gcc-c++ glibc make autoconf openssl openssl-devel
RUN yum install -y libxslt-devel -y gd gd-devel GeoIP GeoIP-devel pcre pcre-devel
RUN useradd -M -s /sbin/nologin nginx
# change dir to /usr/local/src/nginx-1.14.2
WORKDIR /usr/local/src/nginx-1.14.2
# execute command to compile nginx
RUN ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-file-aio  --with-http_ssl_module  --with-http_realip_module    --with-http_addition_module    --with-http_xslt_module   --with-http_image_filter_module    --with-http_geoip_module  --with-http_sub_module  --with-http_dav_module --with-http_flv_module    --with-http_mp4_module --with-http_gunzip_module  --with-http_gzip_static_module  --with-http_auth_request_module  --with-http_random_index_module   --with-http_secure_link_module   --with-http_degradation_module   --with-http_stub_status_module && make && make install
 EXPOSE 80 443/<code>

十一、實例:製作自己的 Docker 容器

下面我以 koa-demos 項目為例,介紹怎麼寫 Dockerfile 文件,實現讓用戶在 Docker 容器裡面運行 Koa 框架。

作為準備工作,請先下載源碼。

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

11.1 編寫 Dockerfile 文件

首先,在項目的根目錄下,新建一個文本文件.dockerignore,寫入下面的內容。

<code>.git
node_modules
npm-debug.log
*.log/<code>

上面代碼表示,這三個路徑要排除,不要打包進入 image 文件。如果你沒有路徑要排除,這個文件可以不新建。

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

<code>FROM node:lts
COPY . /app
WORKDIR /app
RUN npm install --registry=https://registry.npm.taobao.org
EXPOSE 5000/<code>

上面代碼一共五行,含義如下。

FROM node:lts:該 image 文件繼承官方的 node image,冒號表示標籤,這裡標籤是lts,即lts版本的 node。

COPY . /app:將當前目錄下的所有文件(除了.dockerignore排除的路徑),都拷貝進入 image 文件的/app目錄。

WORKDIR /app:指定接下來的工作路徑為/app。

RUN npm install:在/app目錄下,運行npm install命令安裝依賴。注意,安裝後所有的依賴,都將打包進入 image 文件。

EXPOSE 5000:將容器 5000 端口暴露出來, 允許外部連接這個端口。

11.2 創建 image 文件

有了 Dockerfile 文件以後,就可以使用docker image build命令創建 image 文件了。

<code>$ docker image build -t koa-demo ./
# 或者
$ docker image build -t koa-demo:0.0.1 .//<code>

上面代碼中,-t參數用來指定 image 文件的名字,後面還可以用冒號指定標籤。如果不指定,默認的標籤就是latest。最後的那個點表示 Dockerfile 文件所在的路徑,上例是當前路徑,所以是一個點。

如果運行成功,就可以看到新生成的 image 文件koa-demo了。

<code>$ docker image ls/<code>

11.3 生成容器

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

<code>$ docker container run -p 8000:5000 -it koa-demo /bin/bash/<code>

# 或者

<code>$ docker container run -p 8000:5000 -it koa-demo:0.0.1 /bin/bash/<code>

上面命令的各個參數含義如下:

-p參數:容器的 5000 端口映射到本機的 8000 端口。

-it參數:容器的 Shell 映射到當前的 Shell,然後你在本機窗口輸入的命令,就會傳入容器。

koa-demo:0.0.1:image 文件的名字(如果有標籤,還需要提供標籤,默認是 latest 標籤)。

/bin/bash:容器啟動以後,內部第一個執行的命令。這裡是啟動 Bash,保證用戶可以使用 Shell。

如果一切正常,運行上面的命令以後,就會返回一個命令行提示符。

<code>root@12d80f4aaf1e:/app#/<code>

這表示你已經在容器裡面了,返回的提示符就是容器內部的 Shell 提示符。執行下面的命令。

<code>root@12d80f4aaf1e:/app# node demos/01.js/<code>

這時,Koa 框架已經運行起來了。打開本機的瀏覽器,訪問 http://127.0.0.1:8000,網頁顯示"Not Found",這是因為這個 demo 沒有寫路由。

這個例子中,Node 進程運行在 Docker 容器的虛擬環境裡面,進程接觸到的文件系統和網絡接口都是虛擬的,與本機的文件系統和網絡接口是隔離的,因此需要定義容器與物理機的端口映射(map)。

現在,在容器的命令行,按下 Ctrl + c 停止 Node 進程,然後按下 Ctrl + d (或者輸入 exit)退出容器。此外,也可以用docker container kill終止容器運行。

# 在本機的另一個終端窗口,查出容器的 ID

<code>$ docker container ls/<code>

# 停止指定的容器運行

<code>$ docker container kill [containerID]/<code>

容器停止運行之後,並不會消失,用下面的命令刪除容器文件。

# 查出容器的 ID

<code>$ docker container ls --all/<code>

# 刪除指定的容器文件

<code>$ docker container rm [containerID]/<code>

也可以使用docker container run命令的--rm參數,在容器終止運行後自動刪除容器文件。

<code>$ docker container run --rm -p 8000:5000 -it koa-demo /bin/bash/<code>

11.4 CMD 命令

上一節的例子裡面,容器啟動以後,需要手動輸入命令node demos/01.js。我們可以把這個命令寫在 Dockerfile 裡面,這樣容器啟動以後,這個命令就已經執行了,不用再手動輸入了。

<code>FROM node:lts
COPY . /app
WORKDIR /app
RUN npm install --registry=https://registry.npm.taobao.org
EXPOSE 5000
CMD node demos/01.js/<code>

上面的 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命令。現在,啟動容器可以使用下面的命令。

<code>$ docker container run --rm -p 8000:5000 -it koa-demo:0.0.1/<code>

11.5 推送 image到鏡像倉庫

容器運行成功後,就確認了 image 文件的有效性。這時,我們就可以考慮把 image 文件分享到網上,讓其他人使用。

首先,去 hub.docker.com 或 cloud.docker.com 註冊一個賬戶。然後,用下面的命令登錄。

<code>$ docker login/<code>

接著,為本地的 image 標註用戶名和版本。

<code>$ docker image tag [imageName] [username]/[repository]:[tag]/<code>

# 實例

<code>$ docker image tag koa-demos:0.0.1 test/koa-demos:0.0.1/<code>

也可以不標註用戶名,重新構建一下 image 文件。

<code>$ docker container run --rm -p 8000:5000 -it koa-demo:0.0.1/<code>

最後,發佈 image 文件。

<code>$ docker image push [username]/[repository]:[tag]/<code>

發佈成功以後,登錄 hub.docker.com,就可以看到已經發布的 image 文件。

11.6 減少鏡像層數

只有 RUN, COPY, ADD 會創建層數, 其它指令不會增加鏡像的體積

儘可能使用多階段構建

使用以下方法安裝依賴:

<code>$ docker login/<code>

錯誤的方法安裝依賴,這將增加鏡像層數:

<code>$ docker image tag [imageName] [username]/[repository]:[tag]/<code>

將多行參數排序

便於可讀性以及不小心地重複裝包。

<code>$ docker image tag koa-demos:0.0.1 test/koa-demos:0.0.1/<code>

充分利用構建緩存

在鏡像的構建過程中 Docker 會遍歷 Dockerfile 文件中的所有指令,順序執行。對於每一條指令,Docker 都會在緩存中查找是否已存在可重用的鏡像,否則會創建一個新的鏡像。

我們可以使用 docker build --no-cache 跳過緩存:

ADD 和 COPY 將會計算文件的 checksum 是否改變來決定是否利用緩存

RUN 僅僅查看命令字符串是否命中緩存,如 RUN apt-get -y update 可能會有問題

如一個 Node 應用,可以先拷貝 package.json 進行依賴安裝,然後再添加整個目錄,可以做到充分利用緩存的目的。

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

# 此步將可以充分利用 node_modules 的緩存

<code>$ docker image push [username]/[repository]:[tag]/<code>

十二、其他命令

docker 的主要用法就是上面這些,此外還有幾個命令,也非常有用。

<code>(1)docker container start/<code>

前面的docker container run命令是新建容器,每運行一次,就會新建一個容器。同樣的命令運行兩次,就會生成兩個一模一樣的容器文件。如果希望重複使用容器,就要使用docker container start命令,它用來啟動已經生成、已經停止運行的容器文件。

$ docker container start [containerID]

<code>(2)docker container stop/<code>

前面的docker container kill命令終止容器運行,相當於向容器裡面的主進程發出 SIGKILL 信號。而docker container stop命令也是用來終止容器運行,相當於向容器裡面的主進程發出 SIGTERM 信號,然後過一段時間再發出 SIGKILL 信號。

<code>RUN yum install -y node python go/<code>

這兩個信號的差別是,應用程序收到 SIGTERM 信號以後,可以自行進行收尾清理工作,但也可以不理會這個信號。如果收到 SIGKILL 信號,就會強行立即終止,那些正在進行中的操作會全部丟失。

<code>RUN yum install -y node
RUN yum install -y python
RUN yum install -y go/<code>

docker container logs命令用來查看 docker 容器的輸出,即容器裡面 Shell 的標準輸出。如果docker run命令運行容器的時候,沒有使用-it參數,就要用這個命令查看輸出。

$ docker container logs [containerID]

<code>RUN apt-get update && apt-get install -y \\
bzr \\
cvs \\
git \\
mercurial \\
subversion/<code>

docker container exec命令用於進入一個正在運行的 docker 容器。如果docker run命令運行容器的時候,沒有使用-it參數,就要用這個命令進入容器。一旦進入了容器,就可以在容器的 Shell 執行命令了。

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

<code>(5)docker container cp/<code>

docker container cp命令用於從正在運行的 Docker 容器裡面,將文件拷貝到本機。下面是拷貝到當前目錄的寫法。

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

十二、常用的Docker命令

容器生命週期管理

<code>run
start/stop/restart
kill
rm
pause/unpause
create
exec/<code>

容器操作

<code>FROM node:10-alpine as builder
WORKDIR /code
ADD package.json /code/<code>

容器rootfs命令

<code>RUN npm install --production
ADD . /code
RUN npm run build/<code>

鏡一倉庫

<code>login
pull
push
search/<code>

本地鏡像管理

<code>(1)docker container start/<code>



參考鏈接:https://docs.docker.com/


分享到:


相關文章: