IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Dockerfile之gosu浅析 -> 正文阅读

[系统运维]Dockerfile之gosu浅析

权限分析

  • Docker容器运行的时候,如果没有专门指定user, 默认以root用户运行。我们镜像里没有指定user,容器里的执行用户的id是0,输出文件的权限也是0
# 以ROOT用户执行docker查看权限情况如下,发现容器里面文件宿主都是ROOT用户
[root@boy dockerfile]# docker run -it --rm centos:7 /bin/bash -c "echo 1 > /root/text && ls -al /root"
total 28
dr-xr-x---. 1 root root   18 Apr 25 05:44 .
drwxr-xr-x  1 root root   18 Apr 25 05:44 ..
-rw-r--r--. 1 root root   18 Dec 29  2013 .bash_logout
-rw-r--r--. 1 root root  176 Dec 29  2013 .bash_profile
-rw-r--r--. 1 root root  176 Dec 29  2013 .bashrc
-rw-r--r--. 1 root root  100 Dec 29  2013 .cshrc
-rw-r--r--. 1 root root  129 Dec 29  2013 .tcshrc
-rw-------. 1 root root 3416 Nov 13  2020 anaconda-ks.cfg
-rw-r--r--  1 root root    2 Apr 25 05:44 text

# 以ROOT用户来执行进程,可见也是ROOT身份
[root@boy dockerfile]# docker run -it --rm centos:7 /bin/bash -c "ps -aux"
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root          1  0.0  0.0  51728  1544 pts/0    Rs+  06:27   0:00 ps -aux

gosu

  • Docker容器中运行的进程,如果以root身份运行话会有安全隐患,该进程拥有容器内的全部权限,更可怕的是如果有数据卷映射到宿主机,那么通过该容器就能操作宿主机的文件夹了,一旦该容器的进程有漏洞被外部利用后果是很严重的,因此,容器内使用非root账号运行进程才是安全的方式,这也是我们在制作镜像时要注意的地方
  • susudo具有非常奇怪且经常令人讨厌的TTY和信号转发行为的问题。susudo的设置和使用也有些复杂(特别是在sudo的情况下),虽然它们有很大的表达力,但是如果您所需要的只是“以特定用户身份运行特定应用程序”,那么它们将不再那么适合
  • 处理完用户/组后,我们将切换到指定用户,然后执行指定的进程,gosu本身不再驻留或完全不在进程生命周期中。这避免了信号传递和TTY的所有问题
  • 不要在容器中使用sudo命令,因为sudo的执行机制问题,如下所示,我们在启动容器时执行了sudo ps -ef命令,发现我们命名只执行了一条命令,但是竟然会有2个进程,请注意PID,真正执行ps -ef的命令的PID是7,而不是1,这回导致当前进程无法接受Unix的SIGNAL
[root@jiayu ~]# docker run -it --rm ubuntu su -c 'exec ps -aux'
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   4484  1612 pts/0    Ss+  14:31   0:00 su -c exec ps -
root         7  0.0  0.0   5888  1412 pts/0    R+   14:31   0:00 ps -aux

# 下面二个实例,不一定带sudo命令
[root@jiayu ~]# docker run -it --rm ubuntu:trusty sudo ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  3.0  0.0  46020  3144 ?        Ss+  02:22   0:00 sudo ps aux
root         7  0.0  0.0  15576  2172 ?        R+   02:22   0:00 ps aux

#  可见使用gosu后,切换身份后,且只有一个进程
[root@jiayu ~]# docker run -it --rm -v $PWD/gosu-amd64:/usr/local/bin/gosu:ro ubuntu:trusty gosu root ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   7140   768 ?        Rs+  02:22   0:00 ps aux
# 查看dockerfile
# add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added
RUN groupadd -r redis && useradd -r -g redis redis
...............................................
RUN mkdir /data && chown redis:redis /data
VOLUME /data
WORKDIR /data
COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 6379
CMD ["redis-server"]
# 查看entrypoint.sh
#!/bin/sh
set -e

# first arg is `-f` or `--some-option`
# or first arg is `something.conf`
if [ "${1#-}" != "$1" ] || [ "${1%.conf}" != "$1" ]; then
	set -- redis-server "$@"
fi

# allow the container to be started with `--user`
if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then
	find . \! -user redis -exec chown redis '{}' +
	exec gosu redis "$0" "$@"
fi

exec "$@"

注意上面的代码,我们来分析一下:

  1. 假设启动容器的命令是docker run -it redis redis-server /etc/redis.conf
  2. 容器启动后会执行docker-entrypoint.sh脚本,此时的账号是root,此时对于容器来说接收到命令为:docker-entrypoint.sh redis-server /etc/redis.conf
  3. exec gosu redis $0 $@
# 这条命令当于以redis身份执行如下命令
	docker-entrypoint.sh redis-server /etc/redis.conf
	
# exec
	替换当前的shell,且不会生成新的进程保证了gosu redis “$0"@"对应的进程ID为1
	此时运行命令为:docker-entrypoint.sh redis-server /etc/redis.conf
  1. 当切换成redis用户后会执行如下命令
# exec $@
	redis-server /etc/redis.conf

gosu实例

[root@boy dockerfile]# cat dockerfile 
FROM debian:sid-slim
RUN groupadd -r test && useradd -r -g test test
COPY docker-entrypoint.sh /usr/bin/
RUN apt-get update && apt-get install -y --no-install-recommends procps gosu && rm -rf /var/lib/apt/lists/*

ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["ps -aux && sleep 36000"]
[root@boy dockerfile]# cat docker-entrypoint.sh 
#!/bin/bash
if [ "$(id -u)" == "0" ]; then
	exec gosu test "$0" "$@"
fi

exec $@
# 构建镜像
[root@boy dockerfile]# docker build -t gosu:1.0 .

# 启动容器,可以发现目前容器内的进程都是以test身份运行了,且只有一个进程,不存在sudo,su导致生成二个进程
[root@boy dockerfile]# docker run -it --rm gosu:1.0 ps -aux
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
test          1  4.0  0.0   6960  1572 pts/0    Rs+  07:34   0:00 ps -aux

总结

  • gosu启动命令时只有一个进程,所以docker容器启动时使用gosu,那么该进程可以做到PID等于1
  • sudo启动命令时先创建sudo进程,然后该进程作为父进程去创建子进程,1号PID被sudo进程占据

综上所述,在docker的entrypoint中有如下建议:

  • 创建group和普通账号,不要使用root账号启动进程
  • 如果普通账号权限不够用,建议使用gosu来提升权限,而不是sudo
  • entrypoint.sh脚本在执行的时候也是个进程,启动业务进程的时候,在命令前面加上exec,这样新的进程就会取代entrypoint.sh的进程,得到1号PID
  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-04-26 12:16:02  更:2022-04-26 12:17:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 19:50:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码