日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

给一个正在运行的Docker容器动态添加Volume

發(fā)布時間:2025/3/15 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 给一个正在运行的Docker容器动态添加Volume 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

給一個正在運(yùn)行的Docker容器動態(tài)添加Volume
本文轉(zhuǎn)自:http://dockone.io/article/149

【編者的話】之前有人問我Docker容器啟動之后還能否再掛載卷,考慮到mnt命名空間的工作原理,我一開始認(rèn)為這很難實(shí)現(xiàn)。不過現(xiàn)在Petazzoni通過使用nsenter和綁定掛載實(shí)現(xiàn)了這個需求,你可以在你的環(huán)境中測試下。

之前有人問我Docker容器啟動之后還能否再掛載卷,考慮mnt命名空間的工作原理,我一開始認(rèn)為這很難實(shí)現(xiàn)。不過現(xiàn)在我認(rèn)為是它實(shí)現(xiàn)的。

簡單來說,要想將磁盤卷掛載到正在運(yùn)行的容器上,我們需要:

  • 使用nsenter將包含這個磁盤卷的整個文件系統(tǒng)mount到臨時掛載點(diǎn)上;
  • 從我們想當(dāng)作磁盤卷使用的特定文件夾中創(chuàng)建綁定掛載(bind mount)到這個磁盤卷的位置;
  • umount第一步創(chuàng)建的臨時掛載點(diǎn)。

注意事項(xiàng)

在下面的示例中,我故意包含了$符號來表示這是Shell命令行提示符,以幫助大家區(qū)分哪些是你需要輸入的,哪些是機(jī)器回復(fù)的。有一些多行命令,我也繼續(xù)用>。我知道這樣使得例子里的命令無法輕易得被拷貝粘貼。如果你想要拷貝粘貼代碼,請查看文章最后的示例腳本。

詳細(xì)步驟

下面示例的前提是你已經(jīng)使用如下命令啟動了一個簡單的名為charlie的容器:

$?docker?run?--name?charlie?-ti?ubuntu?bash


我們需要做的是將宿主文件夾/home/jpetazzo/Work/DOCKER/docker掛載到容器里的/src目錄。好了,讓我們開始吧。

nsenter

首先,我們需要nsenter以及docker-enter幫助腳本。為什么?因?yàn)槲覀円獜娜萜髦衜ount文件系統(tǒng)。由于安全性的考慮,容器不允許我們這么做。使用nsenter,我們可以突破上述安全限制,在容器的上下文(嚴(yán)格地說,是命名空間)中運(yùn)行任意命令。當(dāng)然,這必須要求擁有Docker宿主機(jī)的root權(quán)限。
nsenter最簡單的安裝方式是和docker-enter腳本關(guān)聯(lián)執(zhí)行:

$?docker?run?--rm?-v?/usr/local/bin:/target?jpetazzo/nsenter


更多細(xì)節(jié),請查看nsenter項(xiàng)目主頁。

找到文件系統(tǒng)

我們想要在容器里掛載包含宿主文件夾(/home/jpetazzo/Work/DOCKER/docker)的文件系統(tǒng)。那我們就需要找出哪個文件系統(tǒng)包含這個目錄。

首先,我們需要canonicalize(或者解除引用)文件,以防這是一個符號鏈接,或者它的路徑包含符號鏈接:

$?readlink?--canonicalize?/home/jpetazzo/Work/DOCKER/docker /home/jpetazzo/go/src/github.com/docker/docker


哈,這的確是一個符號鏈接!讓我們將其放入一個環(huán)境變量中:

$?HOSTPATH=/home/jpetazzo/Work/DOCKER/docker $?REALPATH=$(readlink?--canonicalize?$HOSTPATH)


接下來,我們需要找出哪個文件系統(tǒng)包含這個路徑。我們使用一個有點(diǎn)讓人意想不到的工具來做,它就是df:

$?df?$REALPATH Filesystem?????1K-blocks??????Used?Available?Use%?Mounted?on /sda2??????????245115308?156692700??86157700??65%?/home/jpetazzo


使用-P參數(shù)(強(qiáng)制使用POSIX格式,以防是exotic df,或者是其他人在Solaris或者BSD系統(tǒng)上裝Docker時運(yùn)行的df),將結(jié)果也放到一個變量里:

$?FILESYS=$(df?-P?$REALPATH?|?tail?-n?1?|?awk?'{print?$6}')


找到文件系統(tǒng)的設(shè)備(和sub-root)

現(xiàn)在,系統(tǒng)里已經(jīng)沒有綁定掛載(bind mounts)和BTRFS子卷了,我們僅僅需要查看/proc/mounts,找到對應(yīng)于/home/jpetazzo文件系統(tǒng)的設(shè)備就可以了。但是在我的系統(tǒng)里,/home/jpetazzo是BTRFS池的子卷,要想得到子卷的信息(或者bind mount信息),需要查看/proc/self/moutinfo。

如果你從來沒有聽說過mountinfo,可以查看內(nèi)核文檔的proc.txt。

首先,得到文件系統(tǒng)設(shè)備信息:

$?while?read?DEV?MOUNT?JUNK >?do?[?$MOUNT?=?$FILESYS?]?&&?break >?done?</proc/mounts $?echo?$DEV /dev/sda2


接下來,得到sub-root信息(比如,已掛載文件系統(tǒng)的路徑):

$?while?read?A?B?C?SUBROOT?MOUNT?JUNK >?do?[?$MOUNT?=?$FILESYS?]?&&?break >?done?<?/proc/self/mountinfo? $?echo?$SUBROOT /jpetazzo


很好。現(xiàn)在我們知道需要掛載/dev/sda2。在文件系統(tǒng)內(nèi)部,進(jìn)入/jpetazzo,從這里可以得到到所需文件的剩余路徑(示例中是/go/src/github.com/docker/docker)。
讓我們計(jì)算出剩余路徑:

$?SUBPATH=$(echo?$REALPATH?|?sed?s,^$FILESYS,,)

?

注意:這個方法只適用于路徑里沒有符號“,”的。如果你的路徑里有“,”并且想使用本文方法掛載目錄,請告訴我。(我需要調(diào)用Shell Triad來解決這個問題:jessie,soulshake,tianon?)

在進(jìn)入容器之前最后需要做的是找到這個塊設(shè)備的主和次設(shè)備號。可以使用stat:

$?stat?--format?"%t?%T"?$DEV 8?2


注意這兩個數(shù)字是十六進(jìn)制的,我們之后需要的是二進(jìn)制。可以這么轉(zhuǎn)換:

$?DEVDEC=$(printf?"%d?%d"?$(stat?--format?"0x%t?0x%T"?$DEV))

?

總結(jié)

還有最后一步。因?yàn)槟承┪覠o法解釋的原因,一些文件系統(tǒng)(包括BTRFS)在掛載多次之后會更新/proc/mounts里面的設(shè)備字段。也就是說,如果我們在容器里創(chuàng)建了名為/tmpblkdev的臨時塊設(shè)備,并用其掛載我們自己的文件系統(tǒng),那么文件系統(tǒng)(在宿主機(jī)器里!)會顯示為/tmpblkdev,而不是/dev/sda2。這聽起來無所謂,但實(shí)際上這會讓之后試圖得到文件系統(tǒng)塊設(shè)備的操作都失敗。

長話短說,我們想要確保塊設(shè)備節(jié)點(diǎn)在容器里位于和宿主機(jī)器上的同一個路徑下。

需要這么做:

$?docker-enter?charlie?--?sh?-c?\ >?"[?-b?$DEV?]?||?mknod?--mode?0600?$DEV?b?$DEVDEC"


創(chuàng)建臨時掛載點(diǎn)掛載文件系統(tǒng):

$?docker-enter?charlie?--?mkdir?/tmpmnt $?docker-enter?charlie?--?mount?$DEV?/tmpmnt


確保卷掛載點(diǎn)存在,bind mount卷:

$?docker-enter?charlie?--?mkdir?-p?/src $?docker-enter?charlie?--?mount?-o?bind?/tmpmnt/$SUBROOT/$SUBPATH?/src


刪除臨時掛載點(diǎn):

$?docker-enter?charlie?--?umount?/tmpmnt $?docker-enter?charlie?--?rmdir?/tmpmnt


(我們并不清除設(shè)備節(jié)點(diǎn)。一開始就檢查設(shè)備是否存在可能有點(diǎn)多余,但是現(xiàn)在再檢查就已經(jīng)很復(fù)雜了。)

大功告成!

讓一切自動化

下面這段可以直接拷貝粘貼了。

#!/bin/sh set?-e CONTAINER=charlie HOSTPATH=/home/jpetazzo/Work/DOCKER/docker CONTPATH=/srcREALPATH=$(readlink?--canonicalize?$HOSTPATH) FILESYS=$(df?-P?$REALPATH?|?tail?-n?1?|?awk?'{print?$6}')while?read?DEV?MOUNT?JUNK do?[?$MOUNT?=?$FILESYS?]?&&?break? done??</proc/mounts [?$MOUNT?=?$FILESYS?]?#?Sanity?check!\while?read?A?B?C?SUBROOT?MOUNT?JUNK \do?[?$MOUNT?=?$FILESYS?]?&&?break \done?<?/proc/self/mountinfo? [?$MOUNT?=?$FILESYS?]?#?Moar?sanity?check!SUBPATH=$(echo?$REALPATH?|?sed?s,^$FILESYS,,) DEVDEC=$(printf?"%d?%d"?$(stat?--format?"0x%t?0x%T"?$DEV))docker-enter?$CONTAINER?--?sh?-c?\"[?-b?$DEV?]?||?mknod?--mode?0600?$DEV?b?$DEVDEC" docker-enter?$CONTAINER?--?mkdir?/tmpmnt docker-enter?$CONTAINER?--?mount?$DEV?/tmpmnt docker-enter?$CONTAINER?--?mkdir?-p?$CONTPATH docker-enter?$CONTAINER?--?mount?-o?bind?/tmpmnt/$SUBROOT/$SUBPATH?$CONTPATH docker-enter?$CONTAINER?--?umount?/tmpmnt docker-enter?$CONTAINER?--?rmdir?/tmpmnt

?

狀態(tài)和限制

上述方法不適用于不基于塊設(shè)備的文件系統(tǒng),只有在/proc/mounts能正確得到塊設(shè)備節(jié)點(diǎn)(上面談到,并不總是能正確得到)的時候才能起作用。另外,我只測試了我自己的環(huán)境,沒有在云實(shí)例之類的環(huán)境里測試過,但是我很想知道在那里是否適用。

原文鏈接:Attach a volume to a container while it is running?(翻譯:崔婧雯 校對:李穎杰)

===========================
譯者介紹
崔婧雯,現(xiàn)就職于VMware,高級軟件工程師,負(fù)責(zé)桌面虛擬化產(chǎn)品的質(zhì)量保證工作。曾在IBM WebSphere業(yè)務(wù)流程管理軟件擔(dān)任多年系統(tǒng)測試工作。對虛擬化,中間件技術(shù)有濃厚的興趣。








本文轉(zhuǎn)自秋楓博客園博客,原文鏈接:http://www.cnblogs.com/rwxwsblog/p/5437478.html,如需轉(zhuǎn)載請自行聯(lián)系原作者

總結(jié)

以上是生活随笔為你收集整理的给一个正在运行的Docker容器动态添加Volume的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。