應該如何使用時間命名空間?
我以為我可以做類似的事情:
sudo unshare -T bash -c 'date -s "$1" && foobar' sh "$(date -d -1day)"
所以
foobar
會看到與系統其餘部分不同的系統時間。但是,似乎不包含系統時間的變化。它改變了整個系統的系統時間。這篇 LWN 文章似乎暗示這個命名空間是為了我試圖給它的用途。
調整系統時間的系統呼叫將在根時間命名空間之外呼叫時,改為調整特定於命名空間的偏移量。
看著
strace date -s ...
,我在其他輸出中看到:clock_settime(CLOCK_REALTIME, {tv_sec=1619044910, tv_nsec=0}) = 0
但是,閱讀
time_namespaces(7)
:這會影響測量這些時鐘的各種 API,包括:clock_gettime(2)、clock_nanosleep(2)、nanosleep(2)、timer_settime(2)、timerfd_settime(2) 和 /proc/uptime。
我看到它沒有提到
clock_settime(2)
。“包括”的措辭告訴我,這可能不是完整的列表,但也許是。我也不明白
--boottime
/--monotonic
。看著clock_settime(2)
,我看到:CLOCK_MONOTONIC 一個不可設置的系統範圍的時鐘,代表單調時間——正如 POSIX 所描述的——“過去某個未指定的時間點”。在 Linux 上,該點對應於系統自啟動以來執行的秒數。
CLOCK_BOOTTIME(自 Linux 2.6.39 起;Linux 特定)與 CLOCK_MONOTONIC 相同的不可設置的系統範圍時鐘,除了它還包括系統掛起的任何時間。
但是,在嘗試它們時,它們似乎並沒有改變
uptime
:$ uptime -s 2021-04-10 10:30:45 $ sudo unshare -T --boottime 1000000000 uptime -s 2021-04-10 10:30:45 $ sudo unshare -T --monotonic 1000000000 uptime -s 2021-04-10 10:30:45 $ sudo unshare -T --boottime -100000 uptime -s 2021-04-10 10:30:45 $ sudo unshare -T --monotonic -100000 uptime -s 2021-04-10 10:30:45
我從中
strace uptime
看到它讀取/proc/uptime
而不是呼叫clock_gettime(2)
,並且/proc/uptime
似乎不受unshare
呼叫及其偏移量的影響,儘管文件中time_namespaces(7)
說它會影響/proc/uptime
我上面引用的內容。這個命名空間應該如何使用?我似乎找不到任何會受
unshare --time
.
我在您的推理中看到三個需要澄清的要點:
第一個是取消共享時間命名空間會影響從那時起由呼叫
unshare(2)
. 呼叫程序本身不受影響。這有點像 PID 命名空間,與目前為止的其他命名空間類型不同。然而,呼叫程序可能仍會進入那個新創建的時間命名空間,只是如果它想這樣做,那麼它也必須setns(2)
(即nsenter(1)
用 CLI 用語)自己進入它。所有這一切意味著
unshare -T
您一直在執行的命令從未真正將這些命令移動到新創建的時間命名空間中。您可以添加-f
選項以unshare(1)
使其將指定的命令作為其子項而不是execve(2)
自身執行到其中。這樣,指定的命令將存在於該時間命名空間中。自然,正如您一直在做的那樣,您還希望指定
--boottime
和/或--monotonic
選項來“扭曲”該時間命名空間對這些時鐘的願景,否則子時間命名空間將與其父時間命名空間具有相同的願景。因此,在我的機器上,以您的嘗試為例:
$ sudo unshare -T --boottime 1000000000 uptime -s 2021-04-23 11:07:10 $ sudo unshare -fT --boottime 1000000000 uptime -s 1989-08-15 09:20:30 $
除了使用這些方便的選項之外,您還可以
/proc/self/timens_offsets
手動設置文件,只要您在生成任何子項之前執行此操作即可。上面的“手動”等價物將類似於:$ sudo unshare -T dash -c 'echo "boottime 1000000000 0" > /proc/self/timens_offsets; uptime -s' 1989-08-15 09:20:30
在這裡,我
dash
只是使用一個更精簡的 shell,它當然不會為自己的引導程序生成子程序,並且還有一個內置的echo(以免為它生成子程序)來設置自己的timens_offsets
文件。從那時起,所有後續執行的命令都dash
將看到“扭曲”的引導時間。但如果您願意,則不會
exec uptime -s
,因為這將替換dash
為uptime
因此仍然生活在父時間命名空間中,除非您也nsenter(1)
事先。考慮:$ sudo unshare -T dash -c 'echo "boottime 1000000000 0" > /proc/self/timens_offsets; exec uptime -s' 2021-04-23 11:07:10 $ sudo unshare -T dash -c 'echo "boottime 1000000000 0" > /proc/self/timens_offsets; exec nsenter --time=/proc/self/ns/time_for_children uptime -s' 1989-08-15 09:20:30 $
我認為需要澄清的第二點
date
是專門關於命令的。請注意,僅從核心 v5.11(以及目前最新的 v5.12-rc8)開始
CLOCK_BOOTIME
,並且CLOCK_MONOTONIC
可以在新的時間命名空間中“變形”,正如以下註釋中所述time_namespaces(7)
:請注意,時間命名空間不會虛擬化 CLOCK_REALTIME 時鐘。由於核心中的複雜性和成本的原因,避免了該時鐘的虛擬化。
但是,您可以從命令中註意到,
date
具體作用於時鐘。這意味著,在我寫這篇文章的時候,這個命令仍然完全不受它所在的時間命名空間的影響。CLOCK_REALTIME``strace date -s ...``date
一個確實受時間命名空間影響的命令的快速範例,因為它引用
CLOCK_MONOTONIC
isdmesg
。嘗試類似:$ sudo unshare -fT --monotonic 1000000000 dmesg -T
第三點似乎是關於這句話:
調整系統時間的系統呼叫將在根時間命名空間之外呼叫時,改為調整特定於命名空間的偏移量。
誠然,這有點誤導,因為(目前)顯然不可能**隨意改變時間命名空間對時間的看法,因為
CLOCK_MONOTONIC
兩者實際上CLOCK_BOOTTIME
都是不可改變的。這兩個時鐘是不可改變的。因此,唯一允許的操作是在任何程序加入該時間命名空間之前將它們“引導”到某個偏移量(與初始時間命名空間相關),這樣任何程序都不會經歷這兩個時鐘的跳躍(甚至向前)。
這就是為什麼
unshare(2)
不將呼叫程序移動到新創建的時間命名空間中的原因:這樣它(或其他一些程序)就有機會指定“引導”偏移量,實際上在任何一個程序進入後無法更改時間命名空間。計算正確的偏移量顯然是一項微妙的操作,這是“命名空間管理器”的工作。