文章假設你已經熟悉了Docker的基本命令和基本知識python
首先咱們容許一個交互式的容器git
$docker run -i -t <image name> /bin/bash
這樣就創建了一個到容器內的交互式鏈接,看到的是以下的命令行:docker
root@df3880b17407:/#
這裏咱們啓動了一個容器,以bash做爲其根進程.shell
root@df3880b17407:/# ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 18164 2020 ? S 06:06 0:00 /bin/bash
能夠看到,在這個容器中,bash 的 PID爲 1,而實體機日常狀況下,是這樣的:ubuntu
root@ubuntu:~# ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.1 24716 2612 ? Ss Sep04 0:01 /sbin/init
你們都知道,全部進程的共同祖先都是 PID=1的進程
因此在容器中,全部之後建立的進程都是經過/bin/bash 建立的,PID=1的 bash是容器中全部進程的祖先
理解了這點後,對容器的理解就很簡單了.bash
對於一個正在運行的容器,其文件系統都是一個從根目錄開始的虛擬文件系統,在容器中看到的是這樣的:服務器
root@df3880b17407:/# ll / total 68 drwxr-xr-x 2 root root 4096 Jul 22 22:51 bin drwxr-xr-x 2 root root 4096 Apr 10 22:12 boot drwxr-xr-x 3 root root 4096 Jul 22 22:49 dev drwxr-xr-x 85 root root 4096 Sep 5 06:49 etc drwxr-xr-x 2 root root 4096 Apr 10 22:12 home drwxr-xr-x 16 root root 4096 Jul 22 22:50 lib drwxr-xr-x 2 root root 4096 Aug 12 03:30 lib64 drwxr-xr-x 2 root root 4096 Jul 22 22:48 media drwxr-xr-x 2 root root 4096 Apr 10 22:12 mnt drwxr-xr-x 2 root root 4096 Jul 22 22:48 opt dr-xr-xr-x 356 root root 0 Sep 5 06:06 proc drwx------ 2 root root 4096 Jul 22 22:51 root drwxr-xr-x 7 root root 4096 Sep 5 07:23 run drwxr-xr-x 2 root root 4096 Aug 12 03:30 sbin drwxr-xr-x 2 root root 4096 Jul 22 22:48 srv dr-xr-xr-x 13 root root 0 Sep 5 06:06 sys drwxrwxrwt 2 root root 4096 Sep 5 06:55 tmp drwxr-xr-x 20 root root 4096 Sep 5 06:11 usr drwxr-xr-x 19 root root 4096 Sep 5 06:11 var
其實真是狀況是這樣的,容器中的文件系統都是掛載到了真是系統中的一個目錄下面.
/var/lib/docker/containers/<image-long-id>/rootfs
這個配置是怎麼來的呢,其實全部容器的管理都是經過lxc來管理的,lxc的配置文件放在
/var/lib/docker/containers/<image-long-id>/config.lxc
文件中有字段表示容器掛載到哪一個文件目錄, 好比個人是這樣的:
lxc.rootfs = /var/lib/docker/containers/df3880b17407575cd642a6b7da3c7e417a55fad5bbd63152f89921925626d2b6/rootfs
打開看一下,一目瞭然:網絡
root@ubuntu:/var/lib/docker/containers/df3880b17407575cd642a6b7da3c7e417a55fad5bbd63152f89921925626d2b6/rootfs# ll total 84 drwxr-xr-x 53 root root 4096 Sep 5 00:23 ./ drwx------ 4 root root 4096 Sep 5 00:53 ../ drwxr-xr-x 2 root root 4096 Jul 22 15:51 bin/ drwxr-xr-x 2 root root 4096 Apr 10 15:12 boot/ drwxr-xr-x 3 root root 4096 Jul 22 15:49 dev/ drwxr-xr-x 85 root root 4096 Sep 4 23:49 etc/ drwxr-xr-x 2 root root 4096 Apr 10 15:12 home/ drwxr-xr-x 16 root root 4096 Jul 22 15:50 lib/ drwxr-xr-x 2 root root 4096 Aug 11 20:30 lib64/ drwxr-xr-x 2 root root 4096 Jul 22 15:48 media/ drwxr-xr-x 2 root root 4096 Apr 10 15:12 mnt/ drwxr-xr-x 2 root root 4096 Jul 22 15:48 opt/ drwxr-xr-x 2 root root 4096 Apr 10 15:12 proc/ drwx------ 2 root root 4096 Jul 22 15:51 root/ drwxr-xr-x 7 root root 4096 Sep 5 00:23 run/ drwxr-xr-x 2 root root 4096 Aug 11 20:30 sbin/ drwxr-xr-x 2 root root 4096 Jul 22 15:48 srv/ drwxr-xr-x 2 root root 4096 Mar 12 18:41 sys/ drwxrwxrwt 2 root root 4096 Sep 4 23:55 tmp/ drwxr-xr-x 20 root root 4096 Sep 4 23:11 usr/ drwxr-xr-x 19 root root 4096 Sep 4 23:11 var/
這些就是容器中的真實目錄了,容器中對於目錄的操做都是操做了這個host機器的真實目錄。
對於不一樣的容器,掛載點是不同的,而容器不能穿越根目錄上一級去訪問, 因此這裏對每個容器都作到了文件系統隔離。tcp
咱們把每個
/var/lib/docker/containers/<image-long-id>
看作是一個容器的配置目錄的話,能夠看到在配置目錄下面有一個 rw/
目錄,打開看有些什麼命令行
total 36 drwxr-xr-x 9 root root 4096 Sep 5 00:23 ./ drwx------ 4 root root 4096 Sep 5 00:53 ../ drwxr-xr-x 6 root root 4096 Sep 4 23:49 etc/ drwxr-xr-x 2 root root 4096 Sep 5 00:23 run/ drwxrwxrwt 2 root root 4096 Sep 4 23:55 tmp/ drwxr-xr-x 7 root root 4096 Sep 4 23:11 usr/ drwxr-xr-x 5 root root 4096 Sep 4 23:11 var/ -r--r--r-- 1 root root 0 Sep 4 23:06 .wh..wh.aufs drwx------ 2 root root 4096 Sep 4 23:06 .wh..wh.orph/ drwx------ 2 root root 4096 Sep 4 23:11 .wh..wh.plnk/
裏面是一些不完整的根目錄,這不能說明什麼,可是咱們在container中寫入文件後,看看其中的變化
在容器中執行如下命令
root@df3880b17407:/# touch /opt/x
在 /opt 下咱們生成了一個文件
再看看
root@ubuntu:/var/lib/docker/containers/df3880b17407575cd642a6b7da3c7e417a55fad5bbd63152f89921925626d2b6/rw# ll total 40 drwxr-xr-x 10 root root 4096 Sep 5 01:00 ./ drwx------ 4 root root 4096 Sep 5 00:53 ../ drwxr-xr-x 6 root root 4096 Sep 4 23:49 etc/ drwxr-xr-x 2 root root 4096 Sep 5 01:00 opt/ drwxr-xr-x 2 root root 4096 Sep 5 00:23 run/ drwxrwxrwt 2 root root 4096 Sep 4 23:55 tmp/ drwxr-xr-x 7 root root 4096 Sep 4 23:11 usr/ drwxr-xr-x 5 root root 4096 Sep 4 23:11 var/ -r--r--r-- 1 root root 0 Sep 4 23:06 .wh..wh.aufs drwx------ 2 root root 4096 Sep 4 23:06 .wh..wh.orph/ drwx------ 2 root root 4096 Sep 4 23:11 .wh..wh.plnk/
是的,在host機器上新生成了 opt/
目錄,這裏作到了容器的寫時複製
以系統的三大進程間通訊的消息隊列來看
初始狀態在 ghost, ipcs -q 查看消息隊列
root@ubuntu:~/codes/msq# ipcs -q ------ Message Queues -------- key msqid owner perms used-bytes messages
在ghost 建立一個, 這裏樓主本身寫的代碼建立的消息隊列:
root@ubuntu:~/codes/msq# ./main 1 Create msq with key id 65536root@ubuntu:~/codes/msq# ipcs -q ------ Message Queues -------- key msqid owner perms used-bytes messages 0x00000001 65536 root 666 0 0
而後在容器中查看 ipcs -q
root@df3880b17407:/# ipcs -q ------ Message Queues -------- key msqid owner perms used-bytes messages
能夠看到系統資源是隔離的,這裏只是說了一部分,其實還包括了能夠經過cgoup對其作CPU和Memory的Quota管理.
默認狀況下是使用了全部CPU和內存的,可是能夠在config.lxc增長以下配置設置CPU等,具體能夠參考lxc的文檔
lxc.cgroup.cpu.shares=512 lxc.cgroup.cpuset.cpus=1.2
資源隔離的原理就在於利用cgroup,將不一樣進程的使用隔離開,假設每一個容器都是以bash啓動的,那麼在容器內部,每一個子進程都只能使用當前bash下面的資源,對於其餘的系統資源是隔離的.子進程的訪問權限由父進程決定
在安裝好docker後,會默認初始化一個 docker0
的網橋
docker0 Link encap:Ethernet HWaddr ee:8c:1f:8b:d7:59 inet addr:172.17.42.1 Bcast:0.0.0.0 Mask:255.255.0.0 ...
在host機器上,會爲每個容器生成一個默認的網卡相似這樣的 vethdBVa1H
veth*
這個網卡的一端鏈接在容器的eth0,一端鏈接到docker0.這樣就實現了每一個容器有一個單獨的IP.
這裏若是須要容器訪問外網,須要將eth0設置爲混雜模式:
$ifconfig eth0 promisc
這樣看來,容器會從172.17.0.0/24 這個網段選擇一個IP做爲eth0的IP,這樣,容器就能夠和外部經過 docker0網橋通訊了.
在容器內部監聽一個端口 python -m SimpleHTTPServer 80 >> /tmp/log.log &
從ghost訪問 telnet 172.17.0.2 80
在容器中看到以下:
Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 2823/python tcp 0 0 172.17.0.2:80 172.17.42.1:46142 TIME_WAIT -
在host上看到
Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 172.17.42.1:46142 172.17.0.2:80 ESTABLISHED 10244/telnet
若是須要外部可以訪問容器,須要作端口映射規則,和配置虛擬機同樣的道理, 只不過這裏能夠看到的是,80端口並無佔用了本地端口,而是在容器內部作了監聽,外部是經過docker0 橋接過去的,每一個容器間也作到了端口和網絡隔離.
很少說,在 /var/lib/docker/containers/<image-long-id>.log
下
Docker的變動管理看作是git的版本管理好了。
生成鏡像的時候,未作改動的部分就是上一個版本的鏡像的引用,若是作了改動,就是一個新的文件。
將剛纔操做的容器作成鏡像
docker commit <image-id> <REPOSITORY>
此時的鏡像多出來的部分,好比我在這個鏡像中安裝了Python,那麼多出來的部分做爲新文件,其餘部分任然是上一個版本的引用。
你能夠搭建本身的鏡像服務器,push到本身的鏡像服務器,從其餘機器拉下來後直接能夠運行。
以上,一點愚見,但願指正.