譯文:關(guān)于Docker數(shù)據(jù)容器(data only container)
什么是數(shù)據(jù)容器?
數(shù)據(jù)容器就是本身只創(chuàng)建一個volume供其他容器共享,創(chuàng)建完后即退出,不執(zhí)行任何任務(wù)。比如通過以下方式創(chuàng)建一個postgres容器。
- docker run --name dbdata postgres echo "Data-only container for postgres"
該容器運行echo "Data-only container for postgres"即退出,然而只要沒有刪除該容器,該容器/var/lib/postgresql/data的volume(在Dockerfile使用VOLUME指令定義)就會一直存在。
然后我們可以新建若干容器來共享數(shù)據(jù),比如:
- docker run -d --volumes-from dbdata --name db1 postgres
如何創(chuàng)建數(shù)據(jù)容器?
太簡單了,創(chuàng)建任何容器,然后使用-v創(chuàng)建volume即可。但大家一定會想到用最小的鏡像吧,比如hello-world,即
- docker run -v /data hello-world
但這樣是錯誤的! 為什么呢?
我們首先創(chuàng)建一個簡單的鏡像:
- FROM debian:jessie
- RUN useradd mickey
- RUN mkdir /foo && touch /foo/bar && chown -R mickey:mickey /foo
- USER mickey
- CMD ls -lh /foo
構(gòu)建:
- docker build -t mickey_foo -< Dockerfile
運行下:
- docker run --rm -v /foo mickey_foo
輸出:
- total 0
- -rw-r--r-- 2 mickey mickey 0 Nov 18 05:58 bar
運行正常,沒有任何問題。
下面我們嘗試使用busybox來作為數(shù)據(jù)容器:
- docker run -v /foo --name mickey_data busybox true
- docker run --rm --volumes-from mickey_data mickey_foo
輸出:
- total 0
- # Empty WTF??
- docker run --rm --volumes-from mickey_data mickey_foo ls -lh /
- total 68K
- drwxr-xr-x 2 root root 4.0K Nov 18 06:02 bin
- drwxr-xr-x 2 root root 4.0K Oct 9 18:27 boot
- drwxr-xr-x 5 root root 360 Nov 18 06:05 dev
- drwxr-xr-x 1 root root 4.0K Nov 18 06:05 etc
- drwxr-xr-x 2 root root 4.0K Nov 18 06:02 foo
- drwxr-xr-x 2 root root 4.0K Oct 9 18:27 home
- drwxr-xr-x 9 root root 4.0K Nov 18 06:02 lib
- drwxr-xr-x 2 root root 4.0K Nov 18 06:02 lib64
- drwxr-xr-x 2 root root 4.0K Nov 5 21:40 media
- drwxr-xr-x 2 root root 4.0K Oct 9 18:27 mnt
- drwxr-xr-x 2 root root 4.0K Nov 5 21:40 opt
- dr-xr-xr-x 120 root root 0 Nov 18 06:05 proc
- drwx------ 2 root root 4.0K Nov 18 06:02 root
- drwxr-xr-x 3 root root 4.0K Nov 18 06:02 run
- drwxr-xr-x 2 root root 4.0K Nov 18 06:02 sbin
- drwxr-xr-x 2 root root 4.0K Nov 5 21:40 srv
- dr-xr-xr-x 13 root root 0 Nov 18 06:05 sys
- drwxrwxrwt 2 root root 4.0K Nov 5 21:46 tmp
- drwxr-xr-x 10 root root 4.0K Nov 18 06:02 usr
- drwxr-xr-x 11 root root 4.0K Nov 18 06:02 var
Owened by root? WTF???
- docker run --rm --volumes-from mickey_data mickey_foo touch /foo/ba
- touch: cannot touch '/foo/bar': Permission denied
發(fā)生了什么呢?我們的/foo 仍然存在, 但是它是空的并且所有者是root?
讓我們再試試使用我們剛剛構(gòu)建的mickey_foo作為數(shù)據(jù)容器:
- ~: docker rm -v mickey_data # remove the old one
- mickey_data
- ~: docker run --name mickey_data -v /foo mickey_foo true
- ~: docker run --rm --volumes-from mickey_data mickey_foo
- total 0
- -rw-r--r-- 1 mickey mickey 0 Nov 18 05:58 bar
- # Yes!
- ~: docker run --rm --volumes-from mickey_data mickey_foo ls -lh /
- total 68K
- drwxr-xr-x 2 root root 4.0K Nov 18 06:02 bin
- drwxr-xr-x 2 root root 4.0K Oct 9 18:27 boot
- drwxr-xr-x 5 root root 360 Nov 18 06:11 dev
- drwxr-xr-x 1 root root 4.0K Nov 18 06:11 etc
- drwxr-xr-x 2 mickey mickey 4.0K Nov 18 06:10 foo
- drwxr-xr-x 2 root root 4.0K Oct 9 18:27 home
- drwxr-xr-x 9 root root 4.0K Nov 18 06:02 lib
- drwxr-xr-x 2 root root 4.0K Nov 18 06:02 lib64
- drwxr-xr-x 2 root root 4.0K Nov 5 21:40 media
- drwxr-xr-x 2 root root 4.0K Oct 9 18:27 mnt
- drwxr-xr-x 2 root root 4.0K Nov 5 21:40 opt
- dr-xr-xr-x 121 root root 0 Nov 18 06:11 proc
- drwx------ 2 root root 4.0K Nov 18 06:02 root
- drwxr-xr-x 3 root root 4.0K Nov 18 06:02 run
- drwxr-xr-x 2 root root 4.0K Nov 18 06:02 sbin
- drwxr-xr-x 2 root root 4.0K Nov 5 21:40 srv
- dr-xr-xr-x 13 root root 0 Nov 18 06:05 sys
- drwxrwxrwt 2 root root 4.0K Nov 5 21:46 tmp
- drwxr-xr-x 10 root root 4.0K Nov 18 06:02 usr
- drwxr-xr-x 11 root root 4.0K Nov 18 06:02 var
- # YES!!
- ~: docker run --rm --volumes-from mickey_data mickey_foo touch /foo/baz
- ~: docker run --rm --volumes-from mickey_data mickey_foo ls -lh /foo
- total 0
- -rw-r--r-- 1 mickey mickey 0 Nov 18 06:11 bar
- -rw-r--r-- 1 mickey mickey 0 Nov 18 06:12 baz
- # YES!!!
由于我們剛剛使用了相同的鏡像作為數(shù)據(jù)容器鏡像,共享的容器能夠找到共享數(shù)據(jù)。為什么使用busybox不可以呢?由于busybox沒有/foo這個目錄,當(dāng)我們使用-v創(chuàng)建/foo這個數(shù)據(jù)卷時,docker會以默認(rèn)用戶自動創(chuàng)建對應(yīng)的目錄(這里是root),而--volumes-from僅僅是重用存在的卷,而不會對卷自動做任何事情。因此當(dāng)我們嘗試去寫/foo時由于沒有權(quán)限(root所有,mickey用戶).
因此我們應(yīng)該使用和共享的容器相同的鏡像做數(shù)據(jù)容器鏡像?是的!
那我們使用這么大的鏡像不會浪費空間么?
為什么不使用小鏡像作為數(shù)據(jù)容器?
其中一個原因,在上一節(jié)已經(jīng)解釋。遺留的一個問題是使用這么大的鏡像(因為一般的鏡像都會比較大)會不會浪費空間呢?
首先我們需要知道Docker的文件系統(tǒng)是如何工作的。Docker鏡像是由多個文件系統(tǒng)(只讀層)疊加而成。當(dāng)我們啟動一個容器的時候,Docker會加載只讀鏡像層并在其上(譯者注:鏡像棧頂部)添加一個讀寫層。如果運行中的容器修改了現(xiàn)有的一個已經(jīng)存在的文件,那該文件將會從讀寫層下面的只讀層復(fù)制到讀寫層,該文件的只讀版本仍然存在,只是已經(jīng)被讀寫層中該文件的副本所隱藏。當(dāng)刪除Docker容器,并通過該鏡像重新啟動時,之前的更改將會丟失。在Docker中,只讀層及在頂部的讀寫層的組合被稱為Union File System(聯(lián)合文件系統(tǒng))。
因此當(dāng)我們創(chuàng)建了一個debian容器實例時(大約150MB),根據(jù)以上的原理,我們再創(chuàng)建1000個debian鏡像能夠重用原來的只讀層,需要的空間還是150MB.
容器本身并不會占任何空間,除非你修改了內(nèi)容。
因此Docker無論創(chuàng)建一個鏡像的多少實例,都不會占據(jù)更多的空間。
因此實際上,我們?yōu)榱藙?chuàng)建數(shù)據(jù)容器而使用busybox反而會占用更多的空間,這個空間就是busybox的鏡像大小。
實際上我們經(jīng)常這樣使用:
- ~: docker run --name mydb-data --entrypoint /bin/echo mysql Data-only container for mydb
- ~: docker run -d --name mydb --volumes-from mydb-data mysql
上面的實例指行/bin/echo mysql Data-only container for mydb,能夠更容易知道這是一個數(shù)據(jù)容器,利于使用grep查找.
【本文是51CTO專欄作者“付廣平”的原創(chuàng)文章,如需轉(zhuǎn)載請通過51CTO獲得聯(lián)系】