
我一直在論壇上搜索,以了解如何允許通常僅由 root 或其本身允許的用戶運行命令/進程。
那裡有一些很好的資源,但沒有一個對我的實例有幫助,我希望 Ubuntu 天才之一能為我指明正確的方向。
我已經使用 apt-get install cpulimit 安裝了 cpulimit,該軟體包增加了限制特定進程的 cpu 使用率的功能。安裝後,我可以在 /usr/bin/cpulimit 中看到安裝。
我現在必須在運行用戶處理的進程時運行 cpulimit,在該進程代碼中。
我在 visudo 文件中添加了幾次嘗試,所有變體:
{USER} ALL=(ALL:ALL) NOPASSWD:/usr/bin/cpulimit
但是,當我運行命令時(限制=百分比):
cpulimit --pid 159845 --limit 60
響應是:
Error: Process 159845 detected, but you don't have permission to control it.
其中159845是正確的進程,它是mysqld。
我可以運行 top -i 並看到該進程是由用戶 mysql 運行的:
PID | 使用者 | 公關 | 你 | 虛擬實境技術 | RES | SHR | S | %中央處理器 | %MEM | 時間+ | 命令 |
---|---|---|---|---|---|---|---|---|---|---|---|
159845 | mysql | 20 | 0 | 1460764 | 608076 | 3772 | S | 15.6 | 29.9 | 862:34.15 | mysqld |
這讓我認為沒有必要添加允許{USER} 運行cpulimit 的初始visudo 行,但更重要的是,當{USER} 在針對有問題的進程159845 時運行cpulimit 時,這是不允許的,因為{USER}不允許沒有權限接觸 mysql 的進程。
我如何以{USER}身份在mysql的進程mysql上運行cpulimit?
GENERIC:如何在不同「使用者/帳號/角色」擁有的進程上以 {USER} 身分執行指令?
編輯:該指令正在 {USER} 的 crontab 中觸發的腳本中執行。
編輯2:以 sudo 運行命令後,如下所示:
$limit_mysqld_cpu_usage = "sudo -u mysql cpulimit --pid " . $mysqld_id_exe_output[0] . " --limit " . $cpu_limit_as_perc_of_cpus;
// Run command
exec($limit_mysqld_cpu_usage, $limit_mysqld_cpu_usage_output, $limit_mysqld_cpu_usage_id);
腳本似乎凍結了,之前它會繼續執行腳本。過了這一點的腳本經過嘗試和測試,可以很好地工作,而無需觸發上述命令。
Q:為什麼這不執行然後繼續執行腳本的其餘部分?
答:因為命令運行並且它開始監視該進程,防止它在我們期望返回時繼續執行程式碼,所以它將永遠掛在這裡。
Q:如何在背景觸發 cpulimit 命令的 exec(),或無需在繼續之前觀察並等待回應?
A:如果使用此函數啟動程序,為了使其繼續在背景運行,必須將程式的輸出重定向到檔案或另一個輸出流。如果不這樣做將導致 PHP 掛起,直到程式執行結束。
http://php.net/manual/en/function.exec.php
因此,本質上我們需要 > 到另一個空間,例如 /dev/null 並透過附加 & 來在後台運行該進程。就我而言,該命令需要如下所示:
sudo -u {USER} cpulimit --pid {ID} --limit 60 > /dev/null &"
我還切換了 exec() 來代替 shell_exec() ,它似乎不需要所有參數或產生如此繁重的回應:
shell_exec(sudo -u {USER} cpulimit --pid {ID} --limit 60 > /dev/null &");
答案1
在@steeldriver 的幫助下,我找到了解決問題的方法。
按時間順序回答這個問題:
如何在不同「使用者/帳戶/角色」擁有的進程上以 {USER} 身分執行命令?
為了在充當 {USER} 的同時在 {ALTERNATIVE_USER} 上運行進程,我們必須使用 sudo,然後您可以指定哪個用戶應該運行該命令,如下所示:
sudo -u {ALTERNATIVE_USER} {COMMAND}
如何觸發 {COMMAND} 在後台運行以允許當前腳本繼續?
當進程被觸發時,腳本似乎會凍結,但它並沒有凍結,它只是在等待新觸發的命令結束,而它不會,因為它作用於最初觸發的進程,而該進程永遠不會結束。
為此,當我們啟動掛起的命令時,我們必須為其指定一個出口,以便它有地方可以掛起。這可以透過指向替代位置來完成,在我的實例中我使用了> /dev/null
.
最後,我需要做的是在後台運行它,這可以透過附加&
.
最後一點,特別是對我來說,我不希望收到回應,我只是希望命令運行並按照我所說的那樣執行,因此我將 exec() 換成了 shell_exec()。
shell_exec(sudo -u {USER} cpulimit --pid {ID} --limit 60 /dev/null &");