Docker
的英文翻譯是「搬運工」的意思,他搬運的東西就是咱們常說的集裝箱Container
,Container 裏面裝的是任意類型的 App,咱們的開發人員能夠經過 Docker 將App 變成一種標準化的、可移植的、自管理的組件,咱們能夠在任何主流的操做系統中開發、調試和運行。php
從概念上來看 Docker 和咱們傳統的虛擬機比較相似,只是更加輕量級,更加方便使,Docker 和虛擬機最主要的區別有如下幾點:html
應用容器是個啥樣子呢,一個作好的應用容器長得就像一個裝好了一組特定應用的虛擬機同樣,好比我如今想用 Redis,那我就找個裝好了 Redis 的容器就能夠了,而後運行起來,我就能直接使用了。node
那爲何不能直接安裝一個 Redis 呢?確定是可行的,可是有的時候根據每一個人電腦的不一樣,在安裝的時候可能會報出各類各樣的錯誤,萬一你的機器中毒了,你的電腦掛了,你全部的服務都須要從新安裝。可是有了 Docker 或者說有了容器就不同了,你就至關於有了一個能夠運行起來的虛擬機,只要你能運行容器,Redis 的配置就省了。並且若是你想換個電腦,沒問題,很簡單,直接把容器」端過來」就可使用容器裏面的服務了。python
Docker Engine
是一個C/S架構的應用程序,主要包含下面幾個組件:mysql
Dockerd
CLI
接口,經過和 REST API 進行交互(咱們常用的 docker 命令)
Docker 使用 C/S (客戶端/服務器)體系的架構,Docker 客戶端與 Docker 守護進程通訊,Docker 守護進程負責構建,運行和分發 Docker 容器。Docker 客戶端和守護進程能夠在同一個系統上運行,也能夠將 Docker 客戶端鏈接到遠程 Docker 守護進程。Docker 客戶端和守護進程使用 REST API 經過UNIX
套接字或網絡接口進行通訊。 linux
直接前往官方文檔選擇合適的平臺安裝便可,好比咱們這裏想要在centos
系統上安裝 Docker,這前往地址https://docs.docker.com/install/linux/docker-ce/centos/根據提示安裝便可。nginx
安裝依賴軟件包:git
$ sudo yum install -y yum-utils device-mapper-persistent-data lvm2
添加軟件倉庫,咱們這裏使用穩定版 Docker,執行下面命令添加 yum 倉庫地址:golang
$ sudo yum-config-manager \ --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo
而後直接安裝便可:web
$ sudo yum install docker-ce
若是要安裝指定的版本,可使用 yum list 列出可用的版本:
$ yum list docker-ce --showduplicates | sort -r docker-ce.x86_64 18.03.0.ce-1.el7.centos docker-ce-stable
好比這裏能夠安裝18.03.0.ce版本:
$ sudo yum install docker-ce-18.03.0.ce
要啓動 Docker 也很是簡單:
$ sudo systemctl enable docker $ sudo systemctl start docker
另一種安裝方式是能夠直接下載指定的軟件包直接安裝便可,前往地址:https://download.docker.com/linux/centos/7/x86_64/stable/Packages/ 找到合適的.rpm
包下載,而後安裝便可:
$ sudo yum install /path/to/package.rpm
這節課給你們講解Docker
鏡像和容器的一些基本操做方法。
以前咱們提到過 Docker 官方提供了一個公共的鏡像倉庫:Docker Hub,咱們就能夠從這上面獲取鏡像,獲取鏡像的命令:docker pull,格式爲:
$ docker pull [選項] [Docker Registry 地址[:端口]/]倉庫名[:標籤]
$ docker pull ubuntu:16.04 16.04: Pulling from library/ubuntu bf5d46315322: Pull complete 9f13e0ac480c: Pull complete e8988b5b3097: Pull complete 40af181810e7: Pull complete e6f7c7e5c03e: Pull complete Digest: sha256:147913621d9cdea08853f6ba9116c2e27a3ceffecf3b492983ae97c3d643fbbe Status: Downloaded newer image for ubuntu:16.04
上面的命令中沒有給出 Docker 鏡像倉庫地址,所以將會從 Docker Hub 獲取鏡像。而鏡像名稱是 ubuntu:16.04,所以將會獲取官方鏡像 library/ubuntu 倉庫中標籤爲 16.04 的鏡像。 從下載過程當中能夠看到咱們以前說起的分層存儲的概念,鏡像是由多層存儲所構成。下載也是一層層的去下載,並不是單一文件。下載過程當中給出了每一層的 ID 的前 12 位。而且下載結束後,給出該鏡像完整的
sha256
的摘要,以確保下載一致性。有了鏡像後,咱們就可以以這個鏡像爲基礎啓動並運行一個容器。以上面的 ubuntu:16.04 爲例,若是咱們打算啓動裏面的 bash 而且進行交互式操做的話,能夠執行下面的命令。
$ docker run -it --rm \ ubuntu:16.04 \ /bin/bash root@e7009c6ce357:/# cat /etc/os-release NAME="Ubuntu" VERSION="16.04.4 LTS, Trusty Tahr" ID=ubuntu ID_LIKE=debian PRETTY_NAME="Ubuntu 16.04.4 LTS" VERSION_ID="16.04" HOME_URL="http://www.ubuntu.com/" SUPPORT_URL="http://help.ubuntu.com/" BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
docker run
就是運行容器的命令,具體格式咱們會在後面的課程中進行詳細講解,咱們這裏簡要的說明一下上面用到的參數。
--rm
能夠避免浪費空間。進入容器後,咱們能夠在 Shell 下操做,執行任何所需的命令。這裏,咱們執行了cat /etc/os-release
,這是 Linux 經常使用的查看當前系統版本的命令,從返回的結果能夠看到容器內是 Ubuntu 16.04.4 LTS 系統。最後咱們經過 exit
退出了這個容器。
$ docker image ls
列表包含了倉庫名、標籤、鏡像 ID、建立時間以及所佔用的空間。鏡像 ID 則是鏡像的惟一標識,一個鏡像能夠對應多個標籤。
若是仔細觀察,會注意到,這裏標識的所佔用空間和在 Docker Hub 上看到的鏡像大小不一樣。好比,ubuntu:16.04 鏡像大小,在這裏是 127 MB,可是在Docker Hub顯示的倒是 43 MB。這是由於 Docker Hub 中顯示的體積是壓縮後的體積。在鏡像下載和上傳過程當中鏡像是保持着壓縮狀態的,所以 Docker Hub 所顯示的大小是網絡傳輸中更關心的流量大小。而docker image ls
顯示的是鏡像下載到本地後,展開的大小,準確說,是展開後的各層所佔空間的總和,由於鏡像到本地後,查看空間的時候,更關心的是本地磁盤空間佔用的大小。
另一個須要注意的問題是,docker image ls
列表中的鏡像體積總和並不是是全部鏡像實際硬盤消耗。因爲 Docker 鏡像是多層存儲結構,而且能夠繼承、複用,所以不一樣鏡像可能會由於使用相同的基礎鏡像,從而擁有共同的層。因爲 Docker 使用Union FS
,相同的層只須要保存一份便可,所以實際鏡像硬盤佔用空間極可能要比這個列表鏡像大小的總和要小的多。你能夠經過如下命令來便捷的查看鏡像、容器、數據卷所佔用的空間。
$ docker system df
所須要的命令主要爲docker run
。 例如,下面的命令輸出一個 「Hello World」,以後終止容器。
$ docker run ubuntu:16.04 /bin/echo 'Hello world' Hello world
這跟在本地直接執行/bin/echo 'hello world'
幾乎感受不出任何區別。下面的命令則啓動一個 bash 終端,容許用戶進行交互。
$ docker run -t -i ubuntu:16.04 /bin/bash root@af8bae53bdd3:/#
其中,-t
選項讓Docker分配一個僞終端(pseudo-tty)並綁定到容器的標準輸入上,-i
則讓容器的標準輸入保持打開。 在交互模式下,用戶能夠經過所建立的終端來輸入命令,例如:
root@af8bae53bdd3:/# pwd / root@af8bae53bdd3:/# ls bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
當利用docker run
來建立容器時,Docker 在後臺運行的標準操做包括:
能夠利用docker container start
命令,直接將一個已經終止的容器啓動運行。
容器的核心爲所執行的應用程序,所須要的資源都是應用程序運行所必需的。除此以外,並無其它的資源。能夠在僞終端中利用 ps 或 top 來查看進程信息。
root@ba267838cc1b:/# ps PID TTY TIME CMD 1 ? 00:00:00 bash 11 ? 00:00:00 ps
可見,容器中僅運行了指定的 bash 應用。這種特色使得 Docker 對資源的利用率極高,是貨真價實的輕量級虛擬化。
更多的時候,須要讓 Docker 在後臺運行而不是直接把執行命令的結果輸出在當前宿主機下。此時,能夠經過添加-d
參數來實現。下面舉兩個例子來講明一下。
若是不使用-d
參數運行容器。
$ docker run ubuntu:16.04 /bin/sh -c "while true; do echo hello world; sleep 1; done" hello world hello world hello world hello world
容器會把輸出的結果 (STDOUT) 打印到宿主機上面。若是使用了-d
參數運行容器。
$ docker run -d ubuntu:16.04 /bin/sh -c "while true; do echo hello world; sleep 1; done" 77b2dc01fe0f3f1265df143181e7b9af5e05279a884f4776ee75350ea9d8017a
此時容器會在後臺運行並不會把輸出的結果 (STDOUT) 打印到宿主機上面(輸出結果能夠用 docker logs 查看)。
注: 容器是否會長久運行,是和 docker run 指定的命令有關,和 -d 參數無關。
使用-d
參數啓動後會返回一個惟一的 id,也能夠經過docker container ls
命令來查看容器信息。
$ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 77b2dc01fe0f ubuntu:16.04 /bin/sh -c 'while tr 2 minutes ago Up 1 minute agitated_wright
要獲取容器的輸出信息,能夠經過 docker container logs 命令。
$ docker container logs [container ID or NAMES]
hello world
hello world
hello world
. . .
可使用docker container stop
來終止一個運行中的容器。此外,當 Docker 容器中指定的應用終結時,容器也自動終止。
例如對於上一章節中只啓動了一個終端的容器,用戶經過 exit 命令或 Ctrl+d 來退出終端時,所建立的容器馬上終止。終止狀態的容器能夠用docker container ls -a
命令看到。例如
$ docker container ls -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ba267838cc1b ubuntu:16.04 "/bin/bash" 30 minutes ago Exited (0) About a minute ago trusting_newton
處於終止狀態的容器,能夠經過docker container start
命令來從新啓動。
此外,docker container restart
命令會將一個運行態的容器終止,而後再從新啓動它。
在使用-d
參數時,容器啓動後會進入後臺。某些時候須要進入容器進行操做:exec 命令 -i -t 參數。
只用-i
參數時,因爲沒有分配僞終端,界面沒有咱們熟悉的Linux
命令提示符,但命令執行結果仍然能夠返回。 當-i -t
參數一塊兒使用時,則能夠看到咱們熟悉的 Linux
命令提示符。
$ docker run -dit ubuntu:16.04 69d137adef7a8a689cbcb059e94da5489d3cddd240ff675c640c8d96e84fe1f6 $ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 69d137adef7a ubuntu:16.04 "/bin/bash" 18 seconds ago Up 17 seconds zealous_swirles $ docker exec -i 69d1 bash ls bin boot dev ... $ docker exec -it 69d1 bash root@69d137adef7a:/#
若是從這個 stdin 中 exit,不會致使容器的中止。這就是爲何推薦你們使用docker exec
的緣由。
更多參數說明請使用
docker exec --help
查看。
可使用docker container rm
來刪除一個處於終止狀態的容器。例如:
$ docker container rm trusting_newton trusting_newton
也可用使用docker rm
容器名來刪除,若是要刪除一個運行中的容器,能夠添加-f
參數。Docker 會發送 SIGKILL
信號給容器。
用docker container ls -a (或者docker ps -a)
命令能夠查看全部已經建立的包括終止狀態的容器,若是數量太多要一個個刪除可能會很麻煩,用下面的命令能夠清理掉全部處於終止狀態的容器。
$ docker container prune
或者
$ docker ps -aq
若是要刪除本地的鏡像,可使用`docker image rm·命令,其格式爲:
$ docker image rm [選項] <鏡像1> [<鏡像2> ...]
或者
$ docker rmi 鏡像名
或者用 ID、鏡像名、摘要刪除鏡像 其中,<鏡像> 能夠是 鏡像短 ID、鏡像長 ID、鏡像名 或者 鏡像摘要。 好比咱們有這麼一些鏡像:
$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE centos latest 0584b3d2cf6d 3 weeks ago 196.5 MB redis alpine 501ad78535f0 3 weeks ago 21.03 MB docker latest cf693ec9b5c7 3 weeks ago 105.1 MB nginx latest e43d811ce2f4 5 weeks ago 181.5 MB
咱們能夠用鏡像的完整 ID,也稱爲 長 ID,來刪除鏡像。使用腳本的時候可能會用長 ID,可是人工輸入就太累了,因此更多的時候是用 短 ID 來刪除鏡像。docker image ls
默認列出的就已是短 ID 了,通常取前3個字符以上,只要足夠區分於別的鏡像就能夠了。
好比這裏,若是咱們要刪除redis:alpine鏡像,能夠執行:
$ docker image rm 501 Untagged: redis:alpine Untagged: redis@sha256:f1ed3708f538b537eb9c2a7dd50dc90a706f7debd7e1196c9264edeea521a86d Deleted: sha256:501ad78535f015d88872e13fa87a828425117e3d28075d0c117932b05bf189b7 Deleted: sha256:96167737e29ca8e9d74982ef2a0dda76ed7b430da55e321c071f0dbff8c2899b Deleted: sha256:32770d1dcf835f192cafd6b9263b7b597a1778a403a109e2cc2ee866f74adf23 Deleted: sha256:127227698ad74a5846ff5153475e03439d96d4b1c7f2a449c7a826ef74a2d2fa Deleted: sha256:1333ecc582459bac54e1437335c0816bc17634e131ea0cc48daa27d32c75eab3 Deleted: sha256:4fc455b921edf9c4aea207c51ab39b10b06540c8b4825ba57b3feed1668fa7c7
咱們也能夠用鏡像名,也就是 <倉庫名>:<標籤>,來刪除鏡像。
$ docker image rm centos Untagged: centos:latest Untagged: centos@sha256:b2f9d1c0ff5f87a4743104d099a3d561002ac500db1b9bfa02a783a46e0d366c Deleted: sha256:0584b3d2cf6d235ee310cf14b54667d889887b838d3f3d3033acd70fc3c48b8a Deleted: sha256:97ca462ad9eeae25941546209454496e1d66749d53dfa2ee32bf1faabd239d38
鏡像是容器的基礎,每次執行docker run
的時候都會指定哪一個鏡像做爲容器運行的基礎。在以前的例子中,咱們所使用的都是來自於 Docker Hub 的鏡像。直接使用這些鏡像是能夠知足必定的需求,而當這些鏡像沒法直接知足需求時,咱們就須要定製這些鏡像。接下來的幾節就將講解如何定製鏡像。
回顧一下以前咱們學到的知識,鏡像是多層存儲,每一層是在前一層的基礎上進行的修改;而容器一樣也是多層存儲,是在以鏡像爲基礎層,在其基礎上加一層做爲容器運行時的存儲層。
如今讓咱們以定製一個 Web 服務器爲例子,來說解鏡像是如何構建的。
$ docker run --name webserver -d -p 80:80 nginx
這條命令會用 nginx 鏡像啓動一個容器,命名爲 webserver,而且映射了 80 端口,這樣咱們能夠用瀏覽器去訪問這個 nginx 服務器。
若是是在 Linux 本機運行的 Docker,或者若是使用的是 Docker for Mac、Docker for Windows,那麼能夠直接訪問:http://localhost;若是使用的是 Docker Toolbox,或者是在虛擬機、雲服務器上安裝的 Docker,則須要將 localhost 換爲虛擬機地址或者實際雲服務器地址。
直接用瀏覽器訪問的話,咱們會看到默認的 Nginx 歡迎頁面。
如今,假設咱們很是不喜歡這個歡迎頁面,咱們但願改爲歡迎 Docker 的文字,咱們可使用 docker exec命令進入容器,修改其內容。
$ docker exec -it webserver bash root@3729b97e8226:/# echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html root@3729b97e8226:/# exit
咱們以交互式終端方式進入 webserver 容器,並執行了 bash 命令,也就是得到一個可操做的 Shell。 而後,咱們用<h1>Hello, Docker!</h1>
覆蓋了 /usr/share/nginx/html/index.html的內容。 如今咱們再刷新瀏覽器的話,會發現內容被改變了。
咱們修改了容器的文件,也就是改動了容器的存儲層。咱們能夠經過docker diff
命令看到具體的改動。
$ docker diff webserver C /root A /root/.bash_history C /run C /usr C /usr/share C /usr/share/nginx C /usr/share/nginx/html C /usr/share/nginx/html/index.html C /var C /var/cache C /var/cache/nginx A /var/cache/nginx/client_temp A /var/cache/nginx/fastcgi_temp A /var/cache/nginx/proxy_temp A /var/cache/nginx/scgi_temp A /var/cache/nginx/uwsgi_temp
如今咱們定製好了變化,咱們但願能將其保存下來造成鏡像。
要知道,當咱們運行一個容器的時候(若是不使用卷的話),咱們作的任何文件修改都會被記錄於容器存儲層裏。而 Docker 提供了一個docker commit
命令,能夠將容器的存儲層保存下來成爲鏡像。換句話說,就是在原有鏡像的基礎上,再疊加上容器的存儲層,並構成新的鏡像。之後咱們運行這個新鏡像的時候,就會擁有原有容器最後的文件變化。
咱們能夠用下面的命令將容器保存爲鏡像:
$ docker commit \ --author "海馬學院" \ --message "修改了默認首頁" \ webserver \ nginx:v2 sha256:07e33465974800ce65751acc279adc6ed2dc5ed4e0838f8b86f0c87aa1795214
其中--author
是指定修改的做者,而--message
則是記錄本次修改的內容。這點和 git 版本控制類似,不過這裏這些信息能夠省略留空。
咱們能夠在docker image ls
中看到這個新定製的鏡像:
$ docker image ls nginx REPOSITORY TAG IMAGE ID CREATED SIZE nginx v2 07e334659748 9 seconds ago 181.5 MB nginx 1.11 05a60462f8ba 12 days ago 181.5 MB nginx latest e43d811ce2f4 4 weeks ago 181.5 MB
咱們還能夠用docker history
具體查看鏡像內的歷史記錄,若是比較 nginx:latest 的歷史記錄,咱們會發現新增了咱們剛剛提交的這一層。
$ docker history nginx:v2 IMAGE CREATED CREATED BY SIZE COMMENT 07e334659748 54 seconds ago nginx -g daemon off; 95 B 修改了默認網頁 e43d811ce2f4 4 weeks ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon 0 B <missing> 4 weeks ago /bin/sh -c #(nop) EXPOSE 443/tcp 80/tcp 0 B <missing> 4 weeks ago /bin/sh -c ln -sf /dev/stdout /var/log/nginx/ 22 B <missing> 4 weeks ago /bin/sh -c apt-key adv --keyserver hkp://pgp. 58.46 MB <missing> 4 weeks ago /bin/sh -c #(nop) ENV NGINX_VERSION=1.11.5-1 0 B <missing> 4 weeks ago /bin/sh -c #(nop) MAINTAINER NGINX Docker Ma 0 B <missing> 4 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0 B <missing> 4 weeks ago /bin/sh -c #(nop) ADD file:23aa4f893e3288698c 123 MB
新的鏡像定製好後,咱們能夠來運行這個鏡像。
$ docker run --name webserv2 -d -p 81:80 nginx:v2
這裏咱們命名爲新的服務爲 webserv2,而且映射到 81 端口。若是是 Docker for Mac/Windows 或 Linux 桌面的話,咱們就能夠直接訪問 http://localhost:81 看到結果,其內容應該和以前修改後的 webserver 同樣。
至此,咱們第一次完成了定製鏡像,使用的是docker commit
命令,手動操做給舊的鏡像添加了新的一層,造成新的鏡像,對鏡像多層存儲應該有了更直觀的感受。
注意: docker commit 命令除了學習以外,還有一些特殊的應用場合,好比被入侵後保存現場等。可是,不要使用 docker commit 定製鏡像,定製鏡像應該使用
Dockerfile
來完成。若是你想要定製鏡像請查看下一小節。
從前面一節的docker commit
的學習中,咱們能夠了解到,鏡像的定製實際上就是定製每一層所添加的配置、文件等信息,可是命令畢竟只是命令,每次定製都得去重複執行這個命令,並且還不夠直觀,若是咱們能夠把每一層修改、安裝、構建、操做的命令都寫入一個腳本,用這個腳原本構建、定製鏡像,那麼這些問題不就均可以解決了嗎?對的,這個腳本就是咱們說的Dockerfile
。
Dockerfile 是一個文本文件,其內包含了一條條的指令(Instruction),每一條指令構建一層,所以每一條指令的內容,就是描述該層應當如何構建。
還以以前定製 nginx 鏡像爲例,此次咱們使用 Dockerfile 來定製。在一個空白目錄中,創建一個文本文件,並命名爲 Dockerfile:
$ mkdir mynginx $ cd mynginx $ touch Dockerfile
其內容爲:
FROM nginx RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
這個 Dockerfile 很簡單,一共就兩行。涉及到了兩條指令,FROM 和 RUN。
所謂定製鏡像,那必定是以一個鏡像爲基礎,在其上進行定製。就像咱們以前運行了一個 nginx 鏡像的容器,再進行修改同樣,基礎鏡像是必須指定的。而FROM
就是指定基礎鏡像,所以一個 Dockerfile 中 FROM 是必備的指令,而且必須是第一條指令。
在Docker Store上有很是多的高質量的官方鏡像,有能夠直接拿來使用的服務類的鏡像,如 nginx、redis、mongo、mysql、httpd、php、tomcat 等;也有一些方便開發、構建、運行各類語言應用的鏡像,如 node、openjdk、python、ruby、golang 等。能夠在其中尋找一個最符合咱們最終目標的鏡像爲基礎鏡像進行定製。
若是沒有找到對應服務的鏡像,官方鏡像中還提供了一些更爲基礎的操做系統鏡像,如 ubuntu、debian、centos、fedora、alpine 等,這些操做系統的軟件庫爲咱們提供了更廣闊的擴展空間。
除了選擇現有鏡像爲基礎鏡像外,Docker 還存在一個特殊的鏡像,名爲scratch
。這個鏡像是虛擬的概念,並不實際存在,它表示一個空白的鏡像。
FROM scratch ...
若是你以scratch
爲基礎鏡像的話,意味着你不以任何鏡像爲基礎,接下來所寫的指令將做爲鏡像第一層開始存在。有的同窗可能感受很奇怪,沒有任何基礎鏡像,我怎麼去執行個人程序呢,其實對於 Linux 下靜態編譯的程序來講,並不須要有操做系統提供運行時支持,所需的一切庫都已經在可執行文件裏了,所以直接FROM scratch
會讓鏡像體積更加小巧。使用 Go 語言 開發的應用不少會使用這種方式來製做鏡像,這也是爲何有人認爲 Go 是特別適合容器微服務架構的語言的緣由之一。
RUN
指令是用來執行命令行命令的。因爲命令行的強大能力,RUN
指令在定製鏡像時是最經常使用的指令之一。其格式有兩種:
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
FROM debian:jessie RUN apt-get update RUN apt-get install -y gcc libc6-dev make RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" RUN mkdir -p /usr/src/redis RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 RUN make -C /usr/src/redis RUN make -C /usr/src/redis install
以前說過,Dockerfile 中每個指令都會創建一層,RUN 也不例外。每個 RUN 的行爲,就和剛纔咱們手工創建鏡像的過程同樣:新創建一層,在其上執行這些命令,執行結束後,commit 這一層的修改,構成新的鏡像。
而上面的這種寫法,建立了 7 層鏡像。這是徹底沒有意義的,並且不少運行時不須要的東西,都被裝進了鏡像裏,好比編譯環境、更新的軟件包等等。結果就是產生很是臃腫、很是多層的鏡像,不只僅增長了構建部署的時間,也很容易出錯。 這是不少初學 Docker 的人常犯的一個錯誤。
Union FS 是有最大層數限制的,好比 AUFS,曾經是最大不得超過 42 層,如今是不得超過 127 層。
上面的 Dockerfile 正確的寫法應該是這樣:
FROM debian:jessie RUN buildDeps='gcc libc6-dev make' \ && apt-get update \ && apt-get install -y $buildDeps \ && wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \ && mkdir -p /usr/src/redis \ && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \ && make -C /usr/src/redis \ && make -C /usr/src/redis install \ && rm -rf /var/lib/apt/lists/* \ && rm redis.tar.gz \ && rm -r /usr/src/redis \ && apt-get purge -y --auto-remove $buildDeps
首先,以前全部的命令只有一個目的,就是編譯、安裝 redis 可執行文件。所以沒有必要創建不少層,這只是一層的事情。所以,這裏沒有使用不少個 RUN 對一一對應不一樣的命令,而是僅僅使用一個 RUN 指令,並使用&&
將各個所需命令串聯起來。將以前的 7 層,簡化爲了 1 層。在撰寫 Dockerfile 的時候,要常常提醒本身,這並非在寫 Shell 腳本,而是在定義每一層該如何構建。
而且,這裏爲了格式化還進行了換行。Dockerfile 支持 Shell 類的行尾添加\
的命令換行方式,以及行首#
進行註釋的格式。良好的格式,好比換行、縮進、註釋等,會讓維護、排障更爲容易,這是一個比較好的習慣。
此外,還能夠看到這一組命令的最後添加了清理工做的命令,刪除了爲了編譯構建所須要的軟件,清理了全部下載、展開的文件,而且還清理了 apt 緩存文件。這是很重要的一步,咱們以前說過,鏡像是多層存儲,每一層的東西並不會在下一層被刪除,會一直跟隨着鏡像。所以鏡像構建時,必定要確保每一層只添加真正須要添加的東西,任何無關的東西都應該清理掉。 不少人初學 Docker 製做出了很臃腫的鏡像的緣由之一,就是忘記了每一層構建的最後必定要清理掉無關文件。
好了,讓咱們再回到以前定製的 nginx 鏡像的 Dockerfile 來。如今咱們明白了這個 Dockerfile
的內容,那麼讓咱們來構建這個鏡像吧。在 Dockerfile 文件所在目錄執行:
$ docker build -t nginx:v3 . Sending build context to Docker daemon 2.048 kB Step 1 : FROM nginx ---> e43d811ce2f4 Step 2 : RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html ---> Running in 9cdc27646c7b ---> 44aa4490ce2c Removing intermediate container 9cdc27646c7b Successfully built 44aa4490ce2c
從命令的輸出結果中,咱們能夠清晰的看到鏡像的構建過程。在 Step 2 中,如同咱們以前所說的那樣,RUN 指令啓動了一個容器 9cdc27646c7b,執行了所要求的命令,並最後提交了這一層 44aa4490ce2c,隨後刪除了所用到的這個容器 9cdc27646c7b。這裏咱們使用了 docker build
命令進行鏡像構建。其格式爲:
$ docker build [選項] <上下文路徑/URL/->
在這裏咱們指定了最終鏡像的名稱 -t nginx:v3,構建成功後,咱們能夠像以前運行 nginx:v2 那樣來運行這個鏡像,其結果會和 nginx:v2 同樣。
若是注意,會看到 docker build 命令最後有一個.
。.
表示當前目錄,而 Dockerfile 就在當前目錄,所以很多初學者覺得這個路徑是在指定 Dockerfile 所在路徑,這麼理解實際上是不許確的。若是對應上面的命令格式,你可能會發現,這是在指定上下文路徑。那麼什麼是上下文呢?
首先咱們要理解 docker build 的工做原理。Docker 在運行時分爲 Docker 引擎(也就是服務端守護進程)和客戶端工具。Docker 的引擎提供了一組 REST API,被稱爲 Docker Remote API,而如 docker 命令這樣的客戶端工具,則是經過這組 API 與 Docker 引擎交互,從而完成各類功能。所以,雖然表面上咱們好像是在本機執行各類 docker 功能,但實際上,一切都是使用的遠程調用形式在服務端(Docker 引擎)完成。也由於這種 C/S 設計,讓咱們操做遠程服務器的 Docker 引擎變得垂手可得。
當咱們進行鏡像構建的時候,並不是全部定製都會經過 RUN 指令完成,常常會須要將一些本地文件複製進鏡像,好比經過 COPY 指令、ADD 指令等。而 docker build 命令構建鏡像,其實並不是在本地構建,而是在服務端,也就是 Docker 引擎中構建的。那麼在這種客戶端/服務端的架構中,如何才能讓服務端得到本地文件呢?
這就引入了上下文的概念。當構建的時候,用戶會指定構建鏡像上下文的路徑,docker build 命令得知這個路徑後,會將路徑下的全部內容打包,而後上傳給 Docker 引擎。這樣 Docker 引擎收到這個上下文包後,展開就會得到構建鏡像所需的一切文件。若是在 Dockerfile 中這麼寫:
COPY ./package.json /app/
這並非要複製執行 docker build 命令所在的目錄下的 package.json,也不是複製 Dockerfile 所在目錄下的 package.json,而是複製 上下文(context) 目錄下的 package.json。
所以,COPY
這類指令中的源文件的路徑都是相對路徑。這也是初學者常常會問的爲何 COPY ../package.json /app 或者 COPY /opt/xxxx /app 沒法工做的緣由,由於這些路徑已經超出了上下文的範圍,Docker 引擎沒法得到這些位置的文件。若是真的須要那些文件,應該將它們複製到上下文目錄中去。
如今就能夠理解剛纔的命令docker build -t nginx:v3 .
中的這個.
,其實是在指定上下文的目錄,docker build 命令會將該目錄下的內容打包交給 Docker 引擎以幫助構建鏡像。
若是觀察 docker build 輸出,咱們其實已經看到了這個發送上下文的過程:
$ docker build -t nginx:v3 . Sending build context to Docker daemon 2.048 kB ...
理解構建上下文對於鏡像構建是很重要的,能夠避免犯一些不該該的錯誤。好比有些初學者在發現 COPY /opt/xxxx /app 不工做後,因而乾脆將 Dockerfile 放到了硬盤根目錄去構建,結果發現 docker build 執行後,在發送一個幾十 GB 的東西,極爲緩慢並且很容易構建失敗。那是由於這種作法是在讓 docker build 打包整個硬盤,這顯然是使用錯誤。
通常來講,應該會將 Dockerfile 置於一個空目錄下,或者項目根目錄下。若是該目錄下沒有所需文件,那麼應該把所需文件複製一份過來。若是目錄下有些東西確實不但願構建時傳給 Docker 引擎,那麼能夠用 .gitignore 同樣的語法寫一個.dockerignore
,該文件是用於剔除不須要做爲上下文傳遞給 Docker 引擎的。
那麼爲何會有人誤覺得 . 是指定 Dockerfile 所在目錄呢?這是由於在默認狀況下,若是不額外指定 Dockerfile 的話,會將上下文目錄下的名爲 Dockerfile 的文件做爲 Dockerfile。
這只是默認行爲,實際上 Dockerfile 的文件名並不要求必須爲 Dockerfile,並且並不要求必須位於上下文目錄中,好比能夠用-f ../Dockerfile.php
參數指定某個文件做爲 Dockerfile。
固然,通常你們習慣性的會使用默認的文件名 Dockerfile,以及會將其置於鏡像構建上下文目錄中。
Docker 還提供了docker load
和docker save
命令,用以將鏡像保存爲一個 tar 文件,而後傳輸到另外一個位置上,再加載進來。這是在沒有 Docker Registry 時的作法,如今已經不推薦,鏡像遷移應該直接使用 Docker Registry,不管是直接使用 Docker Hub 仍是使用內網私有 Registry 均可以。
使用docker save
命令能夠將鏡像保存爲歸檔文件。好比咱們但願保存這個 alpine 鏡像。
$ docker image ls alpine REPOSITORY TAG IMAGE ID CREATED SIZE alpine latest baa5d63471ea 5 weeks ago 4.803 MB
保存鏡像的命令爲:
$ docker save alpine | gzip > alpine-latest.tar.gz
而後咱們將 alpine-latest.tar.gz 文件複製到了到了另外一個機器上,能夠用下面這個命令加載鏡像:
$ docker load -i alpine-latest.tar.gz Loaded image: alpine:latest
若是咱們結合這兩個命令以及 ssh 甚至 pv 的話,利用 Linux 強大的管道,咱們能夠寫一個命令完成從一個機器將鏡像遷移到另外一個機器,而且帶進度條的功能:
docker save <鏡像名> | bzip2 | pv | ssh <用戶名>@<主機名> 'cat | docker load'
這節課給你們講講私有鏡像倉庫的使用。
目前 Docker 官方維護了一個公共倉庫Docker Hub
,大部分需求均可以經過在 Docker Hub 中直接下載鏡像來實現。若是你以爲拉取 Docker Hub 的鏡像比較慢的話,咱們能夠配置一個鏡像加速器:http://docker-cn.com/,固然國內大部分雲廠商都提供了相應的加速器,簡單配置便可。
你能夠在 https://cloud.docker.com 免費註冊一個 Docker 帳號。
經過執行docker login
命令交互式的輸入用戶名及密碼來完成在命令行界面登陸 Docker Hub。
你能夠經過docker logout
退出登陸。 拉取鏡像
你能夠經過docker search
命令來查找官方倉庫中的鏡像,並利用docker pull
命令來將它下載到本地。
例如以 centos 爲關鍵詞進行搜索:
$ docker search centos NAME DESCRIPTION STARS OFFICIAL AUTOMATED centos The official build of CentOS. 465 [OK] tianon/centos CentOS 5 and 6, created using rinse instea... 28 blalor/centos Bare-bones base CentOS 6.5 image 6 [OK] saltstack/centos-6-minimal 6 [OK] tutum/centos-6.4 DEPRECATED. Use tutum/centos:6.4 instead. ... 5 [OK]
能夠看到返回了不少包含關鍵字的鏡像,其中包括鏡像名字、描述、收藏數(表示該鏡像的受關注程度)、是否官方建立、是否自動建立。
官方的鏡像說明是官方項目組建立和維護的,automated
資源容許用戶驗證鏡像的來源和內容。
根據是不是官方提供,可將鏡像資源分爲兩類。
username/
來指定使用某個用戶提供的鏡像,好比 tianon 用戶。另外,在查找的時候經過--filter=stars=N
參數能夠指定僅顯示收藏數量爲 N 以上的鏡像。下載官方 centos 鏡像到本地。
$ docker pull centos
Pulling repository centos
0b443ba03958: Download complete
539c0211cd76: Download complete
511136ea3c5a: Download complete
7064731afe90: Download complete
用戶也能夠在登陸後經過docker push
命令來將本身的鏡像推送到 Docker Hub。如下命令中的 username 請替換爲你的 Docker 帳號用戶名。
$ docker tag ubuntu:17.10 username/ubuntu:17.10 $ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu 17.10 275d79972a86 6 days ago 94.6MB username/ubuntu 17.10 275d79972a86 6 days ago 94.6MB $ docker push username/ubuntu:17.10 $ docker search username NAME DESCRIPTION STARS OFFICIAL AUTOMATED username/ubuntu
有時候使用 Docker Hub 這樣的公共倉庫可能不方便,用戶能夠建立一個本地倉庫供私人使用。
docker-registry
是官方提供的工具,能夠用於構建私有的鏡像倉庫。本文內容基於 docker-registry v2.x 版本。你能夠經過獲取官方 registry 鏡像來運行。
$ docker run -d -p 5000:5000 --restart=always --name registry registry
這將使用官方的registry
鏡像來啓動私有倉庫。默認狀況下,倉庫會被建立在容器的/var/lib/registry
目錄下。你能夠經過 -v 參數來將鏡像文件存放在本地的指定路徑。例以下面的例子將上傳的鏡像放到本地的 /opt/data/registry 目錄。
$ docker run -d \ -p 5000:5000 \ -v /opt/data/registry:/var/lib/registry \ registry
建立好私有倉庫以後,就可使用docker tag
來標記一個鏡像,而後推送它到倉庫。例如私有倉庫地址爲 127.0.0.1:5000。先在本機查看已有的鏡像。
$ docker image ls REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE ubuntu latest ba5877dc9bec 6 weeks ago 192.7 MB
使用docker tag
將 ubuntu:latest 這個鏡像標記爲 127.0.0.1:5000/ubuntu:latest。 格式爲 docker tag IMAGE[:TAG] [REGISTRY_HOST[:REGISTRY_PORT]/]REPOSITORY[:TAG]
$ docker tag ubuntu:latest 127.0.0.1:5000/ubuntu:latest $ docker image ls REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE ubuntu latest ba5877dc9bec 6 weeks ago 192.7 MB 127.0.0.1:5000/ubuntu:latest latest ba5877dc9bec 6 weeks ago 192.7 MB
使用docker push
上傳標記的鏡像。
$ docker push 127.0.0.1:5000/ubuntu:latest The push refers to repository [127.0.0.1:5000/ubuntu] 373a30c24545: Pushed a9148f5200b0: Pushed cdd3de0940ab: Pushedfc56279bbb33: Pushed b38367233d37: Pushed 2aebd096e0e2: Pushed latest: digest: sha256:fe4277621f10b5026266932ddf760f5a756d2facd505a94d2da12f4f52f71f5a size: 1568
用curl
查看倉庫中的鏡像。
$ curl 127.0.0.1:5000/v2/_catalog {"repositories":["ubuntu"]}
這裏能夠看到 {"repositories":["ubuntu"]},代表鏡像已經被成功上傳了。
先刪除已有鏡像,再嘗試從私有倉庫中下載這個鏡像。
$ docker image rm 127.0.0.1:5000/ubuntu:latest $ docker pull 127.0.0.1:5000/ubuntu:latest Pulling repository 127.0.0.1:5000/ubuntu:latest ba5877dc9bec: Download complete 511136ea3c5a: Download complete 9bad880da3d2: Download complete 25f11f5fb0cb: Download complete ebc34468f71d: Download complete 2318d26665ef: Download complete $ docker image ls REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE 127.0.0.1:5000/ubuntu:latest latest ba5877dc9bec 6 weeks ago 192.7 MB
若是你不想使用 127.0.0.1:5000 做爲倉庫地址,好比想讓本網段的其餘主機也能把鏡像推送到私有倉庫。你就得把例如 192.168.199.100:5000 這樣的內網地址做爲私有倉庫地址,這時你會發現沒法成功推送鏡像。
這是由於 Docker 默認不容許非 HTTPS 方式推送鏡像。咱們能夠經過 Docker 的配置選項來取消這個限制。
對於使用 upstart 的系統而言,編輯/etc/default/docker
文件,在其中的DOCKER_OPTS
中增長以下內容:
DOCKER_OPTS="--registry-mirror=https://registry.docker-cn.com --insecure-registries=192.168.199.100:5000"
從新啓動服務:
$ sudo service docker restart
對於使用 systemd 的系統,請在/etc/docker/daemon.json
中寫入以下內容(若是文件不存在請新建該文件)
{ "registry-mirror": [ "https://registry.docker-cn.com" ], "insecure-registries": [ "192.168.199.100:5000" ] }
注意:該文件必須符合
json
規範,不然 Docker 將不能啓動。
對於 Docker for Windows、Docker for Mac 在設置中編輯daemon.json
增長和上邊同樣的字符串便可。
這一節介紹如何在 Docker 內部以及容器之間管理數據,在容器中管理數據主要有兩種方式:
數據卷
是一個可供一個或多個容器使用的特殊目錄,它繞過UFS
,能夠提供不少有用的特性:
注意:數據卷 的使用,相似於 Linux 下對目錄或文件進行 mount,鏡像中的被指定爲掛載點的目錄中的文件會隱藏掉,能顯示看的是掛載的 數據卷。
選擇 -v 仍是 -–mount 參數: Docker 新用戶應該選擇--mount
參數,經驗豐富的 Docker 使用者對-v
或者 --volume
已經很熟悉了,可是推薦使用--mount
參數。
建立一個數據卷:
$ docker volume create my-vol
查看全部的 數據卷:
$ docker volume ls local my-vol
在主機裏使用如下命令能夠查看指定 數據卷 的信息
$ docker volume inspect my-vol [ { "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/my-vol/_data", "Name": "my-vol", "Options": {}, "Scope": "local" } ]
啓動一個掛載數據卷的容器:在用docker run
命令的時候,使用--mount
標記來將 數據卷 掛載到容器裏。在一次docker run
中能夠掛載多個 數據卷。下面建立一個名爲 web 的容器,並加載一個 數據卷 到容器的 /webapp 目錄。
$ docker run -d -P \ --name web \ # -v my-vol:/wepapp \ --mount source=my-vol,target=/webapp \ training/webapp \ python app.py
查看數據卷的具體信息:在主機裏使用如下命令能夠查看 web 容器的信息
$ docker inspect web ... "Mounts": [ { "Type": "volume", "Name": "my-vol", "Source": "/var/lib/docker/volumes/my-vol/_data", "Destination": "/app", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ], ...
刪除數據卷:
$ docker volume rm my-vol
數據卷 是被設計用來持久化數據的,它的生命週期獨立於容器,Docker 不會在容器被刪除後自動刪除 數據卷,而且也不存在垃圾回收這樣的機制來處理沒有任何容器引用的 數據卷。若是須要在刪除容器的同時移除數據卷。能夠在刪除容器的時候使用docker rm -v
這個命令。 無主的數據卷可能會佔據不少空間,要清理請使用如下命令
$ docker volume prune
選擇 -v 仍是 -–mount 參數: Docker 新用戶應該選擇 --mount 參數,經驗豐富的 Docker 使用者對 -v 或者 --volume 已經很熟悉了,可是推薦使用 --mount 參數。
掛載一個主機目錄做爲數據卷:使用 --mount
標記能夠指定掛載一個本地主機的目錄到容器中去。
$ docker run -d -P \ --name web \ # -v /src/webapp:/opt/webapp \ --mount type=bind,source=/src/webapp,target=/opt/webapp \ training/webapp \ python app.py
上面的命令加載主機的 /src/webapp 目錄到容器的 /opt/webapp目錄。這個功能在進行測試的時候十分方便,好比用戶能夠放置一些程序到本地目錄中,來查看容器是否正常工做。本地目錄的路徑必須是絕對路徑,之前使用 -v 參數時若是本地目錄不存在 Docker 會自動爲你建立一個文件夾,如今使用 --mount 參數時若是本地目錄不存在,Docker 會報錯。
Docker 掛載主機目錄的默認權限是 讀寫,用戶也能夠經過增長readonly
指定爲 只讀。
$ docker run -d -P \ --name web \ # -v /src/webapp:/opt/webapp:ro \ --mount type=bind,source=/src/webapp,target=/opt/webapp,readonly \ training/webapp \ python app.py
加了readonly
以後,就掛載爲 只讀 了。若是你在容器內 /opt/webapp 目錄新建文件,會顯示以下錯誤:
/opt/webapp # touch new.txt touch: new.txt: Read-only file system
查看數據卷的具體信息:在主機裏使用如下命令能夠查看 web 容器的信息
$ docker inspect web ... "Mounts": [ { "Type": "bind", "Source": "/src/webapp", "Destination": "/opt/webapp", "Mode": "", "RW": true, "Propagation": "rprivate" } ],
掛載一個本地主機文件做爲數據卷:--mount
標記也能夠從主機掛載單個文件到容器中
$ docker run --rm -it \ # -v $HOME/.bash_history:/root/.bash_history \ --mount type=bind,source=$HOME/.bash_history,target=/root/.bash_history \ ubuntu:17.10 \ bash root@2affd44b4667:/# history 1 ls 2 diskutil list
這樣就能夠記錄在容器輸入過的命令了。
當Docker
進程啓動時,會在主機上建立一個名爲docker0
的虛擬網橋,此主機上啓動的Docker
容器會鏈接到這個虛擬網橋上。虛擬網橋的工做方式和物理交換機相似,這樣主機上的全部容器就經過交換機連在了一個二層網絡中。從docker0
子網中分配一個 IP 給容器使用,並設置 docker0 的 IP 地址爲容器的默認網關。在主機上建立一對虛擬網卡veth pair
設備,Docker 將 veth pair 設備的一端放在新建立的容器中,並命名爲eth0
(容器的網卡),另外一端放在主機中,以vethxxx
這樣相似的名字命名,並將這個網絡設備加入到 docker0 網橋中。能夠經過brctl show
命令查看。
bridge
模式是 docker 的默認網絡模式,不寫–net
參數,就是bridge
模式。使用docker run -p
時,docker 實際是在iptables
作了DNAT
規則,實現端口轉發功能。可使用iptables -t nat -vnL
查看。bridge
模式以下圖所示:
演示:
$ docker run -tid --net=bridge --name docker_bri1 \ ubuntu-base:v3 docker run -tid --net=bridge --name docker_bri2 \ ubuntu-base:v3 $ brctl show $ docker exec -ti docker_bri1 /bin/bash $ ifconfig –a $ route –n
若是你以前有 Docker 使用經驗,你可能已經習慣了使用--link
參數來使容器互聯。
隨着 Docker 網絡的完善,強烈建議你們將容器加入自定義的 Docker 網絡來鏈接多個容器,而不是使用 --link 參數。
下面先建立一個新的 Docker 網絡。
$ docker network create -d bridge my-net
-d
參數指定 Docker 網絡類型,有 bridge overlay
。其中 overlay 網絡類型用於 Swarm mode,在本小節中你能夠忽略它。
運行一個容器並鏈接到新建的 my-net 網絡
$ docker run -it --rm --name busybox1 --network my-net busybox sh
打開新的終端,再運行一個容器並加入到 my-net 網絡
$ docker run -it --rm --name busybox2 --network my-net busybox sh
再打開一個新的終端查看容器信息
$ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b47060aca56b busybox "sh" 11 minutes ago Up 11 minutes busybox2 8720575823ec busybox "sh" 16 minutes ago Up 16 minutes busybox1
下面經過 ping 來證實 busybox1 容器和 busybox2 容器創建了互聯關係。 在 busybox1 容器輸入如下命令
/ # ping busybox2 PING busybox2 (172.19.0.3): 56 data bytes 64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.072 ms 64 bytes from 172.19.0.3: seq=1 ttl=64 time=0.118 ms
用 ping 來測試鏈接 busybox2 容器,它會解析成 172.19.0.3。 同理在 busybox2 容器執行 ping busybox1,也會成功鏈接到。
/ # ping busybox1 PING busybox1 (172.19.0.2): 56 data bytes 64 bytes from 172.19.0.2: seq=0 ttl=64 time=0.064 ms 64 bytes from 172.19.0.2: seq=1 ttl=64 time=0.143 ms
這樣,busybox1 容器和 busybox2 容器創建了互聯關係。
若是你有多個容器之間須要互相鏈接,推薦使用Docker Compose
。
若是啓動容器的時候使用host
模式,那麼這個容器將不會得到一個獨立的Network Namespace
,而是和宿主機共用一個 Network Namespace。容器將不會虛擬出本身的網卡,配置本身的 IP 等,而是使用宿主機的 IP 和端口。可是,容器的其餘方面,如文件系統、進程列表等仍是和宿主機隔離的。 Host模式以下圖所示:
演示:
$ docker run -tid --net=host --name docker_host1 ubuntu-base:v3 $ docker run -tid --net=host --name docker_host2 ubuntu-base:v3 $ docker exec -ti docker_host1 /bin/bash $ docker exec -ti docker_host1 /bin/bash $ ifconfig –a $ route –n
這個模式指定新建立的容器和已經存在的一個容器共享一個 Network Namespace,而不是和宿主機共享。新建立的容器不會建立本身的網卡,配置本身的 IP,而是和一個指定的容器共享 IP、端口範圍等。一樣,兩個容器除了網絡方面,其餘的如文件系統、進程列表等仍是隔離的。兩個容器的進程能夠經過 lo 網卡設備通訊。 Container模式示意圖:
演示:
$ docker run -tid --net=container:docker_bri1 \ --name docker_con1 ubuntu-base:v3 $ docker exec -ti docker_con1 /bin/bash $ docker exec -ti docker_bri1 /bin/bash $ ifconfig –a $ route -n
使用none
模式,Docker 容器擁有本身的 Network Namespace,可是,並不爲Docker 容器進行任何網絡配置。也就是說,這個 Docker 容器沒有網卡、IP、路由等信息。須要咱們本身爲 Docker 容器添加網卡、配置 IP 等。 None模式示意圖: 演示:
$ docker run -tid --net=none --name \ docker_non1 ubuntu-base:v3 $ docker exec -ti docker_non1 /bin/bash $ ifconfig –a $ route -n
Docker 的跨主機通訊咱們這裏就先暫時不講解,咱們在後面的Kubernetes
課程當中會用到。