本文介绍普通用户运行容器时,绑定81端口出错的解决过程。
起因
由于之前亲自将测试服务器搞挂了,此后,即使是测试环境服务器,也不敢轻易使用root权限了。由于有大量程序使用docker容器部署,于是做了一系列的权限修改。其中某个Nginx容器使用普通用户启动时,报错了,信息如下:
nginx: [emerg] bind() to 0.0.0.0:81 failed (13: Permission denied)
使用ss和netstat等命令确认,宿主机 81 端口并没有被占用,但容器内就是不能绑定该端口。注意,上述报错的是 "Permission denied",没有提到端口占用问题。问了AI,其回复曰:在 Linux 系统中,绑定低端口(小于1024)或受限制端口需要特定权限。当容器以非 root 用户运行时,进程仍然可能因为缺少 CAP_NET_BIND_SERVICE 能力而无法绑定端口。笔者在所使用的docker-compose.yml文件中配置了 user: "1000:1000",因此容器内进程没有 root 权限------因为上述原因,如果我用root权限,生成的日志或其它文件变成root,权限不统一,维护不方便。另外,AI也提到说缺少了绑定端口的能力,即Linux Capabilities 机制限制了非root用户绑定端口的能力,Nginx因此报出permission denied错误。
解决过程
先确认端口是否被占用:
ss -tlnp | grep :81
输出为空,说明 81 端口未被占用,排除端口冲突。
再到容器里运行id查询身份:
docker exec -it <容器名> id
输出显示 uid=1000 而非 uid=0(root),即容器以普通用户运行。
除了root权限运行外,可以修改 Nginx 配置,让其监听 1024 以上的高位端口(如 8081),示例:
upstream xxxx {
server 172.18.18.168:8081 weight=1;
}
server {
listen 8081;
listen [::]:8081;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
proxy_pass http://onlinefee;
}
# 转发到后端
location /proxy {
proxy_pass http://xxxx
# 标准代理头设置
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
access_log /var/log/nginx/fee_pare2_access.log feeextended;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
再在docker-compose.yaml文件里做端口映射:
yaml
services:
nginx:
image: your-nginx-image
user: "1000:1000"
ports:
- "81:8081" # nginx使用8081端口
小结
本文不涉及过多的技术,只是笔者第一次遇到,因此记录。