一個(gè)因Docker容器掛載引發(fā)的事故
背景
使用 docker 部署的 nginx,并且已經(jīng)配置了文件掛載,參數(shù)如下:
- -v /deploy/nginx/conf.d/doc.crt:/etc/nginx/conf.d/doc.crt
- -v /deploy/nginx/conf.d/doc.key:/etc/nginx/conf.d/doc.key
- -v /deploy/nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf
后續(xù)因?yàn)榧夹g(shù)原因,需要將一個(gè) location 加上 *.html 禁用緩存,如下配置
if ($request_filename ~* .*\\.(htm|html)$) {
add_header Cache-Control "no-store";
}
于是就在宿主機(jī)上直接修改 /deploy/nginx/conf.d/default.conf 文件。
然后運(yùn)行 docker exec -it pc-nginx nginx -s reload,使配置生效。
但是實(shí)際測(cè)試結(jié)果并沒(méi)有生效
還以為是配置加的不對(duì),花了好長(zhǎng)時(shí)間,改了幾種方式,結(jié)果都不行。
直到進(jìn)入容器內(nèi),查看容器內(nèi)的文件發(fā)現(xiàn),文件根本就沒(méi)有改動(dòng)?。?!
重啟了這個(gè)容器,配置文件才進(jìn)行了更新,問(wèn)題得到解決。
思考
docker容器的掛載難道不是生效,而是要容器啟動(dòng)的時(shí)候才會(huì)更新?
肯定不是這樣,容器內(nèi)產(chǎn)生的日志內(nèi)容,在容器外可以實(shí)時(shí)查看,難道是內(nèi)->外是實(shí)時(shí),外->內(nèi) 是啟動(dòng)的時(shí)候才加載?
如果是這樣,那我一直以為的docker掛載是理解錯(cuò)了嗎,越想越不對(duì)???
探索
經(jīng)過(guò)一番查閱資料,發(fā)現(xiàn)了這個(gè):
Docker 中,mount volume 的原理是借用了 Linux Namespace 中的 Mount NameSpace,隔離系統(tǒng)中不同進(jìn)程的掛載點(diǎn)視圖,實(shí)際文件是沒(méi)有變化。
在container中,bash 實(shí)際就是一個(gè)運(yùn)行在宿主機(jī)上的進(jìn)程,被Docker用Linux分別隔離了 Mount Namespace、UTS Namespace、IPC Namespace、PID Namespace、Network Namespace和User Namespace,使得它看上去好像運(yùn)行在了一個(gè)獨(dú)立的、相對(duì)隔離的系統(tǒng)上,但實(shí)際它的一切資源都是宿主機(jī)在不同Namespace中的一個(gè)投影,文件也不例外。
Linux中,證明文件是否相同的根本途徑是,使用 stat命令,判斷其 inode,如果兩個(gè)文件的inode相同,兩個(gè)文件必定為同一文件,從而兩個(gè)文件的內(nèi)容也必然相同。
docker本身不支持直接映射文件,使用docker映射文件時(shí)可能會(huì)出現(xiàn)問(wèn)題 。
實(shí)踐
復(fù)現(xiàn)場(chǎng)景,驗(yàn)證問(wèn)題
- 創(chuàng)建文件
mkdir -p /opt/nginx
cd /opt/nginx
vi demo.conf
nginx內(nèi)容如下:
server {
listen 80;
server_name gateway.cn;
location / {
proxy_pass http://localhost:7001/;
}
}
- 創(chuàng)建2個(gè)容器,一個(gè)映射目錄,一個(gè)映射文件
docker run --name n1-dir -v /opt/nginx:/etc/nginx/conf.d -d nginx
docker run --name n2-file -v /opt/nginx/demo.conf:/etc/nginx/conf.d/demo.conf -d nginx
- 再開啟兩個(gè) shell ,進(jìn)入容器內(nèi),查看文件
docker exec -ti n1-dir /bin/bash
docker exec -ti n2-file /bin/bash
cat /etc/nginx/conf.d/demo.conf
- 修改外部文件
- 簡(jiǎn)單修改,加一行注釋# fadsff
- 重新查看文件
- 但是得到了相同的結(jié)果,這與預(yù)期不符,使用stat命令,容器外和2個(gè)容器內(nèi)的demo.conf 文件都是同一個(gè)inode
和線上的環(huán)境得到的結(jié)果不一致,這就很令人費(fèi)解。想到線上的環(huán)境不是用的root賬號(hào)部署的,難道和用戶也有關(guān)系?
創(chuàng)建demo用戶,再次嘗試
圖片
重試剛才的步驟,得到結(jié)果:
n3
圖片
n4
圖片
得到結(jié)果,在掛載conf.d 目錄時(shí),文件可以得到正常更新,但是如果直接掛載文件,文件的內(nèi)容并不會(huì)實(shí)時(shí)更新。
小結(jié)
docker部署容器需要進(jìn)行掛載時(shí),使用掛載目錄的方式,不要直接掛載文件。 掛載目錄不會(huì)出現(xiàn)宿主機(jī)文件更新,而容器中文件沒(méi)有更新的問(wèn)題。