您好,登錄后才能下訂單哦!
本篇內容介紹了“docker容器中的uid和gid是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
先來了解下 uid 和 gid
uid 和 gid 由 linux 內核負責管理,并通過內核級別的系統調用來決定是否應該為某個請求授予特權。比如當進程試圖寫入文件時,內核會檢查創建進程的 uid 和 gid,以確定它是否有足夠的權限修改文件。注意,內核使用的是 uid 和 gid,而不是用戶名和組名。
簡單起見,本文中剩下的部分只拿 uid 進行舉例,系統對待 gid 的方式和 uid 基本相同。
很多同學簡單地把 docker 容器理解為輕量的虛擬機,雖然這簡化了理解容器技術的難度但是也容易帶來很多的誤解。事實上,與虛擬機技術不同:同一主機上運行的所有容器共享同一個內核(主機的內核)。容器化帶來的巨大價值在于所有這些獨立的容器(其實是進程)可以共享一個內核。這意味著即使由成百上千的容器運行在 docker 宿主機上,但內核控制的 uid 和 gid 則仍然只有一套。所以同一個 uid 在宿主機和容器中代表的是同一個用戶(即便在不同的地方顯示了不同的用戶名)。
注意,由于普通的用來顯示用戶名的 linux 工具并不屬于內核(比如 id 等命令),所以我們可能會看到同一個 uid 在不同的容器中顯示為不同的用戶名。但是對于相同的 uid 不能有不同的特權,即使在不同的容器中也是如此。
如果你已經了解了 linux 的 user namespace 技術,參考《linux namespace : user》,你需要注意的是到目前為止,docker 默認并沒有啟用 user namesapce,這也是本文討論的情況。筆者會在接下來的文章中介紹如何配置 docker 啟用 user namespace。
容器中默認使用 root 用戶
如果不做相關的設置,容器中的進程默認以 root 用戶權限啟動,下面的 demo 使用 ubuntu 鏡像運行 sleep 程序:
$ docker run -d --name sleepme ubuntu sleep infinity
注意上面的命令中并沒有使用 sudo。筆者在宿主機中的登錄用戶是 nick,uid 為 1000:
在宿主機中查看 sleep 進程的信息:
$ ps aux | grep sleep
sleep 進程的有效用戶名稱是 root,也就是說 sleep 進程具有 root 權限。
然后進入容器內部看看,看到的情況和剛才一樣,sleep 進程也具有 root 權限:
那么,容器內的 root 用戶和宿主機上的 root 用戶是同一個嗎?
答案是:是的,它們對應的是同一個 uid。原因我們在前面已經解釋過了:整個系統共享同一個內核,而內核只管理一套 uid 和 gid。
其實我們可以通過數據卷來簡單的驗證上面的結論。在宿主機上創建一個只有 root 用戶可以讀寫的文件:
然后掛載到容器中:
$ docker run --rm -it -w=/testv -v $(pwd)/testv:/testv ubuntu
在容器中可以讀寫該文件:
我們可以通過 dockerfile 中的 user 命令或者是 docker run 命令的 --user 參數指定容器中進程的用戶身份。下面我們分別來探究這兩種情況。
在 dockerfile 中指定用戶身份
我們可以在 dockerfile 中添加一個用戶 appuser,并使用 user 命令指定以該用戶的身份運行程序,dockerfile 的內容如下:
from ubuntu run useradd -r -u 1000 -g appuser user appuser entrypoint ["sleep", "infinity"]
編譯成名稱為 test 的鏡像:
$ docker build -t test .
用 test 鏡像啟動一個容器:
$ docker run -d --name sleepme test
在宿主機中查看 sleep 進程的信息:
這次顯示的有效用戶是 nick,這是因為在宿主機中,uid 為 1000 的用戶的名稱為 nick。再進入到容器中看看:
$ docker exec -it sleepme bash
容器中的當前用戶就是我們設置的 appuser,如果查看容器中的 /etc/passwd 文件,你會發現 appuser 的 uid 就是 1000,這和宿主機中用戶 nick 的 uid 是一樣的。
讓我們再創建一個只有用戶 nick 可以讀寫的文件:
同樣以數據卷的方式把它掛載到容器中:
$ docker run -d --name sleepme -w=/testv -v $(pwd)/testv:/testv test
在容器中 testfile 的所有者居然變成了 appuser,當然 appuser 也就有權限讀寫該文件。
這里到底發生了什么?而這些又這說明了什么?
首先,宿主機系統中存在一個 uid 為 1000 的用戶 nick。其次容器中的程序是以 appuser 的身份運行的,這是由我們通過 user appuser 命令在 dockerfile 程序中指定的。
事實上,系統內核管理的 uid 1000 只有一個,在宿主機中它被認為是用戶 nick,而在容器中,它則被認為是用戶 appuser。
所以有一點我們需要清楚:在容器內部,用戶 appuser 能夠獲取容器外部用戶 nick 的權利和特權。在宿主機上授予用戶 nick 或 uid 1000 的特權也將授予容器內的 appuser。
從命令行參數中自定用戶身份
我們還可以通過 docker run 命令的 --user 參數指定容器中進程的用戶身份。比如執行下面的命令:
$ docker run -d --user 1000 --name sleepme ubuntu sleep infinity
因為我們在命令行上指令了參數 --user 1000,所以這里 sleep 進程的有效用戶顯示為 nick。進入到容器內部看一下:
$ docker exec -it sleepme bash
這是個什么情況?用戶名稱居然顯示為 "i have no name!"!去查看 /etc/passwd 文件,里面果然沒有 uid 為 1000 的用戶。即便沒有用戶名稱,也絲毫不影響該用戶身份的權限,它依然可以讀寫只有 nick 用戶才能讀寫的文件,并且用戶信息也由 uid 代替了用戶名:
需要注意的是,在創建容器時通過 docker run --user 指定的用戶身份會覆蓋掉 dockerfile 中指定的值。
我們重新通過 test 鏡像來運行兩個容器:
$ docker run -d test
查看 sleep 進程信息:
$ docker run --user 0 -d test
再次查看 sleep 進程信息:
指定了 --urser 0 參數的進程顯示有效用戶為 root,說明命令行參數 --user 0 覆蓋掉了 dockerfile 中 user 命令的設置。
“docker容器中的uid和gid是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。