Docker中使用gosu的方法詳解
Docker中使用gosu
為什么要用 gosu?
在 Docker 鏡像中啟動服務(wù)時,我們通常不希望以 root 身份運行主進程。
問題:
- 構(gòu)建鏡像時通常需要 root 權(quán)限;
- 啟動時希望進程使用普通用戶運行;
- 容器中使用
sudo會產(chǎn)生額外的中間進程,導(dǎo)致信號轉(zhuǎn)發(fā)不正常; - 最終可能出現(xiàn)僵尸進程、容器無法優(yōu)雅退出等問題。
gosu 是一個非常輕量的工具,功能類似 sudo,但不會產(chǎn)生額外進程,非常適合在 Docker 容器中用來切換用戶。
注意事項
- 創(chuàng)建專用普通用戶,不要直接使用 root。
- 在 entrypoint 中使用 gosu 切換用戶,不要用 sudo。
- 使用 exec 啟動主進程,保證 PID=1 是應(yīng)用本身。
- 正確接收 SIGTERM 信號,避免僵尸進程。
- 不要在 Docker 中濫用 sudo。
sudo vs gosu:真實對比
使用 gosu
docker run --rm gosu/alpine gosu root ps aux
輸出:
PID USER TIME COMMAND
1 root 0:00 ps aux
ps命令的 PID 是 1,容器內(nèi)只有一個進程。- 這樣當(dāng)宿主機發(fā)送
SIGTERM信號時,應(yīng)用能直接接收到。
使用 sudo
docker run --rm ubuntu:trusty sudo ps aux
輸出:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 46012 1772 ? Rs 12:05 0:00 sudo ps aux
root 6 0.0 0.0 15568 1140 ? R 12:05 0:00 ps aux
- 容器內(nèi)出現(xiàn)兩個進程,PID=1 被
sudo占用。 - 應(yīng)用進程的 PID 不為 1,無法直接接收信號。
- 當(dāng)執(zhí)行
docker stop時,信號發(fā)送給的是sudo,而不是應(yīng)用進程,可能導(dǎo)致應(yīng)用殘留為僵尸進程。
對比:
| 項目 | gosu | sudo |
|---|---|---|
| 進程數(shù) | 1 | 2 |
| PID=1 | 應(yīng)用進程 | sudo |
| 信號轉(zhuǎn)發(fā) | 正常 | 不正常 |
| 僵尸進程風(fēng)險 | 低 | 高 |
| 適合容器使用 | 是 | 否 |
Dockerfile 安裝 gosu
在 Dockerfile 中添加如下步驟即可:
FROM ubuntu:22.04 # 安裝 gosu RUN apt-get update && apt-get install -y gosu curl ca-certificates && rm -rf /var/lib/apt/lists/* # 創(chuàng)建普通用戶 RUN groupadd -r tempuser && useradd -r -g tempuser tempuser # 拷貝入口腳本 COPY entrypoint.sh /usr/local/bin/entrypoint.sh RUN chmod +x /usr/local/bin/entrypoint.sh # 驗證 gosu 是否工作 RUN gosu nobody true ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
entrypoint.sh 的寫法
entrypoint.sh 是容器啟動腳本。
#!/usr/bin/env bash
set -e
# 使用 gosu 切換用戶身份
if [ "$1" = "start-app" ]; then
echo "Running application as tempuser..."
exec gosu tempuser /app/my_server
fi
# 如果有其他命令,直接執(zhí)行
exec "$@"注意:exec 會讓當(dāng)前 shell 被新進程取代,保證應(yīng)用進程的 PID=1。
構(gòu)建 & 運行容器
docker build -t myapp . docker run --rm -p 8080:8080 myapp start-app
容器內(nèi):
/app/my_server的 PID = 1- 收到
docker stop的信號時,能正確退出 - 不會殘留
sudo或 shell 僵尸進程
信號量與僵尸進程問題
容器啟動時 PID=1 的進程非常特殊,它負(fù)責(zé)接收來自宿主機的信號(例如 SIGTERM、SIGINT)。
- 如果 PID=1 是
sudo,信號不會傳給應(yīng)用; - 如果 PID=1 是應(yīng)用進程本身,就能優(yōu)雅退出;
- 使用
exec+gosu可以保證 PID=1 是你的應(yīng)用; - 避免使用 shell 包一層后
&運行后臺進程的錯誤做法。
常見問題
| 問題 | 原因 | 解決方法 |
|---|---|---|
| 容器退出時殘留僵尸進程 | PID=1 不是應(yīng)用進程 | 使用 exec + gosu |
| docker stop 不生效 | 信號被 sudo 攔截 | 不使用 sudo,PID=1 改為應(yīng)用 |
| gosu 報權(quán)限錯誤 | 二進制無執(zhí)行權(quán)限 | chmod +x /usr/local/bin/gosu |
| 切換用戶失敗 | 用戶不存在 | 使用 useradd 創(chuàng)建對應(yīng)用戶 |
參考資料
- gosu 官方 GitHub
- Docker 官方最佳實踐
- Docker 官方最佳實踐中文
- Why use exec in entrypoint?(Stack Overflow)
- CSDN docker與gosu
到此這篇關(guān)于Docker中使用gosu的文章就介紹到這了,更多相關(guān)docker使用gosu內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
win7環(huán)境下Docker快速構(gòu)建及阿里云容器加速配置詳解
這篇文章主要介紹了win7環(huán)境下Docker快速構(gòu)建及阿里云容器加速配置詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
Docker?Compose最常用命令(直接復(fù)制用)
Docker Compose是Docker官方提供的一個用于管理多個容器的工具,可以使用docker-compose.yml文件定義和運行多容器應(yīng)用,這篇文章主要介紹了Docker?Compose最常用命令的相關(guān)資料,需要的朋友可以參考下2025-11-11
docker部署nginx訪問宿主機服務(wù)并使用緩存的操作方法
這篇文章主要介紹了docker部署nginx訪問宿主機服務(wù)并使用緩存的操作方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,感興趣的朋友一起看看吧2024-04-04

